Rails 4 has_many through many - ruby-on-rails

I'm stuck on this:
class Worker < ActiveRecord::Base
has_many :skills
has_many :jobs, through: :skills
..
end
class Skill < ActiveRecord::Base
belongs_to :worker
has_many :jobs
..
end
class Job < ActiveRecord::Base
has_many :skills
has_many :workers, through: :skills
..
end
What I'm trying to do is set up a many to many between Skill and Job inside of the `has_many' through relationship?
My question has three parts
Is this possible - using the has_many jobs rather than belongs_to jobs.
If it can be done and the code is wrong, how do I fix it?
How can I create Worker, Skill and Job records? (looking for syntax)
This is a picture (of sorts) of what I'm trying to do, hope it helps... :(

You're not giving active record enough information about your relationships. Every :has_many should have a corresponding :belongs_to so that active record knows which table holds the foreign key for each association. Notice that you only have one :belongs_to for three relationships. That smells.
As for fixing the problem, you have at least 2 options:
add :has_and_belongs_to_many associations
use explicit join tables
My preference is for the latter option. Being forced to name join tables often clarifies the nature of a relationship. On the flip side, I've found that :has_and_belongs_to_many is often too implicit and ends up making my designs more obscure.
Explicit join tables
You might setup your relationships like this (untested):
class Assignment < ActiveRecord::Base
belongs_to :worker
belongs_to :job
end
class Qualification < ActiveRecord::Base
belongs_to :worker
belongs_to :skill
end
class Worker < ActiveRecord::Base
has_many :qualifications
has_many :skills, through: :qualifications
has_many :assignments
has_many :jobs, through: :assignments
..
end
class Skill < ActiveRecord::Base
has_many :qualifications
has_many :workers, through: :qualifications
has_many :jobs
..
end
class Job < ActiveRecord::Base
has_many :skills
has_many :workers, through: :assignments
..
end
By making the relationships more explicit I think the model is clearer. It should be easier to troubleshoot from here.
EDIT:
If you need to do a traversal like Job.find(1).qualified_workers try making the following adjustment to the above model:
class Job
has_many :required_competencies
has_many :skills, through: :required_competencies
has_many :qualifications, through: :skills
has_many :qualified_workers, through: qualifications, class_name: :workers
end
class RequiredCompetency
belongs_to :job
belongs_to :skill
end
This is explicit about each traversal and names it. If you find these paths through your system are getting really long, I'd consider that a smell. There might be a more direct way to fetch your data or perhaps a better way to model it.

Related

Is this database relation schema correct?

I made my first project and got into problem that I couldn't get the right category_information values for specific competitions category through relations. So I started thinking that this could be the wrong schema for this task, so my question - is it actually wrong?
Current Scheme:
Assuming the following relationships between models from your image.
class Competition < ApplicationRecord
has_many :categories
has_many :informations
has_many :category_informations, through: :categories
end
class Category < ApplicationRecord
belongs_to :competetion
has_many :category_informations
has_many :information, through: :category_informations
end
class CategoryInformation
belongs_to :catagory
belongs_to :information
end
class Information < ApplicationRecord
belongs_to :competetion
has_many :category_informations
has_many :catagory, through: :category_information
end
Model can relates with one_to_many_to_many using :through option
It explains a association used to set up a many-to-many connection with another model.
you can get the category_informations from competition like
Competition.first.category_informations
It is all for doing! Pretty good, right?
And you could do get information from category too
Category.first.informations
Actually wrong schema doesn't exist, just there exists some wrong association description.
You can get more usage to use association from docs at 2.3 section and 4.3 section
Assuming the following relationships between tables,
A competition has_many categories,
A competition has_many information,
A category has_many information,
A category has_many competition,
An information has_many category
You can use has_many_through relationships
class Category < ApplicationRecord
has_many :category_competitions
has_many :competitions, through: :category_competition
has_many :category_informations
has_many :informations, through: :category_informations
end
class Information < ApplicationRecord
has_many :category_informations
has_many :categories, through: :category_informations
end
class Competition < ApplicationRecord
has_many :category_competition
has_many :categories, through: :category_competitions
end
class CategoryCompetition < ApplicationRecord
belongs_to :category
belongs_to :information
end
class CategoryInformation < ApplicationRecord
belongs_to :category
belongs_to :information
end
By this way you can access,Categories of a particular competition by #competition.categories
This article might be helpful for you to understand associations better
https://www.sitepoint.com/master-many-to-many-associations-with-activerecord/

usage of "has_many" vs "has_many, through" relation in rails

i'm new to both rails and web-dev.
currently i'm studding "active record Associations" in rails 4
and i got confused on usage of "has_many" vs "has_many, through" relation.
for example, if i have Physician, Appointment, and Patient model in my schema.(As rails guide provides)
and rails tutorial suggests me to do like this.
class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
end
class Patient < ApplicationRecord
has_many :appointments
has_many :physicians, through: :appointments
end
but what if i make relation like this
class Physician < ApplicationRecord
has_many :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
has_many :patients
end
class Patient < ApplicationRecord
belongs_to :appointment
end
i think both will work fine.
but i want to know whats the differences and why they made "has_many, through" relations.
thank you for reading my question.
has_many through is a way to join two unrelated, independent models/tables and to reduce duplicates/redundancy in tables, where has_many states more directive relation.
Maybe example with appointments and physicians isn't clear. I'll give a different one.
class Artist
has_many :paintings
has_many :purchases
has_many :buyers, through: :purchases
end
class Painting
belongs_to :artist
end
class Purchase
belongs_to :painting
belongs_to :buyer
end
class Buyer
has_many :paintings_buyers
has_many :painting, through: :purchases
end
Talking about your example.
First, there is no convenient way for you to get physician's patents. The only way is:
physician.appoitments.map(&:patient).uniq
Which will result in
poor performance
inability to filter entities with sql, only with ruby(again poor performance)
Also, did you notice I used uniq? That's because patient's table will have lots of duplicates when the same patients will be appointed multiple times to the same physician.

Specifying Conditions on Multiple Nested Eager Loaded Associations

I'm trying to query on ActiveRecord multiple nested eager loaded associations with conditions like so:
user.books.includes(slot: [room: :school]).where("books.slot.room.school.id = 1")
Obviously this query is wrong, but basically what I'm trying to reach is a relation of user.books for a certain school.
My model structure is:
class User < ActiveRecord::Base
has_many :books
has_many :slots, through: :books
has_many :rooms, through: :slots
has_many :schools
end
class Book < ActiveRecord::Base
belongs_to :user
belongs_to :slot
end
class Slot < ActiveRecord::Base
has_many :books
belongs_to :room
end
class Room < ActiveRecord::Base
belongs_to :school
has_many :slots
end
class School < ActiveRecord::Base
has_many :users
has_many :rooms
has_many :slots, through: :rooms
has_many :books, through: :slots
end
Any ideas? Thanks in advance.
includes eager loads association records, while joins does what you want to do.
This question has been asked here numerous times. Please make sure that you look and try to find a similar question here before you ask one.
So you want to change your code like this:
user.books.joins(slot: [room: :school]).where(schools: { id: 1 })

Rails: Create Model with multiple belongs_to

I searched for quite a long time and couldnt find that problem.
user.erb
has_many :workouts
has_many :result_units
workout.erb
belongs_to :user
has_many :sets
set.erb
belongs_to :workout
has_one :result_unit
result_unit.erb
belongs_to :user
belongs_to :set
1 possible Solution is that ResultUnit dont belong to User. But the question is then how much performance it will cost to query User.workouts.all.sets.all.resultunits.all
How could i create a new ResultUnit for User and Set?
This is a case for using a has_many :through association.
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Running User.workouts.all.sets.all.resultunits.all will result in numerous queries being executed. A has_many :through however, will execute only a single query and allow the database to optimize the joins between tables.
class User < ActiveRecord::Base
has_many :workouts
has_many :sets, through: :workouts
has_many :result_units, through: :sets
end
Ok, I didn't understand your problem 100%.. but I'm gonna have a stab at it and feel free to downvote if it's not right.
class User
has_many :workouts
has_many :result_units
has_many :sets, through: :workouts
# User.first.workouts
# User.first.result_units
# User.first.sets
end
class Workout
belongs_to :user
has_many :sets
# Workout.first.user
# Workout.first.sets
end
class ResultUnit
belongs_to :user
belongs_to :set
# ResultUnit.first.user
# ResultUnit.first.set
end
class Sets
belongs_to :workout
has_one :result_unit
# Set.first.workout
# Set.first.result_unit
end

Rails relationships setup for 5 table db

I'm stuck in a circle of indecision and need a shove to break free. I'm a noob with Rails and I'm attempting to translate a pre-existing database using Rails conventions. Basically, I currently have 5 models/tables: Workorders, Mileage_logs, Time_logs, Parts, & Equipment. A Workorder can have many Mileage_logs, Time_logs, and Parts, because each of them is shown on the Workorder's index page. But, that's the seemingly easy part...
I'm getting confused when the Equipment model is introduced because it seems like it's basically the same thing as the Workorder.
What is the best way to handle this relationship setup? Is this an appropriate use for the has_many :through convention? Or, is this best done with simply having the workorder_id and equipment_id in the Mileage_log, Time_log, and Part models and then:
class Part < ActiveRecord::Base
belongs_to :workorder
belongs_to :equipment
end
class Mileage_log < ActiveRecord::Base
belongs_to :workorder
belongs_to :equipment
end
class Time_log < ActiveRecord::Base
belongs_to :workorder
belongs_to :equipment
end
class Workorder < ActiveRecord::Base
has_many :Time_logs
has_many :Parts
has_many :Mileage_logs
end
class Equipment < ActiveRecord::Base
has_many :Time_logs
has_many :Parts
has_many :Mileage_logs
end
Or, is the has_many through: relationship what I should look into for the Workorder & Equipment models?
class Workorder < ActiveRecord::Base
has_many :parts
has_many :mileage_logs
has_many :time_logs
end
class Equipment < ActiveRecord::Base
has_many :parts, through: :workorder
has_many :mileage_logs, through: :workorder
has_many :time_logs, through: :workorder
has_many :workorders
end
Any help would be greatly appreciated!
Also, any general advice on the route setup would be welcomed as well.

Resources