Access extra attributes in join table when using though in has_many relationship

六月ゝ 毕业季﹏ 提交于 2019-12-04 18:31:15

In your User model, you'll have something like:

class User < ActiveRecord::Base
  has_many :groupizations
  has_many :groups, :through => :groupizations
end

You'd access the role information just through the has_many relationship to groupizations like this in the console.

foo = User.first
bar = foo.groupizations.first
bar.role

Assuming you had groupizations on the first user.

Getting a specific user/group relationship could be done like this:

Groupizations.where("group_id = ? and user_id = ?", group.id, user.id)

Then from there you could get the role you were looking for.

Buck Doyle

I don’t think there’s an elegant way to do this, just something like this:

user.groupizations.find_by_group_id(user.groups[0].id).role

The example code you gave with the [0] doesn’t seem like a realistic use, so if you showed us how you’d actually be wanting to access role, there might be a cleaner way.

This was discussed here.

The best approach to this is to work with the join model and then delegate/proxy methods to the group, e.g:

class User < ActiveRecord::Base
  has_many :memberships, :include => :group, :dependent => :delete_all
  has_many :groups, :through => :memberships
end

class Group < ActiveRecord::Base
   has_many :memberships, :include => user, :dependent => :delete_all
   has_many :users, :through => :memberships
end

class Membership < ActiveRecord::Base
  belongs_to :user
  belongs_to :group

  def group_name
    group && group.name
  end

  def user_name
    user && user.name
  end
end

Then if you were to display a user's groups in a view:

<ul>
<% @user.memberships.each do |membership| %>
  <li><%= membership.group_name %> (<%= membership.role %>)</li>
<% end %>
</ul>

similarly for a group's users:

<ul>
<% @group.memberships.each do |membership| %>
  <li><%= membership.user_name %> (<%= membership.role %>)</li>
<% end %>
</ul>

This way only takes three queries - one each for the user, groups and memberships.

It's not clear what you are looking for exactly, so I'll throw out another example with the console output to make it more obvious what it happening. Point is, however, that to get just the role(s) for a user, you'd need to specify which of the user's groups you mean (as shown by @BuckDoyle, although he just picks the first one to mirror your example). To get a list of all a user's roles, you need to iterate over the user's groupizations.

1.9.3-p194 :050 > User.find_by_name("Homer").groupizations.each {|groupization| 
                 puts groupization.group.org + ': ' + groupization.role}

User Load (2.8ms)  SELECT "users".* FROM "users" WHERE "users"."name" = 'Homer' LIMIT 1
Groupization Load (1.5ms)  SELECT "groupizations".* FROM "groupizations" WHERE 
"groupizations"."user_id" = 2

Group Load (1.9ms)  SELECT "groups".* FROM "groups" WHERE "groups"."id" = 1 
LIMIT 1

The Movementarians: cult follower

Group Load (1.4ms)  SELECT "groups".* FROM "groups" WHERE "groups"."id" = 2 
LIMIT 1

Nuclear Plant: employee

One last thought (kind of a trivial one) "groupizations" certainly works, but if "role" is the only attribute you are going to add, naming the relationship model more concretely (say "Memberships") has a practical benefit in that it makes the relationships a little clearer, at least in my experience.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!