has_many and belongs_to with join table - ruby-on-rails

I have Users and Trucks. I want the ability to say #truck.drivers << #users and #user.truck = #truck.
The solution is simple until I want the relationship to be stored in a join table.
# tables
:users
:id
:truck_drivers
:user_id
:truck_id
:truck
:id
I've gotten it to where I can say #truck.drivers << #user and #user.trucks << #truck, but I would like to limit a user to occupy one truck at a time, for my sanity.
Is it possible? A has_many/belongs_to with a join table? Or should I try a different approach? I'm not using a third model for the join table. It's just a table. Here's what I have so far.
class User < ApplicationRecord
has_and_belongs_to_many :trucks,
join_table: :truck_drivers, # points to the table
class_name: :Truck # looks for the truck model in the table
end
class Truck < ApplicationRecord
belongs_to :company
has_and_belongs_to_many :drivers,
join_table: :truck_drivers,
class_name: :User
end
The reason I need a join table in the first place is because each User can have many Roles: Admin, Manager, Driver, Customer Service, etc. I thought it didn't make sense to add a truck_id to all the users if all the users are not going to be using trucks.

It seems like you ought to be able to do something like:
#user.trucks << #truck unless #user.trucks.any?

Yes this is a standard strategy with rails using the :through keyword.
rails documentation: http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Make a model called TruckUser with truck_id and user_id
then edit your classes:
class User < ApplicationRecord
has_many :truck_users
has_many :trucks, through: :truck_users
end
class Truck < ApplicationRecord
belongs_to :company
has_many :truck_users
has_many :drivers, through: :truck_users
end
class TruckUser < ApplicationRecord
belongs_to :truck
belongs_to :user
end

Related

Rails Populate Existing Join Table

So I have two tables, a Customers table and a Companies table. I have also created an empty Employees table that I would like to use as a join table.
These are the associations I have: (I want customers to be associated with their respective company)
class Company < ApplicationRecord
has_many :employees
has_many :customers, :through => :employees
end
class Customer < ApplicationRecord
belongs_to :employees
end
class Employee < ApplicationRecord
belongs_to :customer
belongs_to :company
end
Where would be the best way to do this? In my Customer#new method in the controller? I read that I need to use <<, but I don't know how to approach that.
You need to use the concept of Inverse association here:
class Customer has_many :companies, :through => :employees
You could just try delegating the company call on customers to their employee:
customer.rb
delegate :company, to: :employee
Now whenever you ask a customer its company, it will ask its employee to handle it.

How to create a record when it depends on another record

I have 2 models, each of them depend on another.
class Company < ActiveRecord
belongs_to :user
end
class User < ActiveRecord
belongs_to :company
end
The company has a required user_id column.
The user has a required company_id column.
How can I create a company and user when they both depend on each other?
In your scenarion this relationship is called many to many relationship, You can create middle table between this called users_companies with foreign key of both table
For more details please refer this link Associations
Like example
class Company < ActiveRecord
has_many :users_companies, dependent: :destroy
has_many :users, through: users_companies
end
class User < ActiveRecord
has_many :users_companies, dependent: :destroy
has_many :companies, through: users_companies
end
class UsersCompany < ActiveRecord
belongs_to :user
belongs_to :company
# This model have two foreign key
user_id and company_id
end
Use a dummy value to fake one of the object is valid
company=Company.create(user_id: dummy)
user=User.new
user.company = company
user.save
company.update_attribute(user_id: user.id)

we find all contract of a user and all jobs of contract of that particular user

I have two models one is User and another is Contract.
These are my models
class User < ApplicationRecord
has_many :user_jobs ,dependent: :destroy
has_many :contracts ,through: :user_jobs
end
class Contract < ApplicationRecord
has_many :user_jobs ,dependent: :destroy
has_many :users ,through: :user_jobs
end
class UserJob < ApplicationRecord
belongs_to :user
belongs_to :contract
end
we have to find all unique contracts of a user
If you want only user's jobs then this will be perfect :
Contract.joins([:user_jobs=> [:user]]).where("users.id = ?",user_id).distinct
or directly
Contract.joins(:user_jobs).where("user_jobs.user_id = ?",user_id).distinct
To find all unique contracts of a user, you can make a LEFT OUTER JOIN using includes which would also help you to eager load the association:
Contract.includes(user_jobs: :user).where(user_jobs: {user_id: user_id}).uniq
You can make a join involving several tables. (contracts, user_jobs & users).
# user_id = 1
Contract.includes(:users).where(users: {id: user_id}).distinct
But I think is better to make a user query to avoid the 3 table join as follows
# user = User.find(1)
user.contracts.distinct
Hope it helps

Rails belongs_to and has_many foreign_key relationship

