ruby-on-rails - 连接表有两个复数词。如何正确命名模型和迁移;为了销毁连接表上的孤儿。活动记录
问题描述
好吧,撇开在聊天板上询问如何“消灭孤儿”只是邪恶的事实不谈,这是我的技术问题:
我正在制作一个简单的博客站点,使用 Activerecord 和 Sinatra(我对这两者都是新手)。我在 Post 模型和 Tag 模型之间存在“多对多”关系,并且遇到了我无法解决的错误。最后,我安排了模型和迁移,以免出错;但是,当我销毁标签的实例时,“posts_tags”表上的关联保留在原处(作为孤儿存在),我想知道如何销毁它们(提示邪恶的音乐)。
任何人都可以帮助我吗?
这是我对所有三个表的迁移:
class CreatePostsTable < ActiveRecord::Migration[5.2]
def change
create_table :posts do |t|
t.string :title, default: 'title here'
t.string :content, default: 'content here'
t.belongs_to :blog, index: true
t.timestamps
end
end
end
class CreateTagTable < ActiveRecord::Migration[5.2]
def change
create_table :tags do |t|
t.string :name, unique: true
end
end
end
class CreatePostsTagsTable < ActiveRecord::Migration[5.2]
def change
create_table :posts_tags, :id => false do |t|
t.belongs_to :tag, index: true
t.belongs_to :post, index: true
# t.integer :post_id
# t.integer :tag_id
end
end
end
这是我的三个模型:
文件名:Post_Tag(我已经命名并在几天内重新命名了这个类和文件名)。
class PostsTag < ActiveRecord::Base
# self.table_name = "posts_tags" #had to add this line for seed file not to give errors
belongs_to :post
belongs_to :tag
end
class Post < ActiveRecord::Base
belongs_to :blog
has_many :posts_tags
has_many :tags, :through => :posts_tags
has_many :comments, dependent: :destroy
end
class Tag < ActiveRecord::Base
has_many :posts_tags
has_many :posts, :through => :posts_tags
# has_and_belongs_to_many :posts, :through => :posts_tags
end
当我搜索帖子的标签或标签的帖子时,此配置不会给我错误,但是当我执行 @tag = Tag.find_by_id(1) @tag.destroy 时,“posts_tags”表仍然具有所有 tag_id == 1 行仍然存在。当我试图破坏它们时,我会出错(我认为这是因为这也会破坏关联)。
有谁知道如何解决这一问题?可以一起简单地删除 PostsTag 模型吗?
Activerecord 文档使用了一个示例,其中连接表是一个单词,因此我无法在那里找到答案。
我看到有些人根本没有为连接表制作模型。当我删除我的连接表模型时,我收到了这个错误:
@post = Post.find_by_id(1)
@post.tags.each do |tag|
p tag.name
end
NameError at / uninitialized constant Tag::PostsTag
谢谢你的帮助!
#问题的第二阶段:
在提示我可以尝试将此代码添加到我的模型中之后:
class Post < ActiveRecord::Base
has_many :posts_tags, dependent: :destroy
class Tag < ActiveRecord::Base
我在我的服务器/应用程序文件中运行它:
delete "/tag/destroy" do
body = JSON.parse request.body.read # body: {id: number} or {name: string}
@tag_to_destroy = Tag.where(body)[0]
@tag_to_destroy.destroy
redirect "/tag"
end
我通过邮递员发送此请求:
http://localhost:4567/tag/destroy
body of request:
{
"id": 12
}
我收到了这个错误:(即使posts_tags数据库中有tag_id = 12,post_id = variousNumbers的行):
== Sinatra (v2.0.1) 已在 4567 上进行开发,从 Puma Puma 开始以单模式备份... * 版本 3.11.4 (ruby 2.5.1-p57),代号:Love Song * 最小线程: 0,最大线程数:16 * 环境:开发* 监听 tcp://localhost:4567 使用 Ctrl-C 停止 D,[2018-05-07T10:54:19.604906 #99099] DEBUG -- : Tag Load (0.5ms ) SELECT "tags".* FROM "tags" WHERE "t ags"."id" = $1 [["id", 12]] D, [2018-05-07T10:54:19.617955 #99099] DEBUG -- : (0.3ms) BEGIN D, [2018-05-07T10:54:19.633736 #99099] DEBUG -- : PostsTag Load (1.5ms) SELECT "posts_tags".* FROM "pos ts_tags" WHERE "posts_tags"."tag_id" = $1 [["tag_id", 12]] D, [2018-05-07T10:54:19.642305 #99099] DEBUG -- : PostsTag Destroy (1.6ms) DELETE FROM "post_tags" WHERE "posts_tags"."" IS NULL D,[2018-05-07T10:54:19.642685 #99099] DEBUG -- : (0.2ms) ROLLBACK 2018-05-07 10:54:19 - ActiveRecord::StatementInvalid - PG::SyntaxError:错误:在“”“”或附近的零长度分隔标识符第 1 行:从“posts_tags”中删除“posts_tags”。””为空 ^:从“posts_tags”中删除“posts_tags”。” " 为空:/Users/maiya/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:603:in `async_exec'StatementInvalid - PG::SyntaxError:错误:在“”“”或附近的零长度分隔标识符第 1 行:从“posts_tags”中删除,其中“posts_tags”。“”为空 ^:从“posts_tags”中删除“posts_tags”。 “”为空:/Users/maiya/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:603:in `async_exec'StatementInvalid - PG::SyntaxError:错误:在“”“”或附近的零长度分隔标识符第 1 行:从“posts_tags”中删除,其中“posts_tags”。“”为空 ^:从“posts_tags”中删除“posts_tags”。 “”为空:/Users/maiya/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:603:in `async_exec'rvm/gems/ruby-2.5.1/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:603:in `async_exec'rvm/gems/ruby-2.5.1/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:603:in `async_exec'
问题更新:
连接表迁移以前是:
create_table :posts_tags :id => false do |t|
t.belongs_to :tag, index: true
# comment: the above line creates: t.integer :post_id
t.belongs_to :post, index: true
# comment: the above line creates: t.integer :tag_id
end
解决方案
现在,您的迁移和模型一切正常,您只需要更改Post
和Tag
模型:
has_many :posts_tags
至
has_many :posts_tags, dependent: :destroy
在这种情况下,在您销毁任何标签或发布后,所有关联的 posts_tags 也会被销毁,这将确保您的应用程序的引用完整性并防止错误。
foreign_key: true
此外,回滚迁移、向行添加选项并再次迁移它是个好主意t.belongs_to
。此选项将提供数据库级别的引用完整性。
更新:
has_and_belongs_to_many
(HABTM)不适用于through
选项,您将其与has_many
关联混为一谈。请在指南中阅读更多信息
要使这一切正常工作,您需要:
:id => false
从 CreatePostsTagsTable 迁移中删除选项- 重新迁移或删除并重新创建数据库
- 在 Tag 和 Post 模型中更改
has_and_belongs_to_many <...>, :through => :posts_tags
为has_many <...>, :through => :posts_tags
PS 按照惯例,ruby 中的所有文件名都是小写的蛇形,它应该是 `posts_tag.rb',而不是 'Posts_Tag.rb'
推荐阅读
- java - Liquibase 更改日志不存在 - ChangeLogParseException
- android - readRemoteRssi 后 BLE 上的重复消息?
- c# - 不能在其他方法中使用字符串
- javascript - 如何在图片库中添加 PHP 分页
- python - 调用 super().__init__(**kwargs) 和多重继承?
- mysql - 如何创建mysql函数
- c - C中的猜谜游戏,无法获得尝试工作的次数,变量是“计数器”
- node.js - 使用node js创建webrtc视频、语音通话和文件传输一步一步QA
- java - 触发多个线程获取数据时查询无法得到结果
- vba - 通过vba提取html文本