एक्टिवरकॉर्ड रिकॉर्ड डुप्लिकेट करने का सबसे आसान तरीका क्या है?


412

मैं एक एक्टिवरकॉर्ड रिकॉर्ड की एक प्रति बनाना चाहता हूं, प्रक्रिया में एक ही फ़ील्ड ( आईडी के अलावा ) को बदलना । इसे पूरा करने का सबसे सरल तरीका क्या है?

मुझे लगता है कि मैं एक नया रिकॉर्ड बना सकता हूं, और फिर डेटा फ़ील्ड-दर-फ़ील्ड की प्रतिलिपि बनाने वाले प्रत्येक फ़ील्ड पर पुनरावृति कर सकता हूं - लेकिन मुझे लगा कि ऐसा करने का एक आसान तरीका होना चाहिए ...

जैसे कि:

 @newrecord=Record.copy(:id)  *perhaps?*

जवाबों:


622

प्रतिलिपि प्राप्त करने के लिए, क्लोन का उपयोग करें (या रेल 3.1+ के लिए डुबकी) विधि:

# rails < 3.1
new_record = old_record.clone

#rails >= 3.1
new_record = old_record.dup

फिर आप जो चाहें फ़ील्ड बदल सकते हैं।

ActiveRecord अंतर्निहित ऑब्जेक्ट # क्लोन को ओवरराइड करता है ID के साथ आपको एक नया (DB में सहेजा नहीं गया) रिकॉर्ड देने के को ।
ध्यान दें कि यह संघों की नकल नहीं करता है, इसलिए आपको ज़रूरत पड़ने पर मैन्युअल रूप से यह करना होगा।

रेल 3.1 क्लोन एक उथली प्रति है, इसके बजाय डुबकी का उपयोग करें ...


6
क्या यह अभी भी 3.1.0.beta रेल में काम करता है? जब मैं करता हूं q = p.clone, और फिर p == q, मैं trueवापस आ जाता हूं । दूसरी ओर, अगर मैं उपयोग करता हूं, तो उनकी तुलना करते समय q = p.dupमैं falseवापस आ जाता हूं।
शरद ऋतु 2

1
रेल क्लोन पर 3.1 डॉक्स का कहना है कि यह अभी भी काम करता है, लेकिन मैं रेल 3.1.0.rc4 उपयोग कर रहा हूँ और यहाँ तक कि new?विधि काम नहीं कर रहा।
तुरादग

12
ऐसा लगता है कि इस कार्यक्षमता को डंप के
skattyadz

74
निश्चित रूप से क्लोन का उपयोग न करें। जैसा कि अन्य पोस्टरों ने क्लोन विधि का उल्लेख किया है अब कर्नेल # क्लोन का उपयोग करने के लिए प्रतिनिधि हैं जो आईडी को कॉपी करेगा। ActiveRecord का उपयोग करें :: अब से बेस #
डुप्लिकेट

5
मुझे कहना है, यह एक वास्तविक दर्द था। यदि आपके पास अच्छी युक्ति नहीं है, तो इस तरह की कार्यक्षमता में एक साधारण बदलाव कुछ महत्वपूर्ण सुविधाओं को अपंग कर सकता है।
मैट स्मिथ

74

अपनी आवश्यकताओं और प्रोग्रामिंग शैली के आधार पर, आप कक्षा की नई पद्धति के संयोजन का भी उपयोग कर सकते हैं और विलय कर सकते हैं। एक बेहतर सरल की कमी के लिए उदाहरण लिए, मान लीजिए कि आपके पास एक निश्चित तिथि के लिए निर्धारित कार्य है और आप इसे किसी अन्य तिथि को डुप्लिकेट करना चाहते हैं। कार्य की वास्तविक विशेषताएँ महत्वपूर्ण नहीं हैं, इसलिए:

old_task = Task.find (task_id)
new_task = टास्क.न्यू (old_task.attributes.merge ({: शेड्यूल_ऑन => some_new_date}))

के साथ एक नया कार्य पैदा करेगा :id => nil, :scheduled_on => some_new_dateऔर अन्य सभी विशेषताओं मूल कार्य के रूप में एक ही। टास्क.न्यू का उपयोग करते हुए, आपको स्पष्ट रूप से सेव को कॉल करना होगा, इसलिए यदि आप चाहते हैं कि यह अपने आप सेव हो जाए, तो टास्क को हटा दें।

शांति।


5
यह सुनिश्चित नहीं है कि यह कितना अच्छा विचार है कि b / c आपको WARNING: Can't mass-assign protected attributes: id, due_date, created_at, updated_atवापस मिल जाए
bcackerman

जब मैं ऐसा करता हूं, तो मुझे एक कॉलम के साथ एक अज्ञात विशेषता त्रुटि मिलती है जो कि has_many संबंध के कारण एक कॉलम के साथ होती है। क्या इसके आसपास कोई रास्ता है?
रूबेन मार्टिनेज जूनियर 19

2
@RubenMartineJr। मुझे पता है कि यह एक पुरानी पोस्ट है, लेकिन हाँ आप इसके चारों ओर 'हैशटैग' का उपयोग करके इसे प्राप्त कर सकते हैं। => some_new_date}))
निन्नीगी

@PhillipKoebbe आपको धन्यवाद - लेकिन क्या होगा अगर मैं चाहता हूं कि आईडी शून्य न हो? मैं चाहता हूं कि जब मैं डुप्लिकेट बनाऊं तो रेल अपने आप एक नई आईडी असाइन कर दे - क्या यह संभव है?
BKSpurgeon

1
old_task.attribtes ID फ़ील्ड को दुर्भाग्य से असाइन करता है। यह मेरे लिए काम नहीं कर रहा है
BKSpurgeon

32

आप ActiveRecord 3.2 के लिए अमीबा रत्न को पसंद कर सकते हैं ।

आपके मामले में, आप शायद का उपयोग करना चाहते हैं nullify, regexया prefixविन्यास डीएसएल में उपलब्ध विकल्पों।

यह आसान और स्वचालित पुनरावर्ती दोहराव का समर्थन करता है has_one, has_manyऔरhas_and_belongs_to_many संघों, क्षेत्र प्रीप्रोसेसिंग और एक अत्यधिक लचीला और शक्तिशाली कॉन्फ़िगरेशन डीएसएल जिसे मॉडल और मक्खी दोनों पर लागू किया जा सकता है।

अमीबा प्रलेखन की जाँच करना सुनिश्चित करें लेकिन उपयोग बहुत आसान है ...

केवल

gem install amoeba

या जोड़ें

gem 'amoeba'

अपने रत्न के लिए

फिर अमीबा ब्लॉक को अपने मॉडल में जोड़ें और 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

कॉन्फ़िगरेशन डीएसएल में अभी और विकल्प हैं, इसलिए प्रलेखन की जांच करना सुनिश्चित करें।

का आनंद लें! :)


बहुत बढ़िया जवाब। विस्तार के लिए धन्यवाद!
डेरेक प्रायर

धन्यवाद यह काम करता है !! लेकिन मेरे पास एक सवाल है कि मैं क्लोन किए गए ऑब्जेक्ट को सहेजने से पहले क्लोनिंग के साथ नई प्रविष्टियां कैसे जोड़ूं?
मोहम्मद अनस

1
बस यहाँ एक तय है। सही तरीका है .amoeba_dup, सिर्फ नहीं .dup। मैं इस कोड को निष्पादित करने की कोशिश कर रहा था, लेकिन यह यहां काम नहीं कर रहा था।
विक्टर

31

यदि आप आईडी की प्रतिलिपि नहीं बनाना चाहते हैं तो ActiveRecord :: Base # dup का उपयोग करें


1
@ ऊपर दिए गए उत्तर के अनुसार, यह रेल के लिए सही विधि की तरह दिखता है <3.1 है.clone
दान वीवर

24

मैं आमतौर पर सिर्फ विशेषताओं की नकल करता हूं, जो कुछ भी मुझे बदलने की जरूरत है उसे बदल रहा हूं:

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

जब मैं ऐसा करता हूं, तो मुझे unknown attributeएक स्तंभ के कारण एक त्रुटि मिलती है जो कि has_many संबंध के कारण वहां मौजूद है। क्या इसके आसपास कोई रास्ता है?
रुबेन मार्टिनेज जूनियर।

rails4 के साथ, यह रिकॉर्ड के लिए एक अद्वितीय आईडी नहीं बनाता है
बेन

4
रेल 4 के साथ एक नया रिकॉर्ड बनाने के लिए, करें User.create(old_user.attributes.merge({ login: "newlogin", id: nil }))। यह नए उपयोगकर्ता को सही यूनिक आईडी से बचाएगा।
राजेश

रेल में हैश # को छोड़कर और हैश # स्लाइस है , संभावित रूप से सुझाई गई विधि को सबसे शक्तिशाली और कम त्रुटि वाला है। अतिरिक्त लिबास जोड़ने की जरूरत नहीं है, विस्तार करने में आसान है।
कुकाहबे

10

यदि आपको संघों के साथ एक गहरी प्रतिलिपि की आवश्यकता है, तो मैं डीप_क्लोनबल रत्न की सिफारिश करता हूं


मैं भी। मैंने इस मणि की कोशिश की और इसने पहली बार काम किया, उपयोग में बहुत आसान है।
रोब

4

रेल 5 में आप केवल इस तरह डुप्लिकेट ऑब्जेक्ट या रिकॉर्ड बना सकते हैं।

new_user = old_user.dup

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     

2

#dupउदाहरण के दोहराव को अनुकूलित करने और संबंध दोहराव को शामिल करने के लिए यहां ActiveRecord पद्धति को ओवरराइड करने का एक नमूना दिया गया है :

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लागू किया गया है


0

आप भी कृत्यों की जाँच कर सकते हैं_संबंधी रत्न।

"एक्ट्स इनहेरिटेबल एक रूबी रत्न है जो विशेष रूप से रेल्स / एक्टिवरॉर्ड मॉडल्स के लिए लिखा जाता है। इसका उपयोग सेल्फ-रेफ़रेंशियल एसोसिएशन के साथ या अभिभावक वाले मॉडल के साथ किया जाता है , जो अंतर्निहित विशेषताओं को साझा करता है। यह आपको किसी भी विशेषता को प्राप्त करने देगा। मूल मॉडल से संबंध। "

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

आशा है इससे आपको सहायता मिलेगी।


0

चूंकि अधिक तर्क हो सकता है, जब एक मॉडल की नकल करते हुए, मैं एक नया वर्ग बनाने का सुझाव दूंगा, जहां आप सभी आवश्यक तर्क संभालते हैं। यह आसान करने के लिए, एक मणि है जो मदद कर सकता है: जोकर

एक उपयोगकर्ता मॉडल के लिए उनके प्रलेखन उदाहरण के अनुसार:

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'}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.