I need a little help... I have these relationships... Users belong to Department, a Department has a manager, Managers (Users) can have many managed departments.
I'm having one of those days and I can't for the life of me figure out what to put inside the User model to define the `has_many :managed_departments' part of the relationship.
Department
class Department < ActiveRecord::Base
has_many :users
belongs_to :manager, foreign_key: "manager_id", class_name: "User"
end
User
class User < ActiveRecord::Base
belongs_to :department
# has_many :managed_departments
end
This works: Department.last.manager which returns:
=> #<User id: 2, etc...
I'm having a mindblank on what to put in the User model.
Can anyone help?
You can use class_name option same like you used it in Department model
#user.rb
class User < ActiveRecord::Base
belongs_to :department
has_many :managed_departments, class_name: "Department", foreign_key: "manager_id"
end
You are not creating right association. You have many to many relation ship between user and department.
user has_many departments (Can manage multiple department)
department has_many users
As a database standard you should break many to many relationship and introduce a new intermediate table.
So your new table should be users_departments. In this table you can add column user is manager or not.
table should have column :
user_id , department_is, is_manager
class Department < ActiveRecord::Base
has_many :users, :through => :users_departments
end
class User < ActiveRecord::Base
has_many :departments, :through => :users_departments
end
class UsersDepartment < ActiveRecord::Base
belongs_to :user
belongs_to :department
end
Here you can find anything with association. and with simple scope you can find manager of department also.

Can someone help me with this association?

I'm trying setup a Rails app that will be something like a game. The app has Users, each of which have Pawns that they can create. A User can search other users and the Pawns that they created, and challenge another one if they like, using one of their own Pawns. The challenged user can then accept/decline the challenge.
Right now I can add/delete Pawns for a User fine, and my models look like this:
class User < ActiveRecord::Base
has_many :pawns, dependent: :destroy
and
class Pawn < ActiveRecord::Base
belongs_to :user
Now, if User1 wants to challenge a Pawn created by User2, he looks at User2's list of Pawns and clicks a "Challenge" button for the Pawn he wants. User1 then has to select one of his Pawns to use for the challenge and clicks save. Now User2 needs to either accept/decline the challenge.
I'm having a hard time wrapping my head around how the challenges should be setup. My thought is that each Pawn will have a self-referential many-to-many relationship, almost like a friendship relationship would be setup. However, I don't know if I should consider the challenge something related to the User or the Pawn.
Whats the best way to model something like this?
EDIT:
Here's a diagram of what I'm trying to accomplish. I definitley think I need some sort of association setup. Result would hold statistics of that Pawn for that Challenge (something like time_spent, clicks_made, etc.). Challenge would also have a column for winner or something similar.
Your challenge may have association defined for each type of pawn.
class Challenge < ActiveRecord::Base
# attributes :challengee_id, :challenger_id
belongs_to :challengee, class_name: "Pawn"
belongs_to :challenger, class_name: "Pawn"
has_many :results
end
Pawns will have associations for each type of challenge.
class Pawn < ActiveRecord::Base
# attributes :user_id
belongs_to :user
has_many :results
has_many :initiated_challenges, class_name: "Challenge", foreign_key: :challenger_id
has_many :received_challenges, class_name: "Challenge", foreign_key: :challengee_id
end
It's probably ok to denormalize challenge_id for the result records.
class Result < ActiveRecord::Base
# attributes: pawn_id, challenge_id, :result
belongs_to :pawn
belongs_to :challenge
end
Your user can have associations to pawns and to challenges through pawns. A simple way to get both challenge types associated with a user would be to combine the results of the two challenge associations (initiated and received) into one method #challenge.
class User < ActiveRecord::Base
has_many :pawns
has_many :initiated_challenges, through: :pawns, source: :initiated_challenges
has_many :received_challenges, through: :pawns, source: :received_challenges
def challenges
initiated_challenges + received_challenges
end
end
Performance optimizations for this method could include denormalizing the user_ids on to Challenge as :challengee_user_id and :challenger_user_id... or caching a list of challenge ids on the user so you make one query instead of two.
You can set up another table called Challenges with fields challenger_id, challengee_id, status. The challenger and challengee ids would represent the pawns of course, not the user. The status would represent challenge_pending, challenge_on_going, there are other ways to do this obviously, but this one one.
This has the added benefit of allowing you to restrict pawn-to-pawn challenges to one each very easily if that's your desired behavior, among other things.
In your view controller
#challenges = Challenge.where("challengee_id IN (?)", Pawn.find_all_by_owner_id(current_user.id).map{|u| u[:id]})
#challenged = Challenge.where("challenger_id IN (?)", Pawn.find_all_by_owner_id(current_user.id).map{|u| u[:id]})
In your view
<%= #challenges.each do |challenge| %>
whatever
<% end %>
class User < ActiveRecord::Base
has_many :pawns
end
class Pawn < ActiveRecord::Base
belongs_to :user
has_many :challengers, class_name: 'Challenge'
has_many :challengees, class_name: 'Challenge'
belongs_to :result
end
class Challenge < ActiveRecord::Base
belongs_to :challenger, class_name: 'Pawn'
belongs_to :challengee, class_name: 'Pawn'
belongs_to :result
end
class Result < ActiveRecord::Base
has_one :challenge
has_one :winner, class_name: 'Pawn'
end

Resources