Rails - how to find out user's role in the system? - ruby-on-rails

I have following models:
class Role < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
end
class Assignment < ActiveRecord::Base
belongs_to :user
belongs_to :role
end
class User < ActiveRecord::Base
has_many :assignments
has_many :roles, :through => :assignments
...
end
I am trying to find out user's role, but when I try to
user.assignments.name
It doesn't print out the user's role from the table roles (column name).
How to print out that?

You need to map on your association in order to get a specific field:
user.roles.map(&:name)

Try this.
user.roles.each {|role| puts role }
You can't call name method on user.assignments because it's an array.

user.assignments.each do |a|
puts a.name
end

Related

Rails Rich Associations - undefined method error

I have three basic models that I am working with:
class User < ActiveRecord::Base
has_many :assignments
end
class Assignment < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
class Group < ActiveRecord::Base
has_many :assignments
end
Using this schema, I would assume the "Assignment" model is sort of the join table, which holds the information for which users belong to which groups. So, what I am trying to do is, using a User object, find out what groups they belong to.
In Rail console, I am doing the following:
me = User.find(1)
Which returns the user object, as it should. Then, I attempt to see which "groups" this user belongs to, which I thought it would go through the "Assignment" model. But, I'm obviously doing something wrong:
me.groups
Which returns:
NoMethodError: undefined method `groups' for #<User:0x007fd5d6320c68>
How would I go about finding out which "groups" the "me" object belongs to?
Thanks very much!
You have to declare the User - Groups relation in each model:
class User < ActiveRecord::Base
has_many :assignments
has_many :groups, through: :assignments
end
class Group < ActiveRecord::Base
has_many :assignments
has_many :users, through: :assignments
end
Also, I recommend you to set some validations on the Assignment model to make sure an Assignment always refers to a Group AND a User:
class Assignment < ActiveRecord::Base
belongs_to :group
belongs_to :user
validates :user_id, presence: true
validates :group_id, presence: true
end
class User < ActiveRecord::Base
has_many :assignments
has_many :groups, through: :assignments
end
class Assignment < ActiveRecord::Base
belongs_to :group
belongs_to :user
end
class Group < ActiveRecord::Base
has_many :assignments
has_many :users, through: :assignments
end
Please refer association basics
Your me is of type User not Assignment. You want to do:
me.assignments.first.groups
This will give you all the groups belonging to the user's first assignment. To get all the groups you could do as MrYoshiji has commented below:
me.assignments.map(&:groups)
You didn't define a has_many on groups. Try
me.assignments.first.group
should work.

How do you model "Likes" in rails?

I have 3 models: User, Object, Likes
Currently, I have the model: a user has many Objects. How do I go about modeling:
1) A user can like many objects
2) an Object can have many likes (from different users)
So I want to be able to do something like this:
User.likes = list of objects liked by a user
Objects.liked_by = list of Users liked by object
The model below is definitely wrong...
class User < ActiveRecord::Base
has_many :objects
has_many :objects, :through => :likes
end
class Likes < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Objects < ActiveRecord::Base
belongs_to :users
has_many :users, :through => :likes
end
To elaborate further on my comment to Brandon Tilley's answer, I would suggest the following:
class User < ActiveRecord::Base
# your original association
has_many :things
# the like associations
has_many :likes
has_many :liked_things, :through => :likes, :source => :thing
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :thing
end
class Thing < ActiveRecord::Base
# your original association
belongs_to :user
# the like associations
has_many :likes
has_many :liking_users, :through => :likes, :source => :user
end
You are close; to use a :through, relation, you first must set up the relationship you're going through:
class User < ActiveRecord::Base
has_many :likes
has_many :objects, :through => :likes
end
class Likes < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Objects < ActiveRecord::Base
has_many :likes
has_many :users, :through => :likes
end
Note that Objects should has_many :likes, so that the foreign key is in the right place. (Also, you should probably use the singular form Like and Object for your models.)
Here is a simple method to achieve this. Basically, you can create as many relationships as needed as long as you specify the proper class name using the :class_name option. However, it is not always a good idea, so make sure only one is used during any given request, to avoid additional queries.
class User < ActiveRecord::Base
has_many :likes, :include => :obj
has_many :objs
has_many :liked, :through => :likes, :class_name => 'Obj'
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :obj
end
class Obj < ActiveRecord::Base
belongs_to :user
has_many :likes, :include => :user
has_many :users, :through => :likes
# having both belongs to and has many for users may be confusing
# so it's better to use a different name
has_many :liked_by, :through => :likes, :class_name => 'User'
end
u = User.find(1)
u.objs # all objects created by u
u.liked # all objects liked by u
u.likes # all likes
u.likes.collect(&:obj) # all objects liked by u
o = Obj.find(1)
o.user # creator
o.users # users who liked o
o.liked_by # users who liked o. same as o.users
o.likes # all likes for o
o.likes.collect(&:user)
Models & associations as per naming conventions of rails modeling
class User < ActiveRecord::Base
has_many :likes
has_many :objects, :through => :likes
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Object < ActiveRecord::Base
belongs_to :user
has_many :likes
has_many :users, :through => :likes
end
Also, you can use of already built-in gems like acts-as-taggable-on to have same functionality without code :)

How to traverse multiple many to many associations in activerecord

I am building a authorization framework that will eventually use cancan at the code level. I am creating the model and associations and have things almost perfect, but I ran into a snag.
I have User, Roles and Rights with many to many join tables (user_roles and role_rights) and I have things setup so that you can do User.roles and User.roles.first.rights but I would like to be able to do User.rights
class User < ActiveRecord::Base
has_many :user_roles
has_many :roles, :through => :user_roles
end
class UserRole < ActiveRecord::Base
belongs_to :user
belongs_to :role
end
class Role < ActiveRecord::Base
has_many :user_roles
has_many :users, :through => :users_roles
has_many :role_rights
has_many :rights, :through => :role_rights
end
class RoleRight < ActiveRecord::Base
belongs_to :role
belongs_to :right
end
class Right < ActiveRecord::Base
has_many :role_rights
has_many :roles, :through => :role_rights
end
The following works:
User.roles
so does this:
User.roles.first.rights
but what I want to do is:
User.rights
but when I try, I get the follow error: NoMethodError: undefined method `rights'
I assume that I need to add something to the User model to let it transverse to the Right model but I can't figure out the associations.
I'm using Rails 2.3.4 and Ruby 1.8.7
Try something like this:
class User < ActiveRecord::Base
def self.rights
Right.joins(:roles => :user).all("users.id = ?", self.id)
end
end

Given the following User<>Project<>Permissions<>Roles Model, how to obtain a project's team members?

Given the following:
class User < AR::B
has_many :permissions
has_many :projects, :through => :permissions
end
class Project < AR::B
has_many :permissions
has_many :users, :through => :permissions
end
class Role < AR::B
has_many :permissions
end
class Permission < AR::B
belongs_to :user
belongs_to :project
belongs_to :role
end
I'm interested in creating a SCOPE in the project model (project.rb) that returns all the project's members (bassed on the permissions table <> users & role tables.
Desired output:
user.name, role.name
Here's my scope in the model, which isn't returning the desired
output:
class Project < ActiveRecord::Base
has_many :permissions
has_many :users, :through => :permissions
#Playing with Scopes
scope :teammembers,
Project.permissions.joins(:users, :roles)
end
trying to figure out how to get the output with ActiveRecord. Thanks
Class Project < AR:B
...
def members
User.joins(:permissions => :project).where(:permissions => {:projects => self})
end
...
Here, self can be replaced with some ID, or self.id if you want to change the :projects to :project_id

has_many :through default values

I have a need to design a system to track users memberships to groups with varying roles (currently three).
class Group < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
end
class Role < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :role
belongs_to :group
end
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, :through => :memberships
end
Ideally what I want is to simply set
#group.users << #user
and have the membership have the correct role. I can use :conditions to select data that has been manually inserted as such :
:conditions => ["memberships.role_id= ? ", Grouprole.find_by_name('user')]
But when creating the membership to the group the role_id is not being set.
Is there a way to do this as at present I have a somewhat repetitive piece of code for each user role in my Group model.
UPDATED
It should be noted what id ideally like to achieved is something similar to
#group.admins << #user
#group.moderators << #user
This would create the membership to the group and set the membership role (role_id ) appropriately.
You can always add triggers in your Membership model to handle assignments like this as they are created. For instance:
class Membership < ActiveRecord::Base
before_save :assign_default_role
protected
def assign_default_role
self.role = Role.find_by_name('user')
end
end
This is just an adaptation of your example.

Resources