444

idに加えて、プロセス内の単一のフィールドを変更して、ActiveRecord オブジェクトのコピーを作成したいと考えています。これを達成する最も簡単な方法は何ですか?

新しいレコードを作成し、フィールドごとにデータをコピーして各フィールドを反復処理できることに気付きましたが、これを行うにはもっと簡単な方法があるはずだと思いました。

おそらく次のようなものです:

 new_record = Record.copy(:id)
4

12 に答える 12

667

コピーを取得するには、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 を持つ新しい (DB に保存されない) レコードを提供します。
関連付けはコピーされないため、必要に応じて手動で行う必要があることに注意してください。

Rails 3.1 クローンは浅いコピーです。代わりに dup を使用してください...

于 2008-09-12T21:56:44.727 に答える
75

ニーズとプログラミングスタイルに応じて、クラスの新しいメソッドとマージを組み合わせて使用​​することもできます。より簡単な例がないため、特定の日付にタスクがスケジュールされていて、それを別の日付に複製したいとします。タスクの実際の属性は重要ではないため、次のようになります。

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に変更します。

平和。

于 2008-09-15T13:48:34.157 に答える
35

You may also like the Amoeba gem for ActiveRecord 3.2.

In your case, you probably want to make use of the nullify, regex or prefix options available in the configuration DSL.

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.

be sure to check out the Amoeba Documentation but usage is pretty easy...

just

gem install amoeba

or add

gem 'amoeba'

to your Gemfile

then add the amoeba block to your model and run the dup method as usual

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.

Enjoy! :)

于 2012-02-28T16:12:44.453 に答える
32

ID をコピーしたくない場合はActiveRecord::Base#dupを使用してください

于 2011-08-05T13:59:20.313 に答える
25

私は通常、変更が必要なものを変更して、属性をコピーするだけです。

new_user = User.new(old_user.attributes.merge(:login => "newlogin"))
于 2008-09-15T13:36:15.340 に答える
10

関連付けのあるディープ コピーが必要な場合は、deep_cloneable gem をお勧めします。

于 2011-09-01T02:22:49.767 に答える
2

簡単な方法は次のとおりです。

#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     
于 2016-10-30T13:58:00.290 に答える
0

act_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

継承関係

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">

これがあなたを助けることを願っています。

于 2015-10-27T22:27:24.553 に答える
0

Railsのdup方法を試してください:

new_record = old_record.dup.save
于 2021-04-04T17:21:36.080 に答える