我想复制一个ActiveRecord对象,在此过程中更改单个字段(除了id)。 实现这一点的最简单方法是什么?
我知道我可以创建一个新记录,然后迭代每个字段逐个复制数据,但我想知道是否有更简单的方法。
也许像这样:
new_record = Record.copy(:id)
我想复制一个ActiveRecord对象,在此过程中更改单个字段(除了id)。 实现这一点的最简单方法是什么?
我知道我可以创建一个新记录,然后迭代每个字段逐个复制数据,但我想知道是否有更简单的方法。
也许像这样:
new_record = Record.copy(:id)
要获取一个副本,请使用 dup 方法(对于 < rails 3.1+ 版本,请使用 clone 方法):
#rails >= 3.1
new_record = old_record.dup
# rails < 3.1
new_record = old_record.clone
然后,您可以更改任何您想要的字段。
ActiveRecord覆盖了内置的Object#clone方法,以给您一个新的(未保存到数据库)记录并分配一个未赋值的ID。
请注意,它不会复制关联,所以如果需要,您必须手动完成这个过程。
根据您的需求和编程风格,您还可以使用类的新方法和合并的组合。举个简单的例子,假设您有一个计划在某个日期执行的任务,并且您想将其复制到另一个日期。任务的实际属性并不重要,所以:
old_task = Task.find(task_id) new_task = Task.new(old_task.attributes.merge({:scheduled_on => some_new_date}))
将创建一个新任务,其中:id => nil
,:scheduled_on => some_new_date
,而其他所有属性与原始任务相同。使用Task.new,您将必须显式调用save,因此如果想要自动保存,可以将Task.new更改为Task.create。
祝好!
WARNING: Can't mass-assign protected attributes: id, due_date, created_at, updated_at
的返回信息。 - bcackerman.except
来避免这个问题: new_task = Task.new(old_task.attributes.except(:attribute_you_dont_want, :another_aydw).merge({:scheduled_on => some_new_date}))
。 - Niniginullify
、regex
或 prefix
选项。has_one
、has_many
和 has_and_belongs_to_many
关联、字段预处理以及高度灵活和强大的配置 DSL,可同时应用于模型和即时操作。gem install amoeba
gem 'amoeba'
添加到你的Gemfile中
然后在你的模型中添加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
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
.amoeba_dup
,而不仅仅是 .dup
。我试图在这里执行这段代码,但它没有起作用。 - Victor如果您不想复制id,请使用ActiveRecord :: Base#dup
.clone
。 - Dan Weaver通常我只是复制属性,改变我需要更改的内容:
new_user = User.new(old_user.attributes.merge(:login => "newlogin"))
User.create(old_user.attributes.merge({ login: "newlogin", id: nil }))
。这将保存一个带有正确唯一标识符的新用户。 - RajeshMnew_user = old_user.dup
以下是一个覆盖 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
#dup
方法的新版 ActiveRecord。#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
# if your rails < 3.1
o = Model.find(id)
(1..109).each do |item|
new_record = o.clone
new_record.save
end
您还可以检查acts_as_inheritable gem。
"Acts As Inheritable是一个专门为Rails/ActiveRecord模型编写的Ruby Gem。它旨在与自引用关联一起使用,或者与具有共享可继承属性的父模型一起使用。这将使您从父模型继承任何属性或关系。"
通过向您的模型添加acts_as_inheritable
,您将可以访问以下方法:
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
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">
q = p.clone
,然后比较p == q
时,返回的是true。但是,如果我使用q = p.dup
,则在比较它们时返回false。 - Translunardup
或clone
时添加tap
方法,例如:clone = record.dup.tap { |new_clone| new_clone.name = "dup_#{new_clone.name}" }
。这将允许您修改复制的对象的特定属性,而不会改变其它属性或行为。 - Pablo Cantero