I have 3 models, User, Division and Staff. Staff belongs to User & Division respectively and stored a value called role. There are currently 2 roles which are "1" and "2". Below is my relationship.
User:
class User < ActiveRecord::Base
has_many :staffs, :dependent => :destroy
# manager view
has_many :manage_divisions, -> { where staffs: { role: 1 } }, :through => :staffs, :source => :division
has_many :manage_division_staffs, :through => :manage_divisions, :source => :staffs
# staff view
has_many :work_for_divisions, -> { where staffs: { role: 2 } }, :through => :staffs, :source => :division
has_many :work_for_division_staffs, :through => :work_for_divisions, :source => :staffs
end
I want to get the divisions which the user manage through the staff table by User.manage_divisions. Then get the staff list of those divisions by User.manage_division_staffs. But now when I call User.manage_division_staffs, what return seems the staffs with role = 1 of the divisions(but not all staffs). Also I want to do something similar for User.work_for_divisions.
Below is the sql query generated when I called User.manage_division_staffs:
SELECT "staffs".*
FROM "staffs"
INNER JOIN "divisions" ON "staffs"."division_id" = "divisions"."id"
INNER JOIN "staffs" "staffs_manage_division_staffs_join" ON "divisions"."id" = "staffs_manage_division_staffs_join"."division_id"
WHERE "staffs"."role" = 1
AND "staffs_manage_division_staffs_join"."user_id" = ? [["user_id", 3]]
I know what I am doing wrong but I don't know the way to correct it. Any ideas??
Related
I have tow tables:
User:
user_id
user_blogs:
user_id | blog_id
blogs:
blog_id | source | identifier
Comments:
source | identifier | Field3
I want to be able to select all comments in the blogs that a user owns.
My models are related:
class User < ActiveRecord::Base
has_many :user_blogs
has_many :blogs, trhough: :user_blogs
end
class blogs < ActiveRecord::Base
has_many :comments,
:foreign_key => :source,
:primary_key => :source,
:conditions => Proc.new {
{:identifier=> self.identifier}
}
end
Right now I can retrieve all user comments using this:
User.first.blogs.map{|b| b.comments}
But this creates one query for each blog.
Is there a way to do this in one single step?
class User < ActiveRecord::Base
has_many :user_blogs
has_many :blogs, through: :user_blogs
has_many :comments, through: :blogs
end
class Blog < ActiveRecord::Base
has_many :comments, -> { where(identifier: identifier) }, foreign_key : source, primary_key: source
end
User.find(ID).comments
Yes, you need to use Rails eager_loading feature.
u = User.includes(blogs: :comments)
# now you can do
u.first.blogs.map { |b| b.comments }
Or, you can modify your model association definition also :
class User < ActiveRecord::Base
has_many :user_blogs
has_many :blogs, -> { includes(:comments) }, through: :user_blogs
end
Now, you can do the below without hitting multiple queries for each blog.
User.first.blogs.map { |b| b.comments }
I have four models, User, Team, Idea and Member. Member is join table between Team and User. I want users to be able to visits each others profile pages (controller: :users, action: :show), in the show view I want to list Ideas that belongs to teams that both users are members of. I've created a related question for listing the correct teams here.
Here is what I have now:
def show
#user = User.find(params[:id])
# Only list teams that both users are members of
#teams = #user.teams.find(#user.members.pluck(:team_id) & current_user.members.pluck(:team_id))
# What should I do to list ideas that are created for teams the both users are members of?
#ideas = #user.ideas.search(params[:search], conditions: { 'how should the condition look?' } :page => params[:page], :per_page => 10, :order => 'created_at DESC')
end
My models is set up like this:
have two models, User and Team, it's a many-to-many with a join table called Member. It's set ut like this:
#Team:
has_many :members, dependent: :destroy
has_many :users, through: :members
#User
has_many :members
has_many :teams, through: :members
#Member
belongs_to :user
belongs_to :team
#Idea
belongs_to :user
belongs_to :team
Any ideas on what I should do?
You'll want the following attribute in your Idea index (if you haven't already):
has team_id
And then the following should do the trick (given the existing context of your controller):
#ideas = Idea.search params[:search],
:with => {:team_id => #teams.collect(&:id)},
:page => params[:page],
:per_page => 10,
:order => 'created_at DESC'
You do not want to direct the idea search through #user.ideas - that will limit it to only ideas attached to #user and their corresponding teams, not current_user's teams.
Description
I have four models:
User
Organization
Role
OrganisationUserRole
The idea is that one user can belong to many organizations and can have many roles, but just one per organization.
My models look like this:
user.rb
class User < ActiveRecord::Base
has_many :roles, :through => :organization_user_roles
has_many :organizations, :through => :organization_user_roles
has_many :organization_user_roles
end
organization.rb
class OrganizationUserRole < ActiveRecord::Base
has_many :organization_user_roles
has_many :users, :through => :organization_user_roles
has_many :roles, :through => :organization_user_roles
end
role.rb
class Role < ActiveRecord::Base
end
organization_user_role.rb
class OrganizationUserRole < ActiveRecord::Base
belongs_to :user
belongs_to :organization
belongs_to :role
end
I am seeding my db with following seeds.rb
require 'faker'
# seed with standard roles
role_list = [
[ "superadmin" ],
[ "admin" ],
[ "user" ],
[ "owner" ],
]
role_list.each do |role|
Role.create( :name => role[0] )
end
# create default superadmin & organization
p = User.create(email: 'thomas#aquarterit.com', password: 'password')
o = Organization.create(name: 'A Quarter IT', website: 'www.aquarterit.com')
o.users << User.find_by_email('thomas#aquarterit.com')
p.roles << Role.find_by_name("superadmin")
# 30 organizations, 3 users each
30.times do |organization|
o = Organization.create(name: Faker::Company.name, website: Faker::Internet.domain_name)
3.times do |user|
p = User.create(email: Faker::Internet.email, password: 'password')
p.roles << Role.find_by_name("user")
o.users << User.last
end
end
Problem
Migrations and rake db:seed run successfully, but afterwards the table
organization_user_roles
contains duplicate rows per user:
Row 1: User_id 1 -> Organization_id 1
Row 2: User_id 1 -> Role_id 1
How can I associate the user, organization and role at the same time in one row?
Thanks a lot in advance, you guys are are always an amazing help!
you need to add a database unique key for the three params, something like
add_index "organization_user_roles", ["user_id", "organization_id", "role_id"], name: "unique_roles", unique: true, using: :btree
then in your organization_user_role model
validates_uniqueness_of :role_id, scope: [:user_id, :organization_id]
i did a similar app with unique columns in my db and this solution worked
You need has_many through with 3 tables, look on this link:
Rails 3 has_many through with 3 tables
I ended up following the instructions here:
How to join mutli-role, multi organisation tables in Rails
And it worked like a charm.
i have a user model with fields name and sex. And user can have an one-to-one association called "spouse" with another user, the association must be between a male user and a female user.
with the help of railscasts self-referential-association i create the basic association like this,
class User < ActiveRecord::Base
has_one :spouse_list
has_one :spouse, :through => :spouse_list
has_one :inverse_spouse_list, :class_name => "SpouseList", :foreign_key => "spouse_id"
has_one :inverse_spouse, :through => :inverse_spouse_list, :source => :user
end
class SpouseList < ActiveRecord::Base
belongs_to :spouse, :class_name => "User"
belongs_to :user
end
SpouseList has fields :spouse_id, :user_id,
above association can create many rows for single user and shows the first row if access spouse by #user.spouse_list.spouse.name
How can i restrict between a male user and a female user?
finally i made one-to-one self association for the below condition,
"User can have an one-to-one association called "spouse" with another user, the association must be between a male user and a female user"
added a field spouse_id to user model and created a self association with custom validation,
class User < ActiveRecord::Base
belongs_to :spouse, :class_name => 'User', :inverse_of => :base_user, :foreign_key => "spouse_id"
has_one :base_user, :class_name => 'User', :inverse_of => :spouse
validate :validate_spouse_gender
private
def validate_spouse_gender
errors.add(:spouse_id, 'could not be with same sex') if spouse && spouse.sex == sex
end
end
Now a male user A can only make association as spouse with another user B, if B is of gender female.
hope it helps someone.
I have the following association in my Group model:
has_many :subscriptions, :order => 'subscriptions.expiration_date DESC', :group => 'subscriptions.product_name', :conditions => ['subscriptions.status IN (?)', [:active, :canceled]]
The Models (User, Subscription, Group) break down like this:
**User**
has_many :groups, :before_add => :validates_group, :through => :group_users, :conditions => ["groups_users.status = ?", 'active']
**Group**
has_many :users, :through => :group_users, :conditions => ['groups_users.status = ?', 'active']
has_many :subscriptions, :order => 'subscriptions.expiration_date DESC', :group => 'subscriptions.product_name', :conditions => ['subscriptions.status IN (?)', [:active, :canceled]]
**Subscription**
belongs_to :group
So, a group could have multiple subscriptions (for different products; subscription.product_name) for the same product (depending on if they renewed or it was just an old one in the system). The has_many :subscriptions order_by is not working properly.
For Example:
If the user has 3 subscriptions (One for product X and 2 for product Y). And you run the following
Subscriptions Method in User Model:
def subscriptions
subs = []
groups.collect(&:subscriptions).each do |sub|
if sub
subs << sub
end
end
subs.flatten!
end
u = User.last
u.subscriptions
The one for product X comes back fine, but when it pulls back product Y it is pulling back the first one in the list (the one with the expiration date in the past).
Sorry if this doesn't make sense, I am trying to explain it the best I can. Anyone run into this situation where order and group are not working properly on an association?