How to get users username from group when both has_many memberships - ruby-on-rails

So my models looks like this:
class Group
has_many :memberships
has_many :users, :through => :memberships
end
class Membership
belongs_to :user
belongs_to :group
end
class User
has_many :memberships
has_many :groups, :through => :memberships
end
My question is, how can I find a user who created group in view? Cause when I am iterating like this, it doesnt work:
<= #groups.each do |group| =>
(What now? I have group and want to know who was a creator. I cant just type simply group.membership.username
<= end =>
And I cant just type #groups.memberships.each do because I use another parameters like group title, image, etc.

Related

search query associated models

I am implementing groups feature. I am stuck at searching members of a group.
Let say
Class Group
has_many :group_memberships
has_many :members, :source => :user, :through => :group_memberships
end
Class GroupMembership
belongs_to :group
belongs_to :user
end
Class User
has_many :group_memberships
has_many :groups, :through => :group_memberships
has_one :profile, :dependent => :destroy
end
Class Profile
belongs_to :user
end
How to search group members, with searchable fields in profile
Could something like below work for you?
group = Group.find(id)
users = group.users.joins(:profiles).where("profile.age>18")
You can do this with the help of eager loading -
just Specify Condition on Eager Loaded Associations like -
group = Group.last
users = group.users.includes(:profiles).where("profiles.name" => "xyz")
For more details refer -
http://guides.rubyonrails.org/active_record_querying.html#specifying-conditions-on-eager-loaded-associations

Namespaced Join Table Refers to Itself

I have the following models:
class User < ActiveRecord::Base
has_many :groups, :through => :memberships
has_many :memberships, :class_name => "User::Group"
end
class Group < ActiveRecord::Base
has_many :users, :through => :members
has_many :members, :class_name => "User::Group"
end
class User::Group < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
I make the following association call:
#user.groups
And it returns an array of User::Groups, instead. Am I overlooking something?
I changed the name of the join table to User::Membership, and now everything works as expected. It seems that naming the last part of the namespace after another model was causing some sort of interference, though I'm not sure why. Does anyone have a more informed explanation?

Rails 3, how to make sure Group has_one user.role = groupleader

My current Group model:
class Group < ActiveRecord::Base
has_many :memberships, :dependent => :destroy
has_many :users, :through => :memberships
end
My Current User Model
class User < ActiveRecord::Base
has_and_belongs_to_many :roles
has_many :memberships, :dependent => :destroy
has_many :groups, :through => :memberships
#some more stuff
end
Membership Model
class Membership < ActiveRecord::Base
attr_accessible :user_id, :group_id
belongs_to :user
belongs_to :group
end
Role Model
class Role < ActiveRecord::Base
has_and_belongs_to_many :users
end
I have a Ability class and CanCan installed to handle roles. I have a role type groupleader and need to make sure a Group has only one groupleader...
I think its something like: Group has_one User.role :groupleader... but I know thats not it.
It doesn't make sense to me to have the role on the users table if you want it to determine what the user can do within the context of a group.
Where it would make sense is to have it on the memberships table for groups and users. Records in this table would then have three columns: user_id, group_id and role.
Then to retrieve the leader for the group you would execute a query like this:
group.users.where("memberships.role = 'leader'").first
Where group is a Group object, i.e. Group.first or Group.find(13).
This then leaves open the possibility that you can have more than one leader for a group further down the track if required.
If your roles are in a separate table, then you can do this:
group.users.where("memberships.role_id = ?", Role.find_by_name("leader").id).first

Instance method, named_scope or association extension

class User < ActiveRecord::Base
has_many :memberships
has_many :groups, :through => :memberships
class Group < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
def moderators
# relationship_id is in the memberships table
self.users.find(:all, :conditions => ['relationship_id = ?', 1])
end
end
Given the above code, is this the best way to implement the moderators method? My goal is to be able to find all the users with a "moderator" relationship within a given group. Right now I can use the method to iterate over all the moderators
# ...
#group.moderators
I considered an association extension which makes sense to use here because I'm asking for a subset of users that meet a condition. But the syntax seems redundant to ask for users that are moderators
# Association extension - seems redundant
#group.users.moderators
I considered a named_scope but I couldn't figure out how to implement it without errors. Even if I could the named_scope will return all the moderators across all the groups which isn't what I want.
# named_scope: returns all the moderators across all the groups
moderators = Group.moderators
I'm wondering what the best practice here is and why I might want to us an association extension (or named_scope) over the instance method given that it allows for a more concise syntax?
Add an association on Group class:
class Group < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
has_many :moderators, :source => :user, :through => :memberships,
:conditions => ['relationship_id = ?', 1]
end
Now you can do the following:
#group.moderators
#group.moderators.size
#group.moderators.find_by_city(..)

Linking Two Models Together in Ruby on Rails

I've been stuck on this all day. I have a setup like the one below. I'm trying to define friends using the group_memberships association.
class User < ActiveRecord::Base
has_many :group_memberships
has_many :groups, :through => :group_memberships
has_many :friends # what goes here? <<
end
class GroupMembership < ActiveRecord::Base
belongs_to :user
belongs_to :role
belongs_to :group
end
class Role < ActiveRecord::Base
has_many :group_memberships
end
class Group < ActiveRecord::Base
has_many :group_memberships
has_many :users, :through > :group_memberships
end
I'd like to do this without creating a join table for friends, unless it's completely crazy to do it without.
The group_membership table contains user_id and group_id linking one user to one group.
I'd trying to get
#user.friends
to return users with common group_memberships using the group_id.
has_many :friends, :through => :group_memberships, :source => :group
Nothing I've tried works, but I'll chalk that up to my complete misunderstanding of the above code.
Unfortunately Rails doesn't let you nest has_many's more than 2 deep.. Forgetting about naming it friends for a moment (let's call it users instead), this would theoretically be what you'd want:
has_many :group_memberships
has_many :groups, :through => :group_memberships
has_many :users, :through => groups
Except that this doesn't work. If you try it you'll see this not-so-helpful error message which comes from this bit of code, specifically source_reflection.options[:through].nil?. That is, the through isn't allowed to have a through itself.
Instead, you may want to do something like this:
Solution 1
class User < ActiveRecord::Base
has_many :group_memberships
has_many :groups, :through => :group_memberships
def friends
groups.with_users.map(&:users).flatten.uniq.reject{|u| u == self}
end
end
class Group < ActiveRecord::Base
has_many :group_memberships
has_many :users, :through => :group_memberships
named_scope :with_users, :include => :users
end
Solution 2
Use the nested_has_many_through plugin that Radar mentioned. It looks like at least one fork of it on github has been updated to work on the latest Rails.
Solution 3 (just for kicks)
or, just for kicks, you could do it with one big SQL query:
class User < ActiveRecord::Base
has_many :group_memberships
has_many :groups, :through => :group_memberships
def friends
sql = <<-SQL
SELECT users.* FROM users, (
SELECT DISTINCT gm2.user_id AS user_id
FROM group_memberships gm, groups g, group_memberships gm2
WHERE gm.user_id = ? AND g.id = gm.group_id AND gm2.group_id = g.id AND gm2.user_id != ?
) AS user_ids
WHERE users.id = user_ids.user_id
SQL
User.find_by_sql([sql, id, id])
end
end
Use the nested_has_many_through plugin.
delegate :users, :to => 'group'

Resources