110

Hi (huge Rails newbie here), I have the following models:

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

and

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

When I'm about to create a new shop, I get the following error:

private method `create' called for nil:NilClass 

This is my controller:

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

I've tried different variations by reading guides and tutorials here and there, but I'm more confused than before and can't get it to work. Any help would be greatly appreciated.

2

4 Answers 4

255

A more concise way to do this is with:

@user.create_shop(params[:shop]) 

See methods added by has_one in the Ruby on Rails guides.

Sign up to request clarification or add additional context in comments.

5 Comments

This is definitely more better approach
Beware that if you create_shop more than once that it will delete the previous shop. For instance if you run @user.create_shop(params[:shop_one_info]) it will create shop_one, BUT if you run @user.create_shop(params[:shop_two_info]) that it will delete the first shop and create the second one.
The above comment about deleting the previous shop is for Rails 3.2.18, don't know about more recent versions. Can't edit comment after 5 min -_-
Found a solution, I did not set uniqueness on the associated model, so make sure you do as how it is set up in this example's Shop model.
you can alse use @user.build_shop(params)
134

First of all, here is how to do what you want:

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

Now here's why your version did not work:

You probably thought that this might work because if User had a has_many relation to Shop, @user.shops.create(params[:shop]) would work. However there is a big difference between has_many relations and has_one relations:

With a has_many relation, shops returns an ActiveRecord collection object, which has methods that you can use to add and remove shops to/from a user. One of those methods is create, which creates a new shop and adds it to the user.

With a has_one relation, you don't get back such a collection object, but simply the Shop object that belongs to the user - or nil if the user doesn't have a shop yet. Since neither Shop objects nor nil have a create method, you can't use create this way with has_one relations.

5 Comments

Thanks for your answer, sepp2k. I see now why my code couldn't work.
You could also use @user.create_shop(params[:shop]). See methods added by has_one.
The answer chosen works, but @nates solution works also. +1 to both of you.
+1 to the answer because I was wondering the same, +1 to the answer for explaining why this is and +1 to the comment for giving the best solution.
The distinction between the return values (the collection with has_many vs the object or nil from has_one) was a super helpful distinction. Thank you!
8

Two more ways if you want save instead of create:

shop = @user.build_shop shop.save shop = Show.new shop.user = @user shop.save 

Comments

4

Just to add to above answers -

@user.create_shop(params[:shop]) 

Above syntax creates new record but it subsequently deletes similar existing record.

Alternatively, if you do not want to trigger delete callback

Shop.create(user_id: user.id, title: 'Some unique title') 

This thread might be helpful. Click here

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.