has_many association: building a new association object adds it to the collection ?

Recently I discovered one thing I didn’t even think about, or I believed it to work absolutely differently. So, to explain it, given the following models:

class Project < AR has_many :participants end

class Participant < AR belongs_to :project end

Here is what is going in the console:

irb(main):003:0> p=Project.create(:name=>‘java’) ←[1m←[36m (0.0ms)←[0m ←[1mSAVEPOINT active_record_1←[0m ←[1m←[35mSQL (43.0ms)←[0m INSERT INTO “projects” (“created_at”, “name”, “updated_at”) VALUES (?, ?, ?) [[" created_at", Thu, 28 Mar 2013 19:27:06 UTC +00:00], [“name”, “java”], [“updated_at”, Thu, 28 Mar 2013 19:27:06 UTC +00:00]] ←[1m←[36m (0.0ms)←[0m ←[1mRELEASE SAVEPOINT active_record_1←[0m => #<Project id: 1, name: “java”, created_at: “2013-03-28 19:27:06”, updated_at: “2013-03-28 19:27:06”> irb(main):004:0> p.participants ←[1m←[35mParticipant Load (0.0ms)←[0m SELECT “participants”.* FROM “participants” WHERE “participants”.“pro ject_id” = 1 => irb(main):005:0> part = p.participants.new(username:‘toto’) => #<Participant id: nil, username: “toto”, project_id: 1, created_at: nil, updated_at: nil> irb(main):006:0> p.participants => [#<Participant id: nil, username: “toto”, project_id: 1, created_at: nil, updated_at: nil>]

I always believed that the collection of participants should keep the same size (zero in the above case) until I call save on the Project object. As you see the collection has been changed by 1, despite the record has not been yet save to the database; Is it a normal behaviour ?

Thanks in advance for your help.

You have added one to the collection so it appears in the collection in memory. Note that there is no need to save the project object in order to add to its collection as nothing in the project object changes. It is the participant that must be saved at some point, otherwise it will be lost.

Colin

Recently I discovered one thing I didn't even think about, or I believed it to work absolutely differently. So, to explain it, given the following models:

class Project < AR has_many :participants end

class Participant < AR belongs_to :project end

Here is what is going in the console:

irb(main):003:0> p=Project.create(:name=>'java') ←[1m←[36m (0.0ms)←[0m ←[1mSAVEPOINT active_record_1←[0m ←[1m←[35mSQL (43.0ms)←[0m INSERT INTO "projects" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [[" created_at", Thu, 28 Mar 2013 19:27:06 UTC +00:00], ["name", "java"], ["updated_at", Thu, 28 Mar 2013 19:27:06 UTC +00:00]] ←[1m←[36m (0.0ms)←[0m ←[1mRELEASE SAVEPOINT active_record_1←[0m => #<Project id: 1, name: "java", created_at: "2013-03-28 19:27:06", updated_at: "2013-03-28 19:27:06"> irb(main):004:0> p.participants ←[1m←[35mParticipant Load (0.0ms)←[0m SELECT "participants".* FROM "participants" WHERE "participants"."pro ject_id" = 1 => irb(main):005:0> part = p.participants.new(username:'toto') => #<Participant id: nil, username: "toto", project_id: 1, created_at: nil, updated_at: nil> irb(main):006:0> p.participants => [#<Participant id: nil, username: "toto", project_id: 1, created_at: nil, updated_at: nil>]

I always believed that the collection of participants should keep the same size (zero in the above case) until I call save on the Project object. As you see the collection has been changed by 1, despite the record has not been yet save to the database; Is it a normal behaviour ?

You have added one to the collection so it appears in the collection in memory. Note that there is no need to save the project object in order to add to its collection as nothing in the project object changes. It is the participant that must be saved at some point, otherwise it will be lost.

Thank you, Colin, for the answer, I believed that every time you call a collection method, for example:

project.participants

a DB query will be made to get it, but it is not the case.

Regards,

Serguei