I have 2 model associated with module ProjectsUsersRole:
Users can join more than 1 Projects, Project have lots of users, and user join the project with a role saying "admin" or "member":
class User < ActiveRecord::Base
has_many :projects_users_role
has_many :projects, :through => :projects_users_role
end
class Project < ActiveRecord::Base
has_many :projects_users_role
has_many :users, :through => :projects_users_role
end
class ProjectsUsersRole < ActiveRecord::Base
belongs_to :user
belongs_to :project
attr_accessible :role, :user, :project
end
I can get the project of current user:
#projects = current_user.projects
But how to get all the users in the projects with role?
#projects.each do |project|
project.projects_users_role.each do |r|
debug r.role
end
end
Related
My Models:
class Vip < ActiveRecord::Base
belongs_to :organization
has_many :events
has_many :organizations, :through => :events
end
class Organization < ActiveRecord::Base
belongs_to :user
has_many :events
has_many :vips, :through => :events
end
class Event < ActiveRecord::Base
belongs_to :organization
belongs_to :vip
end
My vips Controller:
def create
#organization = Organization.find(params[:organization_id])
#vip = #organization.vips.build(vip_params)
if #vip.save
redirect_to organization_path(#organization)
else
render 'new'
end
end
def vip_params
params.require(:vip).permit(:name, :about, :organization_id)
end
Before I started using the has_many :through associations, the build method would automatically add the foreign key to the new vip. So my vips table would have the organization_id column populated. Since using the has_many associations, the organization_id column is being left NULL on 'vip#create'.
Is there a reason that build wouldn't work the same way anymore with my new associations?
In my Rails app I have Users and Forms.
class User < ActiveRecord::Base
has_many :admin_roles
#desired association below
#has_many :forms, through: :admin_roles
end
class Form < ActiveRecord::Base
has_one :department
end
The Users need to administrate the Forms through any level of an Organization.
class AdminRole < ActiveRecord::Base
belongs_to :organization
belongs_to :user
end
If assigned to a non-department organization the forms they have control over should come through the child departments.
The Forms are assigned to a departmental level only.
My model for the Organization is an STI model of 3 levels: market>subdomain>department
class Organization < ActiveRecord::Base
self.inheritance_column = :org_level
has_many :admin_roles
end
class Department < Organization
belongs_to :sub_domain, primary_key: :id, foreign_key: :parent_id
has_many :forms
end
class SubDomain < Organization
belongs_to :market, primary_key: :id, foreign_key: :parent_id
has_many :departments
end
class Market < Organization
has_many :sub_domains
end
The desired capability is to do user.forms and get all the associated forms back.
For example: Given there was a hierarchy of FooMarket>BarDomain>LoremDepartment
and a Form associated to LoremDepartment.
If a User is then tied to any of those 3 Organizations through the AdminRole it would allow for the return of the LoremDepartment Form.
Do you have to necessarily do it with associations ? u can always define an instance method in user model and back track it to forms.
But before that, just a reminder, you have to mention the foreign key in both the models for the association to work both ways.
class User < ActiveRecord::Base
attr_accessible :name
has_many :admin_roles
has_many :organizations, :through => :admin_roles
def forms
organizations.map(&:forms).flatten.uniq
end
end
class Department < Organization
belongs_to :sub_domain, primary_key: :id, foreign_key: :parent_id
has_many :forms, :foreign_key => :organization_id
end
class SubDomain < Organization
belongs_to :market, primary_key: :id, foreign_key: :parent_id
has_many :departments, foreign_key: :parent_id
def forms
departments.map(&:forms).flatten
end
end
class Market < Organization
has_many :sub_domains, foreign_key: :parent_id
def forms
sub_domains.map(&:forms).flatten
end
end
I tested this and it does work. But kinda round about.
How should I create following model in Rails 3.2? Project can have 1+ owners and 1+ users. Both of them are instances of class Person. I've thought about has_and_belongs_to_many but I don't know how to handle two separate collections of Persons for each Project.
You'll need a join model to represent each has-and-belongs-to-many relationship, and you would access using has-many-through as described here:
class ProjectOwnerLink < ActiveRecord::Base
belongs_to :project
belongs_to :owner, class_name: 'Person'
end
class ProjectUserLink < ActiveRecord::Base
belongs_to :project
belongs_to :user, class_name: 'Person'
end
class Project < ActiveRecord::Base
has_many :project_owner_links
has_many :owners, :through => :project_owner_links
has_many :project_user_links
has_many :users, :through => :project_user_links
end
class Person < ActiveRecord::Base
has_many :project_owner_links
has_many :owned_projects, :through => :project_owner_links, :source => :project
has_many :project_user_links
has_many :used_projects, :through => :project_user_links, :source => :project
end
You could define another model Participation that holds the type of the relationship, i.e. the role of the user. (Untested) code:
class Project < ActiveRecord::Base
has_many :participations
has_many :users, :through => :participations
def with_role(role)
includes(:participations).where('participation.role = ?', role)
end
def owners
users.with_role('owner')
end
def participants
users.with_role('participant')
end
end
class User < ActiveRecord::Base
has_many :participations
has_many :projects, :through => :participations
def with_role(role)
includes(:participations).where('participation.role = ?', role)
end
def projects_owned
projects.with_role('owner')
end
def projects_participating_in
projects.with_role('participant')
end
end
class Participation < ActiveRecord::Base
# has an attribute 'role'
belongs_to :project
belongs_to :user
end
Below is the demo application.
https://github.com/diatmpravin/habtm-demo.git
Please have a look, Let me know if you have any question?
In my app I have a page which render all the projects in the database. What I want is to be able to filter the results, for example by showing only the once in which the user is a member.
Below is from my projects controller, where I want to do exactly that (show only projects where the user is a member). What do is to first get all the projects from 'ProjectUser' where the user_id is found. Then I want to use this array to retrieve all the relevant projects from the table 'Projects', with the use of #user_is_member.project_id.
This does not work because it only give me ONE project, not all.
How can I change the code so I accomplish what I want?
The code:
#user_is_member = ProjectsUser.where(:user_id => current_user.id)
#user_is_member.each do |member|
#projects = Project.where(:id => member.project_id)
end
Tables:
projects_users:
project_id
user_id
projects:
id
...non relevant fields...
Models:
User model:
class User < ActiveRecord::Base
has_many :project_users
has_and_belongs_to_many :projects
end
Project model:
class Project < ActiveRecord::Base
has_and_belongs_to_many :users # => , :class_name => 'User'
belongs_to :user
end
ProjectUser model:
class ProjectsUser < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
Note: current_user is the currently logged in user (which has access to all the user fields, e.g "id")
This is not a good way to associate the models. If you want to associate user to project and make one user to admin/creator then you should associate your models as:
User
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password
has_secure_password
has_many :projects_users
has_many :projects, :through => :projects_users
end
Project
class Project < ActiveRecord::Base
has_many :projects_users
has_many :users, :through => :projects_users
end
ProjectsUser
class ProjectsUser < ActiveRecord::Base
attr_accessible :role
belongs_to :user
belongs_to :project
end
I have added an extra column/attribute to your ProjectsUser Model that will have a string value (admin/member). And now you can get the members for a project by doing #project.users.where(:role => 'member') and admin by #project.users.where(:role => 'admin').first.
If you don't want to change your way then in your controller do something like:
#user_is_member = ProjectsUser.where(:user_id => current_user.id)
project_ids = []
#user_is_member.each do |member|
project_ids << member.project_id
end
#projects = Project.where(:id => project_ids)
If you want all the projects for the current_user, you can just do:
#projects = current_user.projects
I am assuming you have something like:
class User < ActiveRecord::Base
has_many :project_users
has_many :projects, :through => :project_users
end
class ProjectUser < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
class Project < ActiveRecord::Base
has_many :project_users
has_many :users, :through => :project_users
end
The problem is that you have no project_id for some user which is somehow deleted.
Check your database that which project_id is nil by putting puts like statements in a loop.
Alternatively, you can use :dependent => :destroy on your relationship to get rid of such inconsistent data. It usually happens while you are testing and somehow delete any record but forget to delete the foreign key association relation for other table.
This can be accomplished like following:
#user_is_member = ProjectsUser.where(:user_id => current_user.id)
#user_is_member.each do |member|
puts "Checking the project id existence for each user member"+member.project_id.to_s
end
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