update rails multiple find_or_create_by create ruby-on-rails activerecord model many-to-many dynamic-attributes

ruby on rails - multiple - Rails find_or_create_by más de un atributo?



find_or_create_by rails 5 (5)

Hay un atributo dinámico útil en el registro activo llamado find_or_create_by:

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

Pero, ¿qué sucede si necesito encontrar o crear más de un atributo?

Digamos que tengo un modelo para manejar una relación M: M entre el Grupo y el Miembro llamado GroupMember. Podría tener muchas instancias en las que member_id = 4, pero no quiero más de una vez que instancias donde member_id = 4 y group_id = 7. Estoy tratando de averiguar si es posible hacer algo como esto:

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

Me doy cuenta de que puede haber mejores maneras de manejar esto, pero me gusta la conveniencia de la idea de find_or_create.


Al pasar un bloque a find_or_create , puede pasar parámetros adicionales que se agregarán al objeto si se crea nuevo. Esto es útil si está validando la presencia de un campo que no está buscando.

Asumiendo:

class GroupMember < ActiveRecord::Base validates_presence_of :name end

entonces

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

creará un nuevo GroupMember con el nombre "John Doe" si no encuentra uno con member_id 4 and group_id 7


En Rails 4 podías hacer:

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

Y usar where sea ​​diferente:

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

Esto llamará a create en GroupMember.where(member_id: 4, group_id: 7) :

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

Por el contrario, find_or_create_by(member_id: 4, group_id: 7) llamará a create en GroupMember :

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

Por favor vea este commit relevante sobre rieles / rieles.


Para cualquier otra persona que se tropiece con este hilo pero necesita encontrar o crear un objeto con atributos que puedan cambiar dependiendo de las circunstancias, agregue el siguiente método a su modelo:

# 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

Sugerencia de optimización: independientemente de la solución que elija, considere agregar índices para los atributos que consulta con más frecuencia.


Se pueden conectar múltiples atributos con un and :

GroupMember.find_or_create_by_member_id_and_group_id(4, 7)

(use find_or_initialize_by si no desea guardar el registro de inmediato)

Edición: el método anterior está en desuso en Rails 4. La nueva forma de hacerlo será:

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

y

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

Edición 2: No todos estos factores fueron factorizados fuera de los carriles, solo los atributos específicos.

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

Ejemplo

GroupMember.find_or_create_by_member_id_and_group_id(4, 7)

convirtió

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


Tu puedes hacer:

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 simplemente inicializar:

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