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




multiple attributes (5)

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

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.


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)

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.


En su ejemplo aquí, está asignando 'P' a una variable local 'estado'. Pruebe self.status = 'P' para este rey de las cosas. Aunque sería mejor utilizar after_initialize como se menciona en otras respuestas.







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