has_many through association on unsaved objects

Hello,

I just stumbled upon a behaviour about associations I do not really understand why Rails/ActiveRecord cannot get the connection. Using activerecord (4.2.0.beta2).

To describe it, lets work with theses models:

class User < ActiveRecord::Base
    has_many :project_participations
    has_many :projects, through: :project_participations, inverse_of: :users
end

class ProjectParticipation < ActiveRecord::Base
    belongs_to :user
    belongs_to :project

    enum role: { member: 0, manager: 1 }
end

class Project < ActiveRecord::Base
    has_many :project_participations
    has_many :users, through: :project_participations, inverse_of: :projects
end

``

A user can participate in many projects with a role as a member or a manager. The connecting model is called ProjectParticipation.

I now have a problem using the associations on unsaved objects. The following commands work like I think they should work:

# first example

u = User.new
p = Project.new

u.projects << p

u.projects
=> #<ActiveRecord::Associations::CollectionProxy [#<Project id: nil>]>

u.project_participations
=> #<ActiveRecord::Associations::CollectionProxy [#<ProjectParticipation id: nil, user_id: nil, project_id: nil, role: nil>]>

``

So far so good - AR created the ProjectParticipation by itself and I can access the projects of a user with u.projects.

But it does not work if I create the ProjectParticipation by myself:``

# second example

u = User.new
pp = ProjectParticipation.new
p = Project.new

pp.project = p # assign project to project_participation

u.project_participations << pp # assign project_participation to user

u.project_participations
=> #<ActiveRecord::Associations::CollectionProxy [#<ProjectParticipation id: nil, user_id: nil, project_id: nil, role: nil>]>

u.projects
=> #<ActiveRecord::Associations::CollectionProxy []>

Why are the projects empty? I cannot access the projects by u.projects like before, even the ProjectParticipation is there.

But if I go through the participations directly, the project shows up:

u.project_participations.map(&:project) => [#]


Shouldn't it work like the first example directly:
u.projects returning me all projects not depending on whether I create the join object by myself or not? Or how can I make AR aware of this?

u.projects is going to load things from the database if the record is saved, but otherwise it will only return objects you’ve explicitly stored in it.

The through association is not the same as just mapping &:project over project_participations.

Can you describe what you’re trying to do in more detail? There’s likely a way to make AR do the right thing.

–Matt Jones