activerecord レコードを複製する最も簡単な方法は何ですか?
-
09-06-2019 - |
質問
activerecord レコードのコピーを作成し、プロセス内の 1 つのフィールドを変更したいと考えています ( ID)。これを達成する最も簡単な方法は何でしょうか?
新しいレコードを作成して、データをフィールドごとにコピーして各フィールドを反復処理できることに気づきましたが、これを行うより簡単な方法があるに違いないと考えました...
のような:
@newrecord=Record.copy(:id) *perhaps?*
解決
コピーを取得するには、clone (または Rails 3.1 の場合は dup) メソッドを使用します。
# rails < 3.1
new_record = old_record.clone
#rails >= 3.1
new_record = old_record.dup
その後、必要なフィールドを変更できます。
ActiveRecord は組み込みの Object#clone をオーバーライドします 未割り当ての ID を持つ新しい (DB に保存されていない) レコードを提供します。
関連付けはコピーされないため、必要に応じて手動でコピーする必要があることに注意してください。
他のヒント
ニーズとプログラミング スタイルに応じて、クラスとマージの新しいメソッドを組み合わせて使用することもできます。より良いものがないために 単純 たとえば、特定の日付にスケジュールされたタスクがあり、それを別の日付に複製したいとします。タスクの実際の属性は重要ではないため、次のようになります。
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 に変更します。
平和。
あなたも気に入るかもしれません アメーバジェム ActiveRecord 3.2の場合。
あなたの場合、おそらく、 nullify
, regex
または prefix
構成 DSL で使用可能なオプション。
簡単かつ自動的な再帰的複製をサポートします。 has_one
, has_many
そして has_and_belongs_to_many
アソシエーション、フィールド前処理、およびモデルとオンザフライの両方に適用できる非常に柔軟で強力な構成 DSL が含まれます。
必ずチェックしてください アメーバのドキュメント しかし、使い方はとても簡単です...
ただ
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
アソシエーションの再帰コピーは簡単です。子モデルでもアメーバを有効にするだけです。
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 にはさらに多くのオプションがあるため、必ずドキュメントを確認してください。
楽しむ!:)
使用 ActiveRecord::Base#dup IDをコピーしたくない場合は
通常は属性をコピーし、変更する必要があるものはすべて変更します。
new_user = User.new(old_user.attributes.merge(:login => "newlogin"))
関連性のあるディープ コピーが必要な場合は、 ディープクローン可能 宝石。
簡単な方法は次のとおりです。
#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
Rails 5 では、このように単純に重複したオブジェクトまたはレコードを作成できます。
new_user = old_user.dup
を確認することもできます。 継承可能として機能する 宝石。
「Acts As Inheritable は、Rails/ActiveRecord モデル用に特別に書かれた Ruby Gem です。と一緒に使用することを目的としています。 自己参照協会, 、または継承可能な属性を共有する親を持つモデルを使用します。これにより、親モデルから属性や関係を継承できるようになります。」
追加することで acts_as_inheritable
モデルに対して、次のメソッドにアクセスできるようになります。
継承属性
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">
これがお役に立てば幸いです。
さらに多くのロジックが存在する可能性があるため、モデルを複製するときは、必要なすべてのロジックを処理する新しいクラスを作成することをお勧めします。それを軽減するために役立つ gem があります。 ピエロ
ドキュメントの例によると、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.reject {|k,_v| k.to_s == 'id'}
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
注記:この方法には外部 gem は必要ありませんが、新しい ActiveRecord バージョンが必要です。 #dup
実装されたメソッド