ActiveRecord::Migration 的 create_join_table 的行为是啥?

Posted

技术标签:

【中文标题】ActiveRecord::Migration 的 create_join_table 的行为是啥?【英文标题】:What is the behaviour of create_join_table of ActiveRecord::Migration?ActiveRecord::Migration 的 create_join_table 的行为是什么? 【发布时间】:2015-11-19 00:52:28 【问题描述】:

我发现了一种在我的 Rails 应用程序中为我的 HABTM 关系生成连接表的好方法。

rails g migration CreateJoinTable table1 table2

这会生成一个使用create_join_table 方法的ActiveRecord::Migration

我想知道这个奇妙的神秘方法有什么作用。我猜它创建了一个表(可能没有id 字段),其中包含 table1 外键列和 table2 外键列,但是该表还有其他功能吗?我对连接表的习惯一直是在这两个列中添加唯一索引,这样 table1 中的记录和 table2 中的记录之间的关系就不能输入两次。

我的问题归结为:如果我使用create_join_table,我是否需要继续添加该唯一索引,或者这种方法是否对我这样做(我认为应该这样做)?

documentation I usually look at 没有涉及到这种细节。

【问题讨论】:

【参考方案1】:

还要注意如何定义此连接表的依赖销毁。

如果您稍后离开 HABTM 并使用 through: 定义关系并弄错了,您可能会遇到我报告的 here 的“to_sym”错误。

确保你已经像这样定义了销毁:

class Proposal < ActiveRecord::Base
  has_many :assignments
  has_many :products, through: :assignments, dependent: :destroy # <- HERE
end

class Product < ActiveRecord::Base
  has_many :assignments
  has_many :proposals, through: :assignments, dependent: :destroy # <- HERE
end

class Assignment < ActiveRecord::Base
  belongs_to :product
  belongs_to :proposal
end

不是这个:

class Proposal < ActiveRecord::Base
  has_many :assignments, dependent: :destroy
  has_many :products, through: :assignments
end

class Product < ActiveRecord::Base
  has_many :assignments, dependent: :destroy
  has_many :proposals, through: :assignments
end

class Assignment < ActiveRecord::Base
  belongs_to :product
  belongs_to :proposal
end

【讨论】:

当你把:destroy声明放在:through关系上时,会不会破坏对应的Products或Proposals而不仅仅是Assignment @Toby1Kenobi 嗯,这是个好问题。不知道,需要测试一下。【参考方案2】:

在没有任何块的情况下调用,create_join_table 只是创建一个表,其中两个外键引用两个连接的表。

但是,当您调用该方法执行任何其他操作(例如,添加索引)时,您实际上可以传递一个块。来自 Rails 文档:

create_join_table :products, :categories do |t|
  t.index :product_id
  t.index :category_id
end

看看create_join_table documentation。

您可以查看底部的create_join_table代码(点击Source: show)。

【讨论】:

【参考方案3】:

SchemaStatements#create_join_table() 只创建没有任何花哨索引等的连接表,...因此,如果您希望在两个字段上使用唯一性约束,您必须执行以下操作:

class CreateJoinTable < ActiveRecord::Migration
  def change
    create_join_table :posts, :users do |t|
      t.integer :post_id, index: true
      t.integer :user_id, index: true
      t.index [:post_id, :user_id], name: 'post_user_un', unique: true
    end
  end
end

请注意create_join_table 默认不会创建id 字段。

【讨论】:

【参考方案4】:

事实证明,它只做我在问题中描述的基础知识。我只是通过运行迁移并查看db/schema.rb 中的结果来发现这一点

对于那些感兴趣的人,要获得唯一索引,请执行以下操作:

class CreateJoinTable < ActiveRecord::Migration
  def change
    create_join_table :posts, :users
    add_index :posts_users, [:post_id, :user_id], unique: true, name: 'index_posts_users'
  end
end

【讨论】:

以上是关于ActiveRecord::Migration 的 create_join_table 的行为是啥?的主要内容,如果未能解决你的问题,请参考以下文章

t

Rails Money迁移失败

Rails迁移:从表中删除列

有人可以找到“未知属性”我的语法/逻辑错误是一个多对多的种子创建方法时,在Rails的连接表?

Rails:使用重载!在控制器中

脱离rails 使用Active Record