I want to make a copy of an activerecord record, changing a single field in the process (in addition to the id). What is the simplest way to accomplish this?
我想复制一个activerecord记录,在进程中更改一个字段(除了id)。最简单的方法是什么?
I realize I could create a new record, and then iterate over each of the fields copying the data field-by-field - but I figured there must be an easier way to do this...
我意识到我可以创建一个新的记录,然后遍历每个复制数据字段的字段——但是我认为一定有一种更简单的方法可以做到这一点……
such as:
如:
@newrecord=Record.copy(:id) *perhaps?*
9 个解决方案
#1
550
To get a copy, use the clone (or dup for rails 3.1) method:
要获得副本,请使用克隆(或rails 3.1中的dup)方法:
# rails < 3.1
new_record = old_record.clone
#rails >= 3.1
new_record = old_record.dup
Then you can change whichever fields you want.
然后您可以更改您想要的任何字段。
ActiveRecord overrides the built-in Object#clone to give you a new (not saved to the DB) record with an unassigned ID.
Note that it does not copy associations, so you'll have to do this manually if you need to.
ActiveRecord重写了内置的对象#克隆,以给您一个新的(未保存到DB)记录和一个未分配的ID。
Rails 3.1 clone is a shallow copy, use dup instead...
克隆是一个浅拷贝,使用dup代替…
#2
63
Depending on your needs and programming style, you can also use a combination of the new method of the class and merge. For lack of a better simple example, suppose you have a task scheduled for a certain date and you want to duplicate it to another date. The actual attributes of the task aren't important, so:
根据您的需要和编程风格,您还可以使用类的新方法和merge的组合。如果没有更好的简单示例,假设您有一个为特定日期安排的任务,并且希望将其复制到另一个日期。任务的实际属性并不重要,因此:
old_task = Task.find(task_id) new_task = Task.new(old_task.attributes.merge({:scheduled_on => some_new_date}))
will create a new task with :id => nil
, :scheduled_on => some_new_date
, and all other attributes the same as the original task. Using Task.new, you will have to explicitly call save, so if you want it saved automatically, change Task.new to Task.create.
将使用:id => nil,:scheduled_on => some_new_date创建一个新任务,以及与原始任务相同的所有其他属性。使用任务。新的,您将必须显式地调用save,因此如果您希望它自动保存,请更改任务。新Task.create。
Peace.
和平。
#3
31
You may also like the Amoeba gem for ActiveRecord 3.2.
您可能也喜欢ActiveRecord 3.2的变形虫宝石。
In your case, you probably want to make use of the nullify
, regex
or prefix
options available in the configuration DSL.
在您的示例中,您可能希望使用配置DSL中的nullify、regex或前缀选项。
It supports easy and automatic recursive duplication of has_one
, has_many
and has_and_belongs_to_many
associations, field preprocessing and a highly flexible and powerful configuration DSL that can be applied both to the model and on the fly.
它支持简单的自动递归复制has_one、has_many和has_and_belongs_to_many关联、字段预处理以及高度灵活和强大的配置DSL,可以动态地应用到模型和模型。
be sure to check out the Amoeba Documentation but usage is pretty easy...
一定要查看Amoeba文档,但是使用起来很容易……
just
只是
gem install amoeba
or add
或添加
gem 'amoeba'
to your Gemfile
你Gemfile
then add the amoeba block to your model and run the dup
method as usual
然后将amoeba块添加到模型中,并像往常一样运行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
You can also control which fields get copied in numerous ways, but for example, if you wanted to prevent comments from being duplicated but you wanted to maintain the same tags, you could do something like this:
您还可以通过多种方式控制哪些字段被复制,但是,如果您想防止注释被复制,但是您想维护相同的标记,您可以这样做:
class Post < ActiveRecord::Base
has_many :comments
has_and_belongs_to_many :tags
amoeba do
exclude_field :comments
end
end
You can also preprocess fields to help indicate uniqueness with both prefixes and suffixes as well as regexes. In addition, there are also numerous options so you can write in the most readable style for your purpose:
您还可以预先处理字段,以帮助指示前缀和后缀以及regex的惟一性。此外,还有很多选项,你可以用最易读的风格来写作:
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
Recursive copying of associations is easy, just enable amoeba on child models as well
关联的递归复制很简单,只需在子模型上启用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
The configuration DSL has yet more options, so be sure to check out the documentation.
配置DSL还有更多的选项,所以一定要检查文档。
Enjoy! :)
享受吧!:)
#4
#5
19
I usually just copy the attributes, changing whatever I need changing:
我通常只复制属性,更改我需要更改的内容:
new_user = User.new(old_user.attributes.merge(:login => "newlogin"))
#6
8
If you need a deep copy with associations, I recommend the deep_cloneable gem.
如果您需要一个具有关联的深度副本,我推荐deep_cloneable gem。
#7
1
The easily way is:
最容易的方法是:
#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
#8
0
You can also check the acts_as_inheritable gem.
您还可以检查acts_as_inheritance gem。
"Acts As Inheritable is a Ruby Gem specifically written for Rails/ActiveRecord models. It is meant to be used with the Self-Referential Association, or with a model having a parent that share the inheritable attributes. This will let you inherit any attribute or relation from the parent model."
“充当可继承的角色是专门为Rails/ActiveRecord模型编写的Ruby Gem。”它应该与自引用关联一起使用,或者与具有共享可继承属性的父类的模型一起使用。这将允许您从父模型继承任何属性或关系。
By adding acts_as_inheritable
to your models you will have access to these methods:
通过向模型添加acts_as_inheritance,您可以访问这些方法:
inherit_attributes
inherit_attributes
class Person < ActiveRecord::Base
acts_as_inheritable attributes: %w(favorite_color last_name soccer_team)
# Associations
belongs_to :parent, class_name: 'Person'
has_many :children, class_name: 'Person', foreign_key: :parent_id
end
parent = Person.create(last_name: 'Arango', soccer_team: 'Verdolaga', favorite_color:'Green')
son = Person.create(parent: parent)
son.inherit_attributes
son.last_name # => Arango
son.soccer_team # => Verdolaga
son.favorite_color # => Green
inherit_relations
inherit_relations
class Person < ActiveRecord::Base
acts_as_inheritable associations: %w(pet)
# Associations
has_one :pet
end
parent = Person.create(last_name: 'Arango')
parent_pet = Pet.create(person: parent, name: 'Mango', breed:'Golden Retriver')
parent_pet.inspect #=> #<Pet id: 1, person_id: 1, name: "Mango", breed: "Golden Retriver">
son = Person.create(parent: parent)
son.inherit_relations
son.pet.inspect # => #<Pet id: 2, person_id: 2, name: "Mango", breed: "Golden Retriver">
Hope this can help you.
希望这能帮到你。
#9
0
Since there could be more logic, when duplicating a model, I would suggest to create a new class, where you handle all the needed logic. To ease that, there's a gem that can help: clowne
由于可以有更多的逻辑,所以在复制模型时,我建议创建一个新的类,在这个类中您可以处理所有需要的逻辑。为了缓解这个问题,有一颗宝石可以帮助你:小丑
As per their documentation examples, for a User model:
根据他们的文档示例,为用户模型:
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
You create your cloner class:
你创建cloner类:
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
and then use it:
然后使用它:
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
Example copied from the project, but it will give a clear vision of what you can achieve.
示例从项目中复制,但它将给出一个清晰的远景,您可以实现什么。
For a quick and simple record I would go with:
为了快速而简单的记录,我将:
Model.new(Model.last.attributes.reject {|k,_v| k.to_s == 'id'}
Model.new(Model.last.attributes。反对{ | k,_v | k。to_s = =“id”}
#1
550
To get a copy, use the clone (or dup for rails 3.1) method:
要获得副本,请使用克隆(或rails 3.1中的dup)方法:
# rails < 3.1
new_record = old_record.clone
#rails >= 3.1
new_record = old_record.dup
Then you can change whichever fields you want.
然后您可以更改您想要的任何字段。
ActiveRecord overrides the built-in Object#clone to give you a new (not saved to the DB) record with an unassigned ID.
Note that it does not copy associations, so you'll have to do this manually if you need to.
ActiveRecord重写了内置的对象#克隆,以给您一个新的(未保存到DB)记录和一个未分配的ID。
Rails 3.1 clone is a shallow copy, use dup instead...
克隆是一个浅拷贝,使用dup代替…
#2
63
Depending on your needs and programming style, you can also use a combination of the new method of the class and merge. For lack of a better simple example, suppose you have a task scheduled for a certain date and you want to duplicate it to another date. The actual attributes of the task aren't important, so:
根据您的需要和编程风格,您还可以使用类的新方法和merge的组合。如果没有更好的简单示例,假设您有一个为特定日期安排的任务,并且希望将其复制到另一个日期。任务的实际属性并不重要,因此:
old_task = Task.find(task_id) new_task = Task.new(old_task.attributes.merge({:scheduled_on => some_new_date}))
will create a new task with :id => nil
, :scheduled_on => some_new_date
, and all other attributes the same as the original task. Using Task.new, you will have to explicitly call save, so if you want it saved automatically, change Task.new to Task.create.
将使用:id => nil,:scheduled_on => some_new_date创建一个新任务,以及与原始任务相同的所有其他属性。使用任务。新的,您将必须显式地调用save,因此如果您希望它自动保存,请更改任务。新Task.create。
Peace.
和平。
#3
31
You may also like the Amoeba gem for ActiveRecord 3.2.
您可能也喜欢ActiveRecord 3.2的变形虫宝石。
In your case, you probably want to make use of the nullify
, regex
or prefix
options available in the configuration DSL.
在您的示例中,您可能希望使用配置DSL中的nullify、regex或前缀选项。
It supports easy and automatic recursive duplication of has_one
, has_many
and has_and_belongs_to_many
associations, field preprocessing and a highly flexible and powerful configuration DSL that can be applied both to the model and on the fly.
它支持简单的自动递归复制has_one、has_many和has_and_belongs_to_many关联、字段预处理以及高度灵活和强大的配置DSL,可以动态地应用到模型和模型。
be sure to check out the Amoeba Documentation but usage is pretty easy...
一定要查看Amoeba文档,但是使用起来很容易……
just
只是
gem install amoeba
or add
或添加
gem 'amoeba'
to your Gemfile
你Gemfile
then add the amoeba block to your model and run the dup
method as usual
然后将amoeba块添加到模型中,并像往常一样运行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
You can also control which fields get copied in numerous ways, but for example, if you wanted to prevent comments from being duplicated but you wanted to maintain the same tags, you could do something like this:
您还可以通过多种方式控制哪些字段被复制,但是,如果您想防止注释被复制,但是您想维护相同的标记,您可以这样做:
class Post < ActiveRecord::Base
has_many :comments
has_and_belongs_to_many :tags
amoeba do
exclude_field :comments
end
end
You can also preprocess fields to help indicate uniqueness with both prefixes and suffixes as well as regexes. In addition, there are also numerous options so you can write in the most readable style for your purpose:
您还可以预先处理字段,以帮助指示前缀和后缀以及regex的惟一性。此外,还有很多选项,你可以用最易读的风格来写作:
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
Recursive copying of associations is easy, just enable amoeba on child models as well
关联的递归复制很简单,只需在子模型上启用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
The configuration DSL has yet more options, so be sure to check out the documentation.
配置DSL还有更多的选项,所以一定要检查文档。
Enjoy! :)
享受吧!:)
#4
#5
19
I usually just copy the attributes, changing whatever I need changing:
我通常只复制属性,更改我需要更改的内容:
new_user = User.new(old_user.attributes.merge(:login => "newlogin"))
#6
8
If you need a deep copy with associations, I recommend the deep_cloneable gem.
如果您需要一个具有关联的深度副本,我推荐deep_cloneable gem。
#7
1
The easily way is:
最容易的方法是:
#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
#8
0
You can also check the acts_as_inheritable gem.
您还可以检查acts_as_inheritance gem。
"Acts As Inheritable is a Ruby Gem specifically written for Rails/ActiveRecord models. It is meant to be used with the Self-Referential Association, or with a model having a parent that share the inheritable attributes. This will let you inherit any attribute or relation from the parent model."
“充当可继承的角色是专门为Rails/ActiveRecord模型编写的Ruby Gem。”它应该与自引用关联一起使用,或者与具有共享可继承属性的父类的模型一起使用。这将允许您从父模型继承任何属性或关系。
By adding acts_as_inheritable
to your models you will have access to these methods:
通过向模型添加acts_as_inheritance,您可以访问这些方法:
inherit_attributes
inherit_attributes
class Person < ActiveRecord::Base
acts_as_inheritable attributes: %w(favorite_color last_name soccer_team)
# Associations
belongs_to :parent, class_name: 'Person'
has_many :children, class_name: 'Person', foreign_key: :parent_id
end
parent = Person.create(last_name: 'Arango', soccer_team: 'Verdolaga', favorite_color:'Green')
son = Person.create(parent: parent)
son.inherit_attributes
son.last_name # => Arango
son.soccer_team # => Verdolaga
son.favorite_color # => Green
inherit_relations
inherit_relations
class Person < ActiveRecord::Base
acts_as_inheritable associations: %w(pet)
# Associations
has_one :pet
end
parent = Person.create(last_name: 'Arango')
parent_pet = Pet.create(person: parent, name: 'Mango', breed:'Golden Retriver')
parent_pet.inspect #=> #<Pet id: 1, person_id: 1, name: "Mango", breed: "Golden Retriver">
son = Person.create(parent: parent)
son.inherit_relations
son.pet.inspect # => #<Pet id: 2, person_id: 2, name: "Mango", breed: "Golden Retriver">
Hope this can help you.
希望这能帮到你。
#9
0
Since there could be more logic, when duplicating a model, I would suggest to create a new class, where you handle all the needed logic. To ease that, there's a gem that can help: clowne
由于可以有更多的逻辑,所以在复制模型时,我建议创建一个新的类,在这个类中您可以处理所有需要的逻辑。为了缓解这个问题,有一颗宝石可以帮助你:小丑
As per their documentation examples, for a User model:
根据他们的文档示例,为用户模型:
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
You create your cloner class:
你创建cloner类:
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
and then use it:
然后使用它:
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
Example copied from the project, but it will give a clear vision of what you can achieve.
示例从项目中复制,但它将给出一个清晰的远景,您可以实现什么。
For a quick and simple record I would go with:
为了快速而简单的记录,我将:
Model.new(Model.last.attributes.reject {|k,_v| k.to_s == 'id'}
Model.new(Model.last.attributes。反对{ | k,_v | k。to_s = =“id”}