Ruby-on-rails 复制活动记录记录的最简单方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/60033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the easiest way to duplicate an activerecord record?
提问by Brent
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?*
回答by Michael Sepcot
To get a copy, use the clone (or dup for rails 3.1+) method:
要获取副本,请使用 clone(或 dup for rails 3.1+)方法:
# 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#cloneto 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 覆盖内置的 Object#clone为您提供一个带有未分配 ID 的新记录(未保存到数据库)。
请注意,它不会复制关联,因此如果需要,您必须手动执行此操作。
回答by Phillip Koebbe
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 simpleexample, 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:
根据您的需要和编程风格,您还可以使用类的新方法和合并的组合。由于缺少一个更好的简单示例,假设您有一个任务安排在某个日期,并且您想将它复制到另一个日期。任务的实际属性并不重要,因此:
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和与原始任务相同的所有其他属性的新任务。使用Task.new,您必须显式调用save,因此如果您希望它自动保存,请将Task.new 更改为Task.create。
Peace.
和平。
回答by Vaughn Draughon
You may also like the Amoeba gemfor ActiveRecord 3.2.
您可能还喜欢ActiveRecord 3.2的Amoeba gem。
In your case, you probably want to make use of the nullify, regexor prefixoptions available in the configuration DSL.
在您的情况下,您可能希望使用配置 DSL 中可用的nullify,regex或prefix选项。
It supports easy and automatic recursive duplication of has_one, has_manyand has_and_belongs_to_manyassociations, 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 Documentationbut 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 dupmethod as usual
然后将变形虫块添加到您的模型中并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:
您还可以预处理字段以帮助指示前缀和后缀以及正则表达式的唯一性。此外,还有许多选项,因此您可以根据自己的目的以最易读的风格编写:
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
关联的递归复制很容易,只需在子模型上启用变形虫
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! :)
享受!:)
回答by bradgonesurfing
Use ActiveRecord::Base#dupif you don't want to copy the id
如果您不想复制 id,请使用ActiveRecord::Base#dup
回答by Fran?ois Beausoleil
I usually just copy the attributes, changing whatever I need changing:
我通常只是复制属性,更改我需要更改的任何内容:
new_user = User.new(old_user.attributes.merge(:login => "newlogin"))
回答by raidfive
If you need a deep copy with associations, I recommend the deep_cloneablegem.
如果您需要具有关联的深层副本,我推荐deep_cloneablegem。
回答by Foram Thakral
In Rails 5 you can simply create duplicate object or record like this.
在 Rails 5 中,您可以像这样简单地创建重复的对象或记录。
new_user = old_user.dup
回答by ThienSuBS
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
回答by Zoran Majstorovic
Here is a sample of overriding ActiveRecord #dupmethod to customize instance duplication and include relation duplication as well:
这是一个覆盖 ActiveRecord#dup方法以自定义实例复制并包括关系复制的示例:
class Offer < ApplicationRecord
has_many :offer_items
def dup
super.tap do |new_offer|
# change title of the new instance
new_offer.title = "Copy of #{@offer.title}"
# duplicate offer_items as well
self.offer_items.each { |offer_item| new_offer.offer_items << offer_item.dup }
end
end
end
Note: this method doesn't require any external gem but it requires newer ActiveRecord version with #dupmethod implemented
注意:此方法不需要任何外部 gem,但它需要更新的 ActiveRecord 版本并#dup实现方法
回答by Paulo Fidalgo
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:
根据他们的文档示例,对于 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
You create your cloner class:
您创建克隆器类:
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: '[email protected]')>
cloned = UserCloner.call(user, email: '[email protected]')
cloned.persisted?
# => false
cloned.save!
cloned.login
# => nil
cloned.email
# => "[email protected]"
# 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.reject {|k,_v| k.to_s == 'id'}

