Rails迁移:add_reference到表但外键比Rails公约的列名不同

时间:2015-01-06 23:57:48

标签: ruby-on-rails rails-migrations

我有以下两种型号:

class Store < ActiveRecord::Base
    belongs_to :person
end

class Person < ActiveRecord::Base
    has_one :store
end

以下是问题:我正在尝试创建迁移以在people表中创建外键。但是,引用Store外键的列不是像rails惯例那样命名为 store_id ,而是命名为 foo_bar_store_id

如果我遵循rails约定,我会像这样进行迁移:

class AddReferencesToPeople < ActiveRecord::Migration
  def change
    add_reference :people, :store, index: true
  end
end

但是这不起作用,因为列名不是 store_id ,而是 foo_bar_store_id 。那么如何指定外键名称只是不同,但仍保持索引:true以保持快速性能?

6 个答案:

答案 0 :(得分:62)

在Rails 4.2中,您还可以使用自定义外键名称设置模型或迁移。在您的示例中,迁移将是:

class AddReferencesToPeople < ActiveRecord::Migration
  def change
    add_column :people, :foo_bar_store_id, :integer, index: true
    add_foreign_key :people, :stores, column: :foo_bar_store_id
  end
end

Here是关于此主题的有趣博客文章。 Here是Rails指南中的半隐藏部分。这篇博文绝对帮助了我。

至于关联,明确说明这样的外键或类名(我认为你的原始关联被切换为&#39; belongs_to&#39;进入具有外键的类):

class Store < ActiveRecord::Base
  has_one :person, foreign_key: :foo_bar_store_id
end

class Person < ActiveRecord::Base
  belongs_to :foo_bar_store, class_name: 'Store'
end

请注意,class_name项必须是字符串。 foreign_key项可以是字符串或符号。这实际上允许您使用语义命名的关联访问漂亮的ActiveRecord快捷方式,如下所示:

person = Person.first
person.foo_bar_store
# returns the instance of store equal to person's foo_bar_store_id

详细了解belongs_tohas_one的文档中的关联选项。

答案 1 :(得分:58)

在rails 5.x中,您可以将外键添加到具有不同名称的表中,如下所示:

class AddFooBarStoreToPeople < ActiveRecord::Migration[5.0]
  def change
    add_reference :people, :foo_bar_store, foreign_key: { to_table: :stores }
  end
end

答案 2 :(得分:5)

编辑:对于那些看到勾号但不继续阅读的人!

虽然这个答案实现了拥有非常规外键列名称的目标,但使用索引,它不会向数据库添加fk约束。请使用add_foreign_key和/或“add_reference”查看其他答案以获取更合适的解决方案。

注意:总是看看其他答案,接受的答案并不总是最好的!

原始答案:

AddReferencesToPeople迁移中,您可以使用以下方式手动添加字段和索引:

add_column :people, :foo_bar_store_id, :integer
add_index :people, :foo_bar_store_id

然后让你的模型像这样知道外键:

class Person < ActiveRecord::Base
  has_one :store, foreign_key: 'foo_bar_store_id'
end

答案 3 :(得分:4)

# Migration
change_table :people do |t|
  t.references :foo_bar_store, references: :store #-> foo_bar_store_id
end

# Model
# app/models/person.rb
class Person < ActiveRecord::Base
  has_one :foo_bar_store, class_name: "Store"
end

答案 4 :(得分:4)

要扩展schpet的答案,它可以在IBuffer Rails 5迁移指令中工作,如下所示:

create_table

答案 5 :(得分:1)

在封面下,add_reference只是委托给add_column和add_index,所以你只需要自己处理:

add_column :people, :foo_bar_store_id, :integer
add_index :people, :foo_bar_store_id