我想做一个ActiveRecord对象的副本,改变进程中的一个字段(除了id)。要做到这一点,最简单的方法是什么?
我意识到我可以创建一个新记录,然后遍历每个字段,逐字段复制数据—但我认为一定有更简单的方法来做到这一点。
也许是这样的:
new_record = Record.copy(:id)
我想做一个ActiveRecord对象的副本,改变进程中的一个字段(除了id)。要做到这一点,最简单的方法是什么?
我意识到我可以创建一个新记录,然后遍历每个字段,逐字段复制数据—但我认为一定有更简单的方法来做到这一点。
也许是这样的:
new_record = Record.copy(:id)
当前回答
因为可能会有更多的逻辑,当复制一个模型时,我建议创建一个新的类,在那里你可以处理所有需要的逻辑。 为了缓解这种情况,有一种宝石可以帮助你:小丑
根据他们的文档示例,对于User模型:
class User < ActiveRecord::Base
# create_table :users do |t|
# t.string :login
# t.string :email
# t.timestamps null: false
# end
has_one :profile
has_many :posts
end
你创建你的克隆类:
class UserCloner < Clowne::Cloner
adapter :active_record
include_association :profile, clone_with: SpecialProfileCloner
include_association :posts
nullify :login
# params here is an arbitrary Hash passed into cloner
finalize do |_source, record, params|
record.email = params[:email]
end
end
class SpecialProfileCloner < Clowne::Cloner
adapter :active_record
nullify :name
end
然后使用它:
user = User.last
#=> <#User(login: 'clown', email: 'clown@circus.example.com')>
cloned = UserCloner.call(user, email: 'fake@example.com')
cloned.persisted?
# => false
cloned.save!
cloned.login
# => nil
cloned.email
# => "fake@example.com"
# associations:
cloned.posts.count == user.posts.count
# => true
cloned.profile.name
# => nil
从项目中复制的例子,但它会给你一个清晰的愿景,你可以实现什么。
简单来说,我想说的是:
Model.new (Model.last.attributes。拒绝{|k,_v| k.to_s == 'id'}
其他回答
你可能也喜欢ActiveRecord 3.2的Amoeba宝石。
在您的情况下,您可能希望使用配置DSL中可用的nullify、regex或前缀选项。
它支持has_one, has_many和has_and_belongs_to_many关联的简单和自动递归复制,字段预处理和高度灵活和强大的配置DSL,可以应用于模型和动态。
一定要查看阿米巴文档,但是使用起来很简单…
just
gem install amoeba
或添加
gem 'amoeba'
到您的Gemfile
然后将阿米巴块添加到您的模型中,并像往常一样运行dup方法
class Post < ActiveRecord::Base
has_many :comments
has_and_belongs_to_many :tags
amoeba do
enable
end
end
class Comment < ActiveRecord::Base
belongs_to :post
end
class Tag < ActiveRecord::Base
has_and_belongs_to_many :posts
end
class PostsController < ActionController
def some_method
my_post = Post.find(params[:id])
new_post = my_post.dup
new_post.save
end
end
你也可以通过多种方式控制哪些字段被复制,但例如,如果你想防止注释被复制,但你想保持相同的标签,你可以这样做:
class Post < ActiveRecord::Base
has_many :comments
has_and_belongs_to_many :tags
amoeba do
exclude_field :comments
end
end
您还可以对字段进行预处理,以帮助指示前缀和后缀以及正则表达式的唯一性。此外,还有许多选项,所以你可以写在最易读的风格为您的目的:
class Post < ActiveRecord::Base
has_many :comments
has_and_belongs_to_many :tags
amoeba do
include_field :tags
prepend :title => "Copy of "
append :contents => " (copied version)"
regex :contents => {:replace => /dog/, :with => "cat"}
end
end
关联的递归复制很容易,只要在子模型上启用amoeba即可
class Post < ActiveRecord::Base
has_many :comments
amoeba do
enable
end
end
class Comment < ActiveRecord::Base
belongs_to :post
has_many :ratings
amoeba do
enable
end
end
class Rating < ActiveRecord::Base
belongs_to :comment
end
配置DSL还有更多选项,所以一定要查看文档。
享受吧!:)
试试rails的dup方法:
new_record = old_record.dup.save
因为可能会有更多的逻辑,当复制一个模型时,我建议创建一个新的类,在那里你可以处理所有需要的逻辑。 为了缓解这种情况,有一种宝石可以帮助你:小丑
根据他们的文档示例,对于User模型:
class User < ActiveRecord::Base
# create_table :users do |t|
# t.string :login
# t.string :email
# t.timestamps null: false
# end
has_one :profile
has_many :posts
end
你创建你的克隆类:
class UserCloner < Clowne::Cloner
adapter :active_record
include_association :profile, clone_with: SpecialProfileCloner
include_association :posts
nullify :login
# params here is an arbitrary Hash passed into cloner
finalize do |_source, record, params|
record.email = params[:email]
end
end
class SpecialProfileCloner < Clowne::Cloner
adapter :active_record
nullify :name
end
然后使用它:
user = User.last
#=> <#User(login: 'clown', email: 'clown@circus.example.com')>
cloned = UserCloner.call(user, email: 'fake@example.com')
cloned.persisted?
# => false
cloned.save!
cloned.login
# => nil
cloned.email
# => "fake@example.com"
# associations:
cloned.posts.count == user.posts.count
# => true
cloned.profile.name
# => nil
从项目中复制的例子,但它会给你一个清晰的愿景,你可以实现什么。
简单来说,我想说的是:
Model.new (Model.last.attributes。拒绝{|k,_v| k.to_s == 'id'}
简单的方法是:
#your rails >= 3.1 (i was done it with Rails 5.0.0.1)
o = Model.find(id)
# (Range).each do |item|
(1..109).each do |item|
new_record = o.dup
new_record.save
end
Or
# if your rails < 3.1
o = Model.find(id)
(1..109).each do |item|
new_record = o.clone
new_record.save
end
如果你需要一个有关联的深度拷贝,我推荐deep_cloneable gem。