154

In this example, I create a user with no profile, then later on create a profile for that user. I tried using build with a has_one association but that blew up. The only way I see this working is using has_many. The user is supposed to only have at most one profile.

I have been trying this. I have:

class User < ActiveRecord::Base
  has_one :profile
end

class Profile < ActiveRecord::Base
  belongs_to :user
end

But when I do:

user.build_profile 

I get the error:

ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'profiles.user_id' in 'where clause': SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4)  LIMIT 1

Is there a way in rails to have 0 or 1 association?

Promise Preston
  • 24,334
  • 12
  • 145
  • 143
espinet
  • 1,703
  • 2
  • 11
  • 7

3 Answers3

387

The build method signature is different for has_one and has_many associations.

class User < ActiveRecord::Base
  has_one :profile
  has_many :messages
end

The build syntax for has_many association:

user.messages.build

The build syntax for has_one association:

user.build_profile  # this will work

user.profile.build  # this will throw error

Read the has_one association documentation for more details.

m33lky
  • 7,055
  • 9
  • 41
  • 48
Harish Shetty
  • 64,083
  • 21
  • 152
  • 198
  • 31
    The different syntax for the has_one always catches me out... dammit! – Galaxy May 10 '12 at 10:24
  • 12
    It's funny how the top rated and accepted answer here is answering a different question from the one the OP asked. – Ajedi32 Jun 27 '14 at 15:31
  • Supposedly if user belonged to profile(meaning user table has foreign_key profile_id in its table) then also building profile for user will work as mentioned above i.e but for new action only `user.build_profile ` for edit `user.build_profile if user.profile.nil? ` and if you want to build profile while creating user then write `accepts_nested_attributes_for :profile` this in User model. and in form which user is being created write `<%= f.simple_fields_for :profile do |p| %>` this and go on. – zeal May 16 '15 at 06:22
  • but why this different behavior was kept for has_one or has_many? There would be some reason while designing, I think and expect. – inquisitive Jan 29 '17 at 12:22
  • 2
    @Ajedi32 the answer matches the question's title but not the body. Given that this (`build_`) is a quite weird and unexpected behaviour in Rails, there's a lot more people looking for this answer than the actual questions' answer, if you know what I mean. – Max Williams Nov 10 '17 at 11:53
19

Take a good look at the error message. It is telling you that you do not have required column user_id in the profile table. Setting the relationships in the model is only part of the answer.

You also need to create a migration that adds the user_id column to the profile table. Rails expects this to be there and if it is not you cannot access the profile.

For more information please take a look at this link:

Association Basics

rohin-arka
  • 779
  • 4
  • 10
sosborn
  • 14,676
  • 2
  • 42
  • 46
  • 1
    I just figured out my problem. The book I am learning from didn't explain the foreign key creation very well. I created a new migration which adds a foreign key to my model. thanks. – espinet Mar 19 '10 at 05:22
  • Do you need to create the column yourself every time? I had this idea that it happened automagically. I don't know where I got that idea. – Rimian Jan 26 '12 at 10:40
  • You can add the column when generate a model using command line, something like `rails g model profile user:references:index address:string bio:text`. – duykhoa Jun 25 '20 at 13:36
-14

It should be a has_one. If build isn't working, you can just use new:

ModelName.new( :owner => @owner )

is the same as

@owner.model_names.build
Karl
  • 6,035
  • 5
  • 30
  • 39
  • 11
    This isn't the same: if you create a new model_name with build, when @owner is saved then the new model_name will be saved too. So, you can use build to make a parent and children which will get saved together. This isn't the case if you make a model_name with .new – Max Williams Apr 25 '12 at 14:37