سؤال

أريد عمل نسخة من سجل نشط، مع تغيير حقل واحد في العملية (بالإضافة إلى بطاقة تعريف).ما هي أبسط طريقة لتحقيق ذلك؟

أدرك أنه يمكنني إنشاء سجل جديد، ثم التكرار على كل حقل من الحقول لنسخ البيانات حقلاً تلو الآخر - لكنني اعتقدت أنه يجب أن تكون هناك طريقة أسهل للقيام بذلك...

مثل:

 @newrecord=Record.copy(:id)  *perhaps?*
هل كانت مفيدة؟

المحلول

للحصول على نسخة، استخدم طريقة الاستنساخ (أو dup for Rails 3.1):

# rails < 3.1
new_record = old_record.clone

#rails >= 3.1
new_record = old_record.dup

وبعد ذلك يمكنك تغيير الحقول التي تريدها.

يتجاوز ActiveRecord استنساخ Object# المضمن لتزويدك بسجل جديد (غير محفوظ في قاعدة البيانات) بمعرف غير مخصص.
لاحظ أنه لا ينسخ الارتباطات، لذا سيتعين عليك القيام بذلك يدويًا إذا كنت بحاجة إلى ذلك.

استنساخ 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، سيتعين عليك استدعاء حفظ بشكل صريح، لذلك إذا كنت تريد حفظه تلقائيًا، فقم بتغيير Task.new إلى Task.create.

سلام.

قد يعجبك أيضًا جوهرة الأميبا لأكتيف ريكورد 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 إذا كنت لا تريد نسخ المعرف

عادةً ما أقوم بنسخ السمات فقط، مع تغيير كل ما أحتاج إلى تغييره:

new_user = User.new(old_user.attributes.merge(:login => "newlogin"))

إذا كنت بحاجة إلى نسخة عميقة مع الارتباطات، فإنني أوصي بـ Deep_cloneable جوهرة.

الطريقة سهلة هي :

#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

يمكنك أيضًا التحقق من act_as_inheritable جوهرة.

"Acts As Inheritable عبارة عن جوهرة روبي مكتوبة خصيصًا لنماذج Rails/ActiveRecord.ومن المفترض أن تستخدم مع جمعية المرجعية الذاتية, أو مع نموذج له أحد الوالدين يشترك في السمات القابلة للتوريث.سيتيح لك ذلك وراثة أي سمة أو علاقة من النموذج الأصلي."

بإضافة 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">

نأمل أن يكون هذا يمكن أن تساعدك.

نظرًا لأنه قد يكون هناك المزيد من المنطق، عند تكرار نموذج، أود أن أقترح إنشاء فئة جديدة، حيث يمكنك التعامل مع كل المنطق المطلوب.ولتخفيف ذلك، هناك جوهرة يمكن أن تساعد: مهرج

وفقًا لأمثلة التوثيق الخاصة بهم، بالنسبة لنموذج المستخدم:

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

يمكنك إنشاء فئة cloner الخاصة بك:

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

ملحوظة:لا تتطلب هذه الطريقة أي جوهرة خارجية ولكنها تتطلب إصدار ActiveRecord أحدث #dup تم تنفيذ الطريقة

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top