ruby on rails - references - Build vs new en Rails 3
rails references (5)
En los docs Rails 3, el método de build
para asociaciones se describe como el mismo que el new
, pero con la asignación automática de la clave externa. Directamente de los documentos:
Firm#clients.build (similar to Client.new("firm_id" => id))
He leído algo similar en otro lugar.
Sin embargo, cuando uso new
(ej. some_firm.clients.new
sin ningún parámetro), la asociación firm_id
del nuevo cliente se crea automáticamente. ¡Estoy mirando los resultados ahora mismo en la consola!
¿Me estoy perdiendo de algo? ¿Los documentos están un poco desactualizados (poco probable)? ¿Cuál es la diferencia entre build
y new
?
Model.new
Tag.new post_id: 1
creará una instancia de una etiqueta con su conjunto de post_id
.
@ model.models.new
@post.tags.build
hace lo mismo Y la etiqueta instanciada estará en @post.tags
incluso antes de que se guarde.
Esto significa que @post.save
guardará tanto el poste como la etiqueta recién construida (suponiendo que se haya configurado el valor inverso). Esto es genial porque Rails validará ambos objetos antes de guardarlos, y ninguno se guardará si alguno de ellos falla la validación.
models.new vs models.build
@post.tags.build
y @post.tags.new
son equivalentes (al menos desde Rails 3.2).
Estás malinterpretando los documentos un poco. some_firm.client.new
está creando un nuevo objeto Client
partir de la colección de clientes, por lo que puede establecer automáticamente el firm_id
en some_firm.id
, mientras que los documentos llaman a Client.new
que no tiene ningún conocimiento del id. de ninguna empresa, por lo que necesita el firm_id
pasado a él.
La única diferencia entre some_firm.clients.new
y some_firm.clients.build
parece ser que build
también agrega el cliente recién creado a la colección de clients
:
henrym:~/testapp$ rails c
Loading development environment (Rails 3.0.4)
r:001 > (some_firm = Firm.new).save # Create and save a new Firm
#=> true
r:002 > some_firm.clients # No clients yet
#=> []
r:003 > some_firm.clients.new # Create a new client
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>
r:004 > some_firm.clients # Still no clients
#=> []
r:005 > some_firm.clients.build # Create a new client with build
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>
r:006 > some_firm.clients # New client is added to clients
#=> [#<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>]
r:007 > some_firm.save
#=> true
r:008 > some_firm.clients # Saving firm also saves the attached client
#=> [#<Client id: 1, firm_id: 1, created_at: "2011-02-11 00:18:47",
updated_at: "2011-02-11 00:18:47">]
Si está creando un objeto a través de una asociación, debe preferir la compilación a la new
ya que build mantiene su objeto en memoria, some_firm
(en este caso) en un estado consistente incluso antes de que cualquier objeto se haya guardado en la base de datos.
Tiene razón, la compilación y las nuevas funciones tienen el mismo efecto de establecer la clave externa, cuando se llaman a través de una asociación. Creo que la razón por la cual la documentación está escrita así es para aclarar que se está creando una instancia de un nuevo objeto Cliente, a diferencia de una nueva relación de registro activo. Este es el mismo efecto que llamar .new en una clase tendría en Ruby. Es decir que la documentación está aclarando que invocar construir sobre una asociación es lo mismo que crear un nuevo objeto (llamar .new) y pasar las claves externas a ese objeto. Estos comandos son todos equivalentes:
Firm.first.clients.build
Firm.first.clients.new
Client.new(:firm_id => Firm.first.id)
Creo que la razón por la que .build existe es que Firm.first.clients.new podría interpretarse en el sentido de que está creando un nuevo objeto de relación has_many, en lugar de un cliente real, por lo que llamar a .build es una forma de aclarar esto.
construir vs nuevo:
la mayoría de las veces nuevas y compiladas son las mismas, pero las compilaciones almacenan objetos en la memoria,
p.ej.
para nuevo:
Client.new(:firm_id=>Firm.first.id)
Para la construcción:
Firm.first.clients.build
Aquí los clientes se almacenan en la memoria, cuando se guardan firmes, también se guardan los registros asociados.
build
es solo un alias para los new
:
alias build new
El código completo se puede encontrar: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb