質問

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

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

他のヒント

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

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 実装されたメソッド

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top