Evolutio
Evolutio

Reputation: 974

rails wrong association with has_many

I tried to set up a basic association between users and projects:

user.rb

class User < ActiveRecord::Base
  has_many :projects, foreign_key: 'owner_id'
  has_many :project_members, through: :project_members
end

project.rb

class Project < ActiveRecord::Base
  has_many :project_members, dependent: :destroy
  has_many :users, through: :project_members
end

project_member.rb

class ProjectMember < ActiveRecord::Base
  belongs_to :user
  belongs_to :project
end

my project_members table:

+----+------------+---------+
| id | project_id | user_id |
+----+------------+---------+
|  1 |          1 |       1 |
|  2 |          2 |       1 |
+----+------------+---------+

and my project table:

+----+-------+----------+
| id | name  | owner_id |
+----+-------+----------+
|  1 | test1 |        1 |
|  2 | test2 |        2 |
+----+-------+----------+

why I get with

current_user.projects

only the projects where the projects.owner_id = current_user.id and not the projects where the user is member?

But I think it's the wrong side I tried to get the data I want. I'm on /projects where the projects controller gets the data. I think I should use something like that:

class ProjectsController < ApplicationController
  # GET /projects
  def index
    @projects = Project.all
  end
end

but how I can get only the projects where current_user.id is member of?

Upvotes: 2

Views: 999

Answers (2)

Richard Peck
Richard Peck

Reputation: 76774

As an addition to Kasper Johansen's answer, you may also wish to look into has_and_belongs_to_many:

enter image description here

The main reason you'd use this is because you're not using any extra attributes in your join model (which is your current setup).

If you want to keep it that way, you can do away with your join model by using the has_and_belongs_to_many association in place of has_many :through:

#app/models/user.rb
class User < ActiveRecord::Base
   has_and_belongs_to_many :projects
end

#join table - projects_users

#app/models/project.rb
class Project < ActiveRecord::Base
   has_and_belongs_to_many :users
end

From the docs:

The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don't need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you'll need to remember to create the joining table in the database).


In regards your original problem, you have to also remember that in order to get the data back from an associative model, you have to set up the associations that will be populated with that data.

You mention...

why I get with current_user.projects only the projects where the projects.owner_id = current_user.id

... because you've set the association of has_many :projects, foreign_key: 'owner_id'

Rails is not magic - it has to take what associations you give it and populate the data in those methods accordingly:

#app/models/user.rb
class User < ActiveRecord::Base
   has_many :owned_projects, class_name: "Project", foreign_key: :owner_id
   has_and_belongs_to_many :projects
end

#app/models/project.rb
class Project < ActiveRecord::Base
   has_and_belongs_to_many :users
end

Hopefully gives you some more context to add to Kasper's answer.

Upvotes: 3

kaspernj
kaspernj

Reputation: 1253

I think you should set that up a tiny bit different:

class User < ActiveRecord::Base
  has_many :owned_projects, class_name: "Project", foreign_key: 'owner_id', dependent: :restrict_with_error
  has_many :project_members, dependent: :destroy
  has_many :projects, through: :project_members
end

class Project < ActiveRecord::Base
  has_many :project_members, dependent: :destroy
  has_many :users, through: :project_members

  belongs_to :owner, class_name: "User"
end

In order to get all the projects the current_user is a member of you can do:

current_user.projects

In order to get all the projects the current_user owns you can do:

current_user.owned_projects

Upvotes: 5

Related Questions