Rails find_or_create_by plus d’un atsortingbut?

Il y a un atsortingbut dynamic pratique dans l’enregistrement actif appelé find_or_create_by:

Model.find_or_create_by_(: => "")

Mais que se passe-t-il si je dois trouver_ou_crer par plus d’un atsortingbut?

Disons que j’ai un modèle pour gérer une relation M: M entre le groupe et le membre appelé GroupMember. Je pourrais avoir beaucoup d’instances où member_id = 4, mais je ne veux jamais plus d’une fois où member_id = 4 et group_id = 7. J’essaie de savoir s’il est possible de faire quelque chose comme ceci:

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

Je me rends compte qu’il y a peut-être de meilleures façons de gérer cela, mais j’aime l’idée pratique de find_or_create.

Plusieurs atsortingbuts peuvent être connectés à un and :

 GroupMember.find_or_create_by_member_id_and_group_id(4, 7) 

(utilisez find_or_initialize_by si vous ne voulez pas enregistrer l’enregistrement tout de suite)

Edit: La méthode ci-dessus est déconseillée dans Rails 4. La nouvelle méthode consiste à:

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

et

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

Edit 2: Tous ces éléments n’ont pas été pris en compte uniquement dans les atsortingbuts.

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

Exemple

 GroupMember.find_or_create_by_member_id_and_group_id(4, 7) 

devenu

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

Pour quiconque trébuche sur ce thread mais doit trouver ou créer un object avec des atsortingbuts susceptibles de changer en fonction des circonstances, ajoutez la méthode suivante à votre modèle:

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

Conseil d’optimisation: quelle que soit la solution choisie, envisagez d’append des index pour les atsortingbuts les plus fréquemment interrogés.

Dans Rails 4, vous pouvez faire:

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

Et utiliser where est différent:

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

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

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

Au contraire, find_or_create_by(member_id: 4, group_id: 7) appellera create sur GroupMember :

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

S’il vous plaît voir cet engagement pertinent sur les rails / rails.

En transmettant un bloc à find_or_create , vous pouvez transmettre des parameters supplémentaires qui seront ajoutés à l’object s’il est créé. Ceci est utile si vous validez la présence d’un champ que vous ne recherchez pas.

En supposant:

 class GroupMember < ActiveRecord::Base validates_presence_of :name end 

puis

 GroupMember.where(:member_id => 4, :group_id => 7).first_or_create { |gm| gm.name = "John Doe" } 

créera un nouveau GroupMember nommé "John Doe" s'il n'en trouve pas avec member_id 4 and group_id 7

Tu peux faire:

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

Ou simplement initialiser:

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