ما هي أسهل طريقة لتكرار سجل نشط؟
-
09-06-2019 - |
سؤال
أريد عمل نسخة من سجل نشط، مع تغيير حقل واحد في العملية (بالإضافة إلى بطاقة تعريف).ما هي أبسط طريقة لتحقيق ذلك؟
أدرك أنه يمكنني إنشاء سجل جديد، ثم التكرار على كل حقل من الحقول لنسخ البيانات حقلاً تلو الآخر - لكنني اعتقدت أنه يجب أن تكون هناك طريقة أسهل للقيام بذلك...
مثل:
@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# المضمن لتزويدك بسجل جديد (غير محفوظ في قاعدة البيانات) بمعرف غير مخصص.
لاحظ أنه لا ينسخ الارتباطات، لذا سيتعين عليك القيام بذلك يدويًا إذا كنت بحاجة إلى ذلك.
نصائح أخرى
اعتمادًا على احتياجاتك وأسلوب البرمجة الخاص بك، يمكنك أيضًا استخدام مزيج من طريقة الفصل الجديدة والدمج.لعدم وجود أفضل بسيط على سبيل المثال، لنفترض أن لديك مهمة مجدولة لتاريخ معين وتريد تكرارها إلى تاريخ آخر.السمات الفعلية للمهمة ليست مهمة، لذلك:
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
تم تنفيذ الطريقة