127

In the Rails 3 docs, the build method for associations is described as being the same as the new method, but with the automatic assignment of the foreign key. Straight from the docs:

Firm#clients.build (similar to Client.new("firm_id" => id))

I've read similar elsewhere.

However, when I use new (e.g. some_firm.clients.new without any parameters), the new client's firm_id association is automatically created. I'm staring at the results right now in the console!

Am I missing something? Are the docs a bit out of date (unlikely)? What's the difference between build and new?

ClosureCowboy
  • 20,825
  • 13
  • 57
  • 71

5 Answers5

210

You're misreading the docs slightly. some_firm.client.new is creating a new Client object from the clients collection, and so it can automatically set the firm_id to some_firm.id, whereas the docs are calling Client.new which has no knowledge of any Firm's id at all, so it needs the firm_id passed to it.

The only difference between some_firm.clients.new and some_firm.clients.build seems to be that build also adds the newly-created client to the clients collection:

(some_firm = Firm.new).save # Create and save a new Firm
#=> true

some_firm.clients           # No clients yet
#=> []

some_firm.clients.new       # Create a new client
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>

some_firm.clients           # Still no clients
#=> []

some_firm.clients.build     # Create a new client with build
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>

some_firm.clients           # New client is added to clients
#=> [#<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>]

some_firm.save
#=> true

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">] 

If you're creating an object through an association, build should be preferred over new as build keeps your in-memory object, some_firm (in this case) in a consistent state even before any objects have been saved to the database.

Richard-Degenne
  • 2,892
  • 2
  • 26
  • 43
henrym
  • 2,565
  • 1
  • 16
  • 14
  • 8
    Using `some_firm.client.new` also adds the client to `some_firm.clients`, and calling `save` on `some_firm` resulted in a validation error indicating that `client` was invalid. If both `new` and `build` add the new client to `some_firm`'s client collection, what does `build` do that `new` doesn't do? I'm sorry for being dense, here! – ClosureCowboy Feb 10 '11 at 14:37
  • I've added an example to my post to be more clear about the difference between `build` and `new`. As for the validation error, I'm guessing that your client model needs more data before it can be saved (e.g. a name field that can't be nil)? In which case, you'd still have to set the attributes before saving. – henrym Feb 11 '11 at 00:43
  • Thank you for those details. I am staring at different behavior right now, though I'm still on 3.0.3 (I'll update and check again in a moment). On `r:004`, `clients` for you is an empty collection; for me, it contains the `new` client. Pan Thomakos described the same behavior. And the validation error for the user said: `{:clients=>["is invalid"]}` – ClosureCowboy Feb 11 '11 at 01:06
  • 1
    +1 I received your result with 3.0.4. I'd love if someone with 3.0.3 could confirm I'm not crazy. – ClosureCowboy Feb 11 '11 at 01:32
  • @ClosureCowboy I tried to reproduce what you're seeing with 3.0.3, but I'm still getting the same behaviour as 3.0.4 (and 2.3.4). The only thing I can think of is that somehow your association classes have been patched, but I don't know how you'd figure out if that's the case or not. – henrym Feb 11 '11 at 02:48
  • 42
    @henrym It looks like in 3.2.6 clients.new and clients.build are similar in they both add the new object into the collection. I wanted to add a comment for anyone who came across this while Googling like I did – hubbard Aug 07 '12 at 04:55
  • 11
    Looks like there is no difference between them in Rails 3.2.3 – Aditya Kapoor Oct 26 '12 at 10:01
  • it's really crazy in rails 3.2 – Chamnap Nov 29 '12 at 09:44
  • 4
    This answer is not correct for Rails >3.2.13, where 'build' is just an alias for 'new'. See @HatemMahmoud's answer below. – Andreas Feb 02 '14 at 12:50
  • @henrym @hubbard @andreas This is only true of some associations/relations. Singular associations, for example, have entirely different definitions for `build` and `build_#{association}`. See [here](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/singular_association.rb#L28) and [here](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/builder/singular_association.rb#L17). – coreyward Feb 12 '14 at 01:55
95

build is just an alias for new:

alias build new

Full code can be found: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74

jayqui
  • 1,882
  • 2
  • 20
  • 18
Hatem Mahmoud
  • 403
  • 6
  • 9
  • 13
    `alias build new` as of rails 3.2.13 – fontno May 13 '13 at 23:06
  • 7
    This is only true of some associations/relations. Singular associations, for example, have entirely different definitions for `build` and `build_#{association}`. See [here](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/singular_association.rb#L28) and [here](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/builder/singular_association.rb#L17). – coreyward Feb 12 '14 at 01:54
  • 1
    Is this still true for `Rails 4`? – fatman13 Apr 22 '14 at 09:35
  • 1
    [here](https://github.com/rails/rails/issues/9167#issuecomment-52789407) is the bug report... which suggests if you were using new like restaurant.customers.new, as a way of getting a new customer associated to restaurant without appending it to restaurant.customers, to use scoped... such as restaurant.customers.scoped.new – user3334690 Aug 20 '14 at 18:15
11

You are correct, the build and new functions have the same effect of setting the foreign key, when they are called through an association. I believe the reason the documentation is written like this is to clarify that a new Client object is being instantiated, as opposed to a new active record relationship. This is the same effect that calling .new on a class would have in Ruby. That is to say that the documentation is clarifying that calling build on an association is the same is creating a new object (calling .new) and passing the foreign keys to that object. These commands are all equivalent:

Firm.first.clients.build
Firm.first.clients.new
Client.new(:firm_id => Firm.first.id)

I believe the reason .build exists is that Firm.first.clients.new might be interpreted to mean that you are creating a new has_many relationship object, rather than an actual client, so calling .build is a way of clarifying this.

Pan Thomakos
  • 34,082
  • 9
  • 88
  • 85
  • So they *are* equivalent. That's definitely what it seems. Thank you! – ClosureCowboy Feb 10 '11 at 14:49
  • 6
    This is not correct. The first two are equivalent in later versions of Rails (looks like at time of posting they were not). BUT, the last one has a significant difference in that Firm.first.clients will not contain the new client. – tybro0103 Feb 03 '14 at 18:29
4

build vs new:

mostly new and build are same but build stores object in memory,

eg:

for new:

Client.new(:firm_id=>Firm.first.id)

For build:

Firm.first.clients.build

Here clients are stored in memory, when save firm , associated records are also saved.

Kick Buttowski
  • 6,709
  • 13
  • 37
  • 58
Sarwan Kumar
  • 1,283
  • 9
  • 24
2

Model.new

Tag.new post_id: 1 will instantiate a Tag with its post_id set.

@model.models.new

@post.tags.build does the same AND the instantiated Tag will be in @post.tags even before it's saved.

This means @post.save will save both the @post and the newly built tag (assuming :inverse_of is set). This is great because Rails will validate both objects before saving, and neither will be saved if either one of them fails validation.

models.new vs models.build

@post.tags.build and @post.tags.new are equivalent (at least since Rails 3.2).

tybro0103
  • 48,327
  • 33
  • 144
  • 170
  • how about this `The only difference between some_firm.clients.new and some_firm.clients.build seems to be that build also adds the newly-created client to the clients collection:`? – Incerteza Feb 02 '15 at 06:49