Domanda

Voglio fare una copia di un record activerecord, modificando un singolo campo nel processo (oltre al file id).Qual è il modo più semplice per raggiungere questo obiettivo?

Mi rendo conto che potrei creare un nuovo record e quindi scorrere ciascuno dei campi copiando i dati campo per campo, ma ho pensato che ci dovesse essere un modo più semplice per farlo...

ad esempio:

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

Soluzione

Per ottenerne una copia, utilizza il metodo clone (o dup per rails 3.1):

# rails < 3.1
new_record = old_record.clone

#rails >= 3.1
new_record = old_record.dup

Quindi puoi modificare i campi che desideri.

ActiveRecord sovrascrive il clone Object# incorporato per darti un nuovo record (non salvato nel DB) con un ID non assegnato.
Tieni presente che non copia le associazioni, quindi dovrai farlo manualmente se necessario.

Il clone di Rails 3.1 è una copia superficiale, usa invece dup...

Altri suggerimenti

A seconda delle tue esigenze e del tuo stile di programmazione, puoi anche utilizzare una combinazione del nuovo metodo della classe e dell'unione.In mancanza di meglio semplice Ad esempio, supponiamo di avere un'attività pianificata per una determinata data e di volerla duplicare in un'altra data.Gli attributi effettivi dell'attività non sono importanti, quindi:

old_task = Task.find(task_id)
new_task = Task.new(old_task.attributes.merge({:scheduled_on => some_new_date}))

creerà una nuova attività con :id => nil, :scheduled_on => some_new_date, e tutti gli altri attributi sono uguali a quelli dell'attività originale.Usando Task.new, dovrai chiamare esplicitamente save, quindi se vuoi che venga salvato automaticamente, cambia Task.new in Task.create.

Pace.

Potrebbe piacerti anche il Gemma dell'ameba per ActiveRecord 3.2.

Nel tuo caso, probabilmente vorrai utilizzare il file nullify, regex O prefix opzioni disponibili nella configurazione DSL.

Supporta la duplicazione ricorsiva semplice e automatica di has_one, has_many E has_and_belongs_to_many associazioni, preelaborazione sul campo e una configurazione DSL altamente flessibile e potente che può essere applicata sia al modello che al volo.

assicurati di controllare il Documentazione sull'ameba ma l'utilizzo è piuttosto semplice...

Appena

gem install amoeba

o aggiungi

gem 'amoeba'

al tuo Gemfile

quindi aggiungi il blocco ameba al tuo modello ed esegui il file dup metodo come al solito

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

Puoi anche controllare quali campi vengono copiati in numerosi modi, ma ad esempio, se desideri evitare che i commenti vengano duplicati ma desideri mantenere gli stessi tag, potresti fare qualcosa del genere:

class Post < ActiveRecord::Base
  has_many :comments
  has_and_belongs_to_many :tags

  amoeba do
    exclude_field :comments
  end
end

Puoi anche preelaborare i campi per indicare l'unicità sia con i prefissi che con i suffissi e con le espressioni regolari.Inoltre, ci sono anche numerose opzioni per poter scrivere nello stile più leggibile per il tuo scopo:

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

La copia ricorsiva delle associazioni è semplice, basta abilitare l'ameba anche sui modelli figlio

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

La configurazione DSL ha ancora più opzioni, quindi assicurati di controllare la documentazione.

Godere!:)

Utilizzo ActiveRecord::Base#dup se non vuoi copiare l'id

Di solito copio semplicemente gli attributi, cambiando tutto ciò di cui ho bisogno di cambiare:

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

Se hai bisogno di una copia approfondita con le associazioni, ti consiglio il deep_cloneable gemma.

Il modo più semplice è:

#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

O

# if your rails < 3.1
 o = Model.find(id)
 (1..109).each do |item|
   new_record = o.clone
   new_record.save
 end     

In Rails 5 puoi semplicemente creare oggetti duplicati o registrare come questo.

new_user = old_user.dup

Puoi anche controllare il agisce_come_ereditabile gemma.

"Acts As Inheritable è una gemma di rubino scritta appositamente per i modelli Rails/ActiveRecord.È pensato per essere utilizzato con Associazione Autoreferenziale, o con un modello avente un genitore che condivide gli attributi ereditabili.Ciò ti consentirà di ereditare qualsiasi attributo o relazione dal modello principale."

Aggiungendo acts_as_inheritable ai tuoi modelli avrai accesso a questi metodi:

eredita_attributi

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

eredita_relazioni

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

Spero che questo possa aiutarti.

Poiché potrebbe esserci più logica, quando si duplica un modello, suggerirei di creare una nuova classe, in cui gestire tutta la logica necessaria.Per facilitarlo, c'è una gemma che può aiutare: clown

Secondo i loro esempi di documentazione, per un modello Utente:

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

Crei la tua classe 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

e poi usarlo:

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

Esempio copiato dal progetto, ma darà una visione chiara di ciò che puoi ottenere.

Per un record semplice e veloce sceglierei:

Model.new(Model.last.attributes.reject {|k,_v| k.to_s == 'id'}

Ecco un esempio di sostituzione di ActiveRecord #dup metodo per personalizzare la duplicazione dell'istanza e includere anche la duplicazione della relazione:

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

Nota:questo metodo non richiede alcun gem esterno ma richiede la versione più recente di ActiveRecord con #dup metodo implementato

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top