2010-10-01 14 views
61

Hola (enormes rieles novato aquí), tengo los siguientes modelos:Rieles: crear en asociación has_one

class Shop < ActiveRecord::Base 
    belongs_to :user 
    validates_uniqueness_of :title, :user_id, :message => "is already being used" 
end 

y

class User < ActiveRecord::Base 
    has_one :shop, :dependent => :destroy 
end 

Cuando estoy a punto de crear una nueva tienda, el siguiente error:

private method `create' called for nil:NilClass 

Ésta es mi controlador:

@user = current_user 
@shop = @user.shop.create(params[:shop]) 

He intentado diferentes variaciones leyendo guías y tutoriales aquí y allá, pero estoy más confundido que antes y no puedo hacerlo funcionar. Cualquier ayuda sería muy apreciada.

+0

título de la pregunta Editado para reflejar cuestión. Duplicate of [Usando build con una asociación has_one en rieles] (http://stackoverflow.com/questions/2472982/using-build-with-a-has-one-association-in-rails) –

+1

también puedes usar '@ user.build_shop (params) ' – ImranNaqvi

Respuesta

82

En primer lugar, aquí es cómo hacer lo que quiere:

@user = current_user 
@shop = Shop.create(params[:shop]) 
@user.shop = @shop 

Ahora aquí es por eso que su versión no funcionó:

Probablemente pensaron que esto podría funcionar, porque si el usuario tenía una has_many relación con Comprar, @user.shops.create(params[:shop])sería trabajo. Sin embargo, hay una gran diferencia entre has_many relaciones y las relaciones: has_one

Con una relación has_many, shops devuelve un objeto de colección de ActiveRecord, que cuenta con métodos que se pueden utilizar para agregar y quitar tiendas a/desde un usuario. Uno de esos métodos es create, que crea una nueva tienda y se lo agrega al usuario.

Con una relación has_one, no recupera un objeto de colección, sino simplemente el objeto Shop que pertenece al usuario, o nulo si el usuario aún no tiene una tienda. Como ni Shop Objects ni nil tienen un método create, no puede usar create de esta manera con relaciones has_one.

+0

Gracias por su respuesta, sepp2k. Ahora veo por qué mi código no podría funcionar. – Neko

+78

También podría usar '@ user.create_shop (params [: shop])'. Ver [métodos agregados por has_one] (http://guides.rubyonrails.org/association_basics.html#methods-added-by-has_one). – nates

+0

La respuesta elegida funciona, pero la solución @nates también funciona. +1 a ambos. – nfriend21

147

Una forma más concisa de hacerlo es con:

@user.create_shop(params[:shop]) 

Ver methods added by has_one en el Ruby on Rails guías.

+3

Este es sin duda el mejor enfoque – Magnum

+2

Tenga en cuenta que si crea más de una tienda que eliminará la tienda anterior. Por ejemplo, si ejecuta '@ user.create_shop (params [: shop_one_info])' creará shop_one, PERO si ejecuta '@ user.create_shop (params [: shop_two_info])' que eliminará la primera tienda y creará el segundo. – ecoding5

+0

El comentario anterior sobre la eliminación de la tienda anterior es para Rails 3.2.18, no sé sobre versiones más recientes. No puedo editar el comentario después de 5 minutos -_- – ecoding5

2

Dos maneras más si quieres save en lugar de create:

shop = @user.build_shop 
shop.save 

shop = Show.new 
shop.user = @user 
shop.save 
Cuestiones relacionadas