首页 > 解决方案 > 连接表有两个复数词。如何正确命名模型和迁移;为了销毁连接表上的孤儿。活动记录

问题描述

好吧,撇开在聊天板上询问如何“消灭孤儿”只是邪恶的事实不谈,这是我的技术问题:

我正在制作一个简单的博客站点,使用 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

标签: ruby-on-railsrubypostgresqlactiverecordsinatra-activerecord

解决方案


现在,您的迁移和模型一切正常,您只需要更改PostTag模型:

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_tagshas_many <...>, :through => :posts_tags

PS 按照惯例,ruby 中的所有文件名都是小写的蛇形,它应该是 `posts_tag.rb',而不是 'Posts_Tag.rb'


推荐阅读