Buenas, me he encontrado con un problema al intentar actualizar dos
modelos de forma automática, se lo comento para ver si pueden echarme
un cable. Gracias.
En un formulario, una relación 1 a 1 (lector (es un) usuario)
= f.label :name
= f.text_field :name, :class => ‘required’
- fields_for “reader[user_associations][]”, @reader.user do |u|
= u.label :email
= u.text_field :email, :class => ‘required’
En mi modelo lector
def user_associations=(user_associations)
user_associations.each {|value| build_user(value) }
end
Hasta aquí es perfecto, pero solo a la hora de crear un elemento
nuevo, no así a la hora de editar
Me explico mejor, cuando creo un elemento lector nuevo, se crea un
hash así
“user_associations” => e[{“email”=>“[email protected]”}]
y un html así
<input id=“reader_user_associations__password” name="reader
[user_associations]e[]e[email]>
pero cuando voy a actualizar el registro se crea un hash así
“user_associations” => e{“11” => {“email”=>“[email protected]”}}
y el html de la siguiente manera
<input id=“reader_user_associations_11_password” name="reader
[user_associations]e[11]e[email]>
Saben cual puede ser el motivo de que a la hora de actualizar no se
actualice el usuario?
Gracias de nuevo.
Saludos.
On Sun, Jun 22, 2008 at 3:19 AM, alarkspur [email protected] wrote:
= u.label :email
y el html de la siguiente manera
<input id=“reader_user_associations_11_password” name="reader
[user_associations] [11] [email]>
Saben cual puede ser el motivo de que a la hora de actualizar no se
actualice el usuario?
Yep, si el modelo no es new_record? al usar “[]” Rails pone el ID para
que le llegue al controlador y en ese caso recibes un hash de hashes
con los IDs como llave, en lugar de un array de hashes.
Puedes hacer dos cosas: una es soportar en el setter las dos situaciones
a mano.
Otra es usar :index => nil asi:
fields_for “reader[user_associations][]”, @reader.user, :index => nil
do |u|
(a partir de cierta version de Rails, creo que la 2.0, si no hay que
poner :index => nil en cada campo de los que pertenecen a ese
fields_for), y en tal caso borrar + build del asociado en el setter
sin mas complicaciones.
Todo esto sucede dentro de la transaccion iniciada por el save del
padre.
Muchas gracias Xavier por la ayuda, pero ni con esas ni con la api de
AR consigo actualizar.
Ahora tengo el setter de la siguiente manera
def user_associations=(user_associations)
user_associations.each do |value|
if user.nil?
build_user(value)
else
if value[“password”].empty? ? user.update_attribute
(‘email’, value[“email”]) : user.update_attributes(value)
end
end
end
Con user.nil? distingo entre crear y actualizar y evalúo password
para no tener que al actualizar introducirlo de nuevo, lo que no
alcanzo a terminar de entender es que a pesar de que las condiciones
del setter están bien, por que sigue siendo necesario introducir el
password.
Si el password esta vació tendría que hacer el update_attribute del
mail y así se evitaría la comprobación del password en el setter del
modelo user ¿no es esto
así?
Gracias por la ayuda.
Saludos.
El 22/06/2008, a las 10:09, Xavier N.
escribió:
Yep, si el modelo no es new_record? al usar “[]” Rails pone el ID para
2008/6/22 alarkspur [email protected]:
if value["password"].empty? ? user.update_attribute
(‘email’, value[“email”]) : user.update_attributes(value)
end
end
end
Con user.nil? distingo entre crear y actualizar
Pero no es suficiente, de hecho no hay que hacerlo asi.
El quid esta en que, como ya habias observado, user_association es o
bien un array (nueva asociacion), o bien un hash (edicion de la ya
existente).
Tu codigo hace algo porque Hash#each existe, pero ya ves que no es lo
que necesitas.
Al tratarse de una has_one ademas no iteraras, la iteracion hace falta
cuando usas esa tecnica para editar una has_many.
El 22/06/2008, a las 23:33, Xavier N.
escribió:
build_user(value)
else
if value["password"].empty? ? user.update_attribute
(‘email’, value[“email”]) : user.update_attributes(value)
end
end
end
Con user.nil? distingo entre crear y actualizar
Pero no es suficiente, de hecho no hay que hacerlo asi.
Por que? lo estoy tratando todo a nivel de modelo, ¿no es así como
hay que hacerlo?
El quid esta en que, como ya habias observado, user_association es o
bien un array (nueva asociacion), o bien un hash (edicion de la ya
existente).
Vale, vale, esto entendido, de todas formas como había usado la
segunda opción que me recomendaste la de :index => nil, el setter
siempre recibía un array.
Como he probado casi de todo y todas las opciones, comentar como
curiosidad que la opción :index => nil no funciona con los select,
solo funciona con los campos de texto.
Al tratarse de una has_one ademas no iteraras, la iteracion hace falta
cuando usas esa tecnica para editar una has_many.
Es a esto a lo que te refieres cuando has dicho “de hecho no hay que
hacerlo así”, ¿mejor lo trato como has_many? si se me ha pasado por
la cabeza el ponerlo todo como has_many que seguro me da menos
problemas.
Voy a seguir dandole vueltas a ver si encuentro una mejor forma de
solucionarlo.
Gracias.
Saludos.
Muchas gracias Xavier por la ayuda y paciencia al seguir el hilo.
Al final lo he resuelto de varias maneras, en el controlador, en el
modelo, con has_one, con has_manny, y de varias formas mas… ahora
no se por cual decidirme, toy leyendo un poco sobre MVC para ver que
opción puede ser mejor.
Gracias de nuevo.
Saludos.
El 23/06/2008, a las 3:22, Xavier N.
escribió:
2008/6/23 alarkspur [email protected]:
2008/6/23 alarkspur [email protected]:
Como he probado casi de todo y todas las opciones, comentar como
curiosidad que la opción :index => nil no funciona con los select,
solo funciona con los campos de texto.
Buena.
Otra que yo vi es un gotcha relacionado con check boxes que documente
aqui:
http://github.com/lifo/docrails/commit/ea40dc09a564ebc2b0034e3c1ae2c4daffe7e79b
Es a esto a lo que te refieres cuando has dicho “de hecho no hay que
hacerlo asÔ, ¿mejor lo trato como has_many? si se me ha pasado por
la cabeza el ponerlo todo como has_many que seguro me da menos
problemas.
Me parece que el codigo esta basando en el railcast que explica esa
tecnica, pero alli la cosa va de una has_many.
En tu caso al tratarse de una has_one no hace falta el “[]” ya que de
haberlo el asociado es uno solo. Si quitas el “[]” el setter recibira
un hash corriente con atributo => valor del modelo asociado.