dal*_*lef 8 migration activerecord data-migration ruby-on-rails
我有一个模特A,
Class A < ActiveRecord::Base
has_many: names, class_name: 'B'
Run Code Online (Sandbox Code Playgroud)
和模型B.
class B < ActiveRecord::Base
belongs to :A
Run Code Online (Sandbox Code Playgroud)
并且数据库中已经存在大量数据.
如何编写迁移以将它们从一对多迁移到多对多关系?我更喜欢使用
has_many: through
Run Code Online (Sandbox Code Playgroud)
如果可能的话.
编写db迁移并不难,但是如何迁移数据呢?
agr*_*nov 10
这种情况经常出现在Rails项目中,我很惊讶那里仍然没有太多的方法,因为它是一个简单的数据演变,但在处理已部署的系统时需要一些细微之处.
我不确定你是否对多对多的多态行为感兴趣,但我把它扔进去,因为我发现它对许多多对多场景很有用(双关语!:-).
在我开始之前我有这个:
class Tag < ActiveRecord::Base
has_many :posts, inverse_of: :tag
class Post < ActiveRecord::Base
belongs_to :tag, inverse_of: :posts
Run Code Online (Sandbox Code Playgroud)
我知道,我知道,为什么只有一个帖子标签?事实证明,我希望我的帖子毕竟有多个标签.然后我想,等一下,我希望其他东西也有标签,比如某种东西.
您可以对每个Posts-Tags和Things-Tags使用:has_and_belongs_to_many但是这会产生2个连接表,我们可能希望在添加权限时标记更多实体?has_many :through对于我们关联的一方来说,这是一个很好的选择,并避免使用多个连接表.
我们将在涉及2个部署的2个步骤中执行此操作:
第1步 - 不改变现有的关联.一个新的Taggable模型/迁移,它将在Posts and Things方面具有多态性. 部署.
第2步 - 更新关联.新的迁移:tag_id从Posts中删除旧的foreign_key. 部署.
这两个步骤是必要的,以便能够使用以前的关联定义在步骤1中执行迁移,否则您的新关联将无法正常工作.
我认为两个步骤是最简单的方法,建议如果您的流量足够低,以至于在两个步骤之间的帖子/事物上创建额外标签的风险足够低.如果您的流量非常高,您可以将这两个步骤合并为一个,但是您需要使用不同的关联名称,然后在工作推出后返回删除旧的未使用的关联名称.我将离开一步的方法作为读者的练习:-)
为新的多态联接表创建模型迁移.
rails g model Taggable tag_id:integer tagged_id:integer tagged_type:string --timestamps=false
Run Code Online (Sandbox Code Playgroud)
编辑生成的迁移以恢复使用#up和#down(而不是#change)并添加数据迁移:
class CreateTaggables < ActiveRecord::Migration
def up
create_table :taggables do |t|
t.integer :tag_id
t.integer :tagged_id
t.string :tagged_type
end
# we pull Posts here as they have the foreign_key to tags...
Posts.all.each do |p|
Taggable.create(tag_id: p.tag_id, tagged_id: p.id, tagged_type: "Post")
end
end
def down
drop_table :taggables
end
end
Run Code Online (Sandbox Code Playgroud)
编辑新模型:
class Taggable < ActiveRecord::Base
belongs_to :tag
belongs_to :tagged, polymorphic: true
end
Run Code Online (Sandbox Code Playgroud)
此时,请部署新模型和迁移. 大.
现在我们要更新我们的类定义:
class Tag < ActiveRecord::Base
has_many :taggables
has_many :posts, through: :taggables, source: :tagged, source_type: "Post"
has_many :things, through: :taggables, source: :tagged, source_type: "Thing"
class Post < ActiveRecord::Base
has_and_belongs_to_many :tags, join_table: 'taggables', foreign_key: :tagged_id
class Thing < ActiveRecord::Base
has_and_belongs_to_many :tags, join_table: 'taggables', foreign_key: :tagged_id
Run Code Online (Sandbox Code Playgroud)
你应该能够添加dependent: :destroy上has_many :posts,并has_many :things作为:tag一个belongs_to上加标签.
不要忘记丢弃旧的foreign_key:
class RemoveTagIdFromPosts < ActiveRecord::Migration
def up
remove_column :posts, :tag_id
end
def down
add_column :posts, :tag_id, :integer
end
end
Run Code Online (Sandbox Code Playgroud)
更新您的规格!
部署!
| 归档时间: |
|
| 查看次数: |
2591 次 |
| 最近记录: |