我的模型(Bar)已经有一个参考列,我们称之为foo_id
,现在我需要将foo_id
更改为fooable_id
并使其变为多态。
我认为我有两个选择:
fooable
并从foo_id
迁移ID(迁移这些ID的最佳方法是什么?我可以Bar.each { |b| b.fooable_id = b.foo_id }?
< / LI>
foo_id
重命名为fooable_id
,并将polymorphic
添加到fooable_id
。如何在现有列中添加多态?答案 0 :(得分:13)
1。将 foo_id 的名称更改为 fooable_id ,方法是在以下迁移中重命名:
rename_column :bars, :foo_id, :fooable_id
2。并通过在迁移中添加所需的 foo_type 列来为其添加多态性:
add_column :bars, :fooable_type, :string
3。,在您的模型中:
class Bar < ActiveRecord::Base
belongs_to :fooable,
polymorphic: true
end
4. 最后播种已经关联的类型,如:
Bar.update_all(fooable_type: 'Foo')
答案 1 :(得分:2)
我要做的一个小改动就是迁移:
#db/migrate/latest.rb
class Latest
def change
rename_column :bars, :foo_id, :fooable_id
add_column :bars, :fooable_type, :string, after: :id, default: 'Foo'
end
end
这将消除进行数据迁移的需要。
更新:这将适用于rails 3及更高版本。根据问题,原始基类隐含为Foo。
答案 2 :(得分:1)
Rails更新=> 4.2
Current Rails生成带有index和foreign_key的引用,这是一件好事。
这意味着@Christian Rolle的答案不再有效,因为重命名foo_id
后,它在bars.fooable_id
上引用了foo.id
的外键对其他fooable
无效。< / p>
幸运的是,迁移也在发展,因此确实存在无法撤消的参考迁移。
您需要创建一个新引用并删除旧引用,而不是重命名引用ID。
新功能是需要将ID从旧引用迁移到新引用。
这可以通过
Bar.find_each { |bar| bar.update fooable_id: bar.foo_id }
但是当已经有很多关系时,这可能会非常慢。 Bar.update_all
是在数据库级别完成的,这要快得多。
当然,您应该能够回滚迁移,因此在使用foreign_keys时,完整的迁移为:
def change
add_reference :bars, :fooable, polymorphic: true
reversible do |dir|
dir.up { Bar.update_all("fooable_id = foo_id, fooable_type='Foo'") }
dir.down { Bar.update_all('foo_id = fooable_id')
end
remove_reference :bars, :foo, index: true, foreign_key: true
end
请记住,在回滚期间,更改是从下到上处理的,因此foo_id是在update_all
之前创建的,一切都很好。
答案 3 :(得分:0)
具体参考你的问题,这就是我要做的事情:
Bar
模型中的所有数据都将存储在Bar
模型的引用中。这意味着,如果您更改模型中的foo_id
属性,则只需填充需要添加的bar_type
属性(因为它们都可以引用相同的模型)
执行此操作的方法如下:
- 为
foo_id
&gt;创建迁移fooable_id
- 插入
fooable_type
列- 在rails控制台中,循环浏览
醇>Bar
的所有现有记录,填写fooable_type
列
首先要做的事情:
$ rails g migration ChangeFooID
#db/migrate/latest.rb
class Latest
def change
rename_column :bars, :foo_id, :fooable_id
add_column :bars, :fooable_type, :string, after: :id
end
end
这将为您创建各种列。然后你只需要能够循环记录和更改type
列:
rails c
Bar.find_each do |bar|
bar.update(barable_type: "Foo")
end
这将允许您更改列的类型,使您能够将所有当前记录与相应的记录相关联。
<强>多态性强>
您将能够use the Rails docs as a reference关于如何关联模型:
#app/models/foo.rb
class Foo < ActiveRecord::Base
has_many :bars, as: :barable
end
#app/models/bar.rb
class Bar < ActiveRecord::Base
belongs_to :foo, polymorphic: true
end