ruby-on-rails - Rails find_or_create da più di un attributo?





activerecord model many-to-many dynamic-attributes (5)


Più attributi possono essere collegati con un and :

GroupMember.find_or_create_by_member_id_and_group_id(4, 7)

(usa find_or_initialize_by se non vuoi salvare subito il record)

Modifica: il metodo precedente è obsoleto in Rails 4. Il nuovo modo di farlo sarà:

GroupMember.where(:member_id => 4, :group_id => 7).first_or_create

e

GroupMember.where(:member_id => 4, :group_id => 7).first_or_initialize

Modifica 2: non tutti questi sono stati scomposti da binari solo quelli specifici degli attributi.

https://github.com/rails/rails/blob/4-2-stable/guides/source/active_record_querying.md

Esempio

GroupMember.find_or_create_by_member_id_and_group_id(4, 7)

divenne

GroupMember.find_or_create_by(member_id: 4, group_id: 7)

C'è un utile attributo dinamico nel record attivo chiamato find_or_create_by:

Model.find_or_create_by_<attribute>(:<attribute> => "")

Ma cosa succede se ho bisogno di find_or_create per più di un attributo?

Supponiamo che abbia un modello per gestire una relazione M: M tra Group e Member chiamata GroupMember. Potrei avere molti casi in cui member_id = 4, ma non voglio mai più di una istanza dove member_id = 4 e group_id = 7. Sto cercando di capire se è possibile fare qualcosa del genere:

GroupMember.find_or_create(:member_id => 4, :group_id => 7)

Mi rendo conto che potrebbero esserci modi migliori per gestirlo, ma mi piace la convenienza dell'idea di find_or_create.




In Rails 4 puoi fare:

GroupMember.find_or_create_by(member_id: 4, group_id: 7)

E usa where è diverso:

GroupMember.where(member_id: 4, group_id: 7).first_or_create

Questo chiamerà create su GroupMember.where(member_id: 4, group_id: 7) :

GroupMember.where(member_id: 4, group_id: 7).create

Al contrario, find_or_create_by(member_id: 4, group_id: 7) chiamerà create su GroupMember :

GroupMember.create(member_id: 4, group_id: 7)

Si prega di vedere questo commit rilevante su rotaie / rotaie.




Tu puoi fare:

User.find_or_create_by(first_name: 'Penélope', last_name: 'Lopez')
User.where(first_name: 'Penélope', last_name: 'Lopez').first_or_create

O per inizializzare semplicemente:

User.find_or_initialize_by(first_name: 'Penélope', last_name: 'Lopez')
User.where(first_name: 'Penélope', last_name: 'Lopez').first_or_initialize



Per chiunque altro si imbatta in questo thread ma deve trovare o creare un oggetto con attributi che potrebbero cambiare in base alle circostanze, aggiungere il seguente metodo al modello:

# Return the first object which matches the attributes hash
# - or -
# Create new object with the given attributes
#
def self.find_or_create(attributes)
  Model.where(attributes).first || Model.create(attributes)
end

Suggerimento per l'ottimizzazione: indipendentemente dalla soluzione scelta, prendere in considerazione l'aggiunta di indici per gli attributi che si richiedono più frequentemente.




Credo che quello che stai cercando sia assign_attributes .

È fondamentalmente lo stesso di update_attributes ma non salva il record:

class User < ActiveRecord::Base
  attr_accessible :name
  attr_accessible :name, :is_admin, :as => :admin
end

user = User.new
user.assign_attributes({ :name => 'Josh', :is_admin => true }) # Raises an ActiveModel::MassAssignmentSecurity::Error
user.assign_attributes({ :name => 'Bob'})
user.name        # => "Bob"
user.is_admin?   # => false
user.new_record? # => true




ruby-on-rails activerecord model many-to-many dynamic-attributes