Carriles 6
Rails 6 agregó métodos upsert
y upsert_all
que brindan esta funcionalidad.
Model.upsert(column_name: value)
[upsert] No crea instancias de ningún modelo ni activa devoluciones de llamada o validaciones de Active Record.
Carriles 5, 4 y 3
No si está buscando un tipo de declaración "upsert" (donde la base de datos ejecuta una actualización o una declaración de inserción en la misma operación). Fuera de la caja, Rails y ActiveRecord no tienen tal característica. Sin embargo, puedes usar la gema upsert .
De lo contrario, puede usar: find_or_initialize_by
o find_or_create_by
, que ofrecen una funcionalidad similar, aunque a costa de un acceso adicional a la base de datos, lo que, en la mayoría de los casos, no es un problema en absoluto. Entonces, a menos que tenga serias preocupaciones de rendimiento, no usaría la gema.
Por ejemplo, si no se encuentra ningún usuario con el nombre "Roger", se name
crea una instancia de una nueva instancia de usuario con su conjunto en "Roger".
user = User.where(name: "Roger").first_or_initialize
user.email = "[email protected]"
user.save
Alternativamente, puede usar find_or_initialize_by
.
user = User.find_or_initialize_by(name: "Roger")
En rieles 3.
user = User.find_or_initialize_by_name("Roger")
user.email = "[email protected]"
user.save
Puede usar un bloque, pero el bloque solo se ejecuta si el registro es nuevo .
User.where(name: "Roger").first_or_initialize do |user|
# this won't run if a user with name "Roger" is found
user.save
end
User.find_or_initialize_by(name: "Roger") do |user|
# this also won't run if a user with name "Roger" is found
user.save
end
Si desea usar un bloque independientemente de la persistencia del registro, use tap
en el resultado:
User.where(name: "Roger").first_or_initialize.tap do |user|
user.email = "[email protected]"
user.save
end
find_or_initialize_by
yfind_or_create_by
acepto un bloque. Pensé que querías decir que, ya sea que el registro exista o no, se transmitirá un bloque con el objeto de registro como argumento para realizar la actualización.En Rails 4 puedes agregar a un modelo específico:
y úsalo como
O si prefiere agregar estos métodos a todos los modelos, coloque un inicializador:
fuente
assign_or_new
devolverá la primera fila de la tabla si existe y luego esa fila se actualizará? Parece estar haciendo eso por mí.User.where(email: "[email protected]").first
devolverá nil si no se encuentra. Asegúrese de tener unwhere
alcanceupdated_at
no se tocará porqueassign_attributes
se usaAgregue esto a su modelo:
Con eso, puedes:
fuente
La magia que ha estado buscando se ha agregado en
Rails 6
Ahora puede insertar (actualizar o insertar). Para uso de un solo registro:Para varios registros, use upsert_all :
Nota :
fuente
Antigua pregunta, pero arrojo mi solución al ring para que esté completa. Necesitaba esto cuando necesitaba un hallazgo específico pero una creación diferente si no existe.
fuente
Puede hacerlo en una declaración como esta:
fuente
La gema de la secuela agrega un método update_or_create que parece hacer lo que estás buscando.
fuente