I have question regarding associations in Ruby on Rails. In the application there are projects, users, roles and groups. The project belongs to a group with users, a user can belong to many different groups but can only have one specific role within that group. For example:
In one group the user is the project owner, but in another group he is a writer.
What is the best way to implement this using the built in functions in Rails?
Thanks
Here is a very quick set of models that should fulfill your requirements:
class User < ActiveRecord::Base
has_many :group_memberships
has_many :groups, :through => :group_memberships
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
Basically there is a join table that has a user, group and role id in it. I'll leave the migrations as an exercise for the questioner
Related
I'm having trouble trying to understand/wrap my brain around this. I'm trying to create a relationship that allows this:
User has_many Groups
Item has_many Groups
Groups has_many User
Groups has_many Items
So I think I need a Join-Table here but belongs this table to three models or do I need two Join-Tables?
class Group < ActiveRecord::Base
has_many :users
has_many :items
end
class User < ActiveRecord::Base
has_and_belongs_to_many :groups
end
class Item < ActiveRecord::Base
has_and_belongs_to_many :groups
end
So what is the right migration here for my Group model?
These are two separate many-to-many associations. Each many-to-many to many association requires a join table.
For has_and_belongs_to_many you can generate the migrations with:
$ rails g migration CreateJoinTableGroupsUsers group user
$ rails g migration CreateJoinTableGroupsItems group item
However has_and_belongs_to_many is very limited and has_many through: is usually a better option.
One example of the limits of has_and_belongs_to_many is that you can't add any additional columns on the join table (metadata) and you can't query the join table directly. So you're skrewed if you want to keep track of stuff like when a user joined a group or who added an item to a group.
$ rails g model Membership user:belongs_to group:belongs_to
$ rails g model GroupItem group:belongs_to item:belongs_to
class User < ApplicationRecord
has_many :memberships
has_many :groups, through: :memberships
end
class Group < ApplicationRecord
has_many :memberships
has_many :group_items
has_many :users, through: :memberships
has_many :items, through: :group_items
end
class Membership < ApplicationRecord
belongs_to :user
belongs_to :group
end
class Item < ApplicationRecord
has_many :group_items
has_many :groups, though: :group_items
end
class GroupItem < ApplicationRecord
belongs_to :user
belongs_to :item
end
I'm still learning how to use has_many and has_many through relationships effectly. I am currently building a system where I would like users to be able to access certain maps that they are added to.
The map model is what I need the user to be able to access if they are apart of a certain group.
class Map < ApplicationRecord
has_many :rows
has_many :mapgroups
has_many :groups, through: :mapgroups
end
Since a user can belong to many groups I have a has_many through relationship
class Usergroup < ApplicationRecord
belongs_to :user
belongs_to :group
end
class User < ApplicationRecord
has_many :usergroups
has_many :groups, through: :usergroups
end
class Group < ApplicationRecord
has_many :usergroups
has_many :users, through: :usergroups
has_many :mapgroups
has_many :maps, through: :mapgroups
end
I thought about making a mapgroup model to take care of this but, so far, I am not so sure this is going to work.
class Mapgroup < ApplicationRecord
belongs_to :map
belongs_to :group
end
I am looking for a method to check to see what groups the user is apart of and then, based on those groups, give the user access to the corresponding maps. Am I on the right track with the relationships? How could I do this?
If you want to use MapGroup model only for keeping users an map connected (ModelGroup has only foreign keys on Group and Map) it's not the best approach. In this case it's better to opt for has_and_belongs_to_many assosiation. It will let you to assosiate Groups and Maps without creating useless model.
A has_and_belongs_to_many association creates a direct many-to-many connection with another model, with no intervening model.
class Group < ApplicationRecord
...
has_and_belongs_to_many :maps
end
class Map < ApplicationRecord
...
has_and_belongs_to_many :groups
end
I am confused on how to go about approaching this. I am connecting users and groups through the membership model, but I also want users to be able to create new groups. Clearly a group must then belong to a user, but the groups also belong to users through the memberships table.
I have this in my user.rb file, but I feel it is wrong. Do I remove the first one and just have the through one? How do I work in the creator of the group in that case?
class User < ApplicationRecord
has_many :groups
has_many :groups, through: :memberships
end
In other words, the user is a member of many groups, but also the creator of many groups. The memberships table only has two columns (group id and user id). The user id in this column is used to store users who are members of that group. I am stuck on what to do about the user who created the group.
You should have two relationships between Groups and Users. One reflecting the fact that a user created a group, and one that a user belongs to a group. You can reflect this idea by configuring the naming of your relationships. You will have to add a user_id field to your Groups table as well.
class User < ApplicationRecord
has_many :created_groups, class_name: "Group"
has_many :memberships
has_many :groups, through: :memberships
end
class Group < ApplicationRecord
belongs_to :creator, class_name: "User"
has_many :memberships
has_many :subscribers, through: :memberships, source: :user
end
class Membership < ApplicationRecord
belongs_to :user
belongs_to :group
end
I have table:
Groups
and table
Library
Now, I would like to make association, that I can set which Library records can Groups records see (basicaly a checkbox). So that If user belongs to a Group, he doesn't see certain Library records.
One suggestion before you start - don't use Group as an ActiveRecord class name as it will override certain functionality that already uses that term by convention. For now, I'll assume you are using Group.
If a Library can belong to only one Group, you need a simple has_many-belongs_to association setup:
class Group < ActiveRecord::Base
has_many :users
has_many :libraries
end
class Library < ActiveRecord::Base
belongs_to :group
end
class User < ActiveRecord::Base
belongs_to :group
has_many :libraries, :through => :group
end
If Library can belong to several Groups, you'll need a join table (and ideally a join model) to set this up:
class Group < ActiveRecord::Base
has_many :users
has_many :group_libraries
has_many :libraries, :through => :group_libraries
end
class GroupLibrary < ActiveRecord::Base
belongs_to :group
belongs_to :library
end
class Library < ActiveRecord::Base
has_many :group_libraries
has_many :groups, :through => :group_libraries
end
class User < ActiveRecord::Base
belongs_to :group
has_many :libraries, :through => :group
end
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