Reputation: 5896
So I have a table structure below:
Plane
Seating
PlaneSeating
PlaneSeatingNote
Note
This gives me a third-normal DB, but I need to set the model relations up.
I currently have:
class Plane < ActiveRecord::Base
has_many :plane_seatings, dependent: :destroy
has_many :seatings, through: :plane_seatings
end
class Seatings < ActiveRecord::Base
has_many :plane_seatings, dependent: :destroy
has_many :planes, through: :plane_seatings
end
class PlaneSeating < ActiveRecord::Base
belongs_to :plane
belongs_to :seating
has_many :plane_seating_notes, dependent: :destroy
has_many :notes, through: :plane_seating_notes
end
class PlaneSeatingNote < ActiveRecord::Base
belongs_to :plane_seating
has_one :note
end
class Note < ActiveRecord::Base
end
Now, this will give me the ability to say Plane.all.first.plan_seatings.first.notes
and get the notes I believe. However, I'd like to be able to say Plane.all.first.seatings.notes
and get the notes associated with that plane given that seating.
My thought is there should be a way to say, in Plane:
has_many :seatings, through: plane_seating, has_many :notes, through: plane_seating
or some other chaining magic to get a seating with some notes that only apply to that plane and seating combo. a :with, if you will. But I can't think of any syntax that would give me that. Anyone know?
Upvotes: 2
Views: 1442
Reputation: 5896
I used a helper method in the Plane model to get what I wanted. This method may be inefficient if you are dealing with large datasets, but for my datasets, it works fine. It packages up each seating subset for each plane with the notes associated with it into a hash.
#Get an easy to read hash of the seatings with their notes
def seatings_with_notes
@seatings_with_notes = []
self.plane_seatings.each do |item|
seating = Seating.where(id: item.product_application_id).first
notes = item.notes
combo = {seating:seating, notes:notes}
@seatings_with_notes.append(combo)
end
return @seatings_with_notes
end
Upvotes: 0
Reputation: 6981
The best is to pivot it the other way, it you want to grab the notes for a certain Plane:
Note.joins(plane_seating_note: [:plane_seating]).where(plane_seating_note: {plane_seating: {plane_id: 1})
You could make that a scope if you're using it in multiple places and if you want it on the Plane model:
class Plane < ActiveRecord::Base
has_many :plane_seatings, dependent: :destroy
has_many :seatings, through: :plane_seatings
def notes
@notes ||= Note.for_plane_id id
end
end
class Note < ActiveRecord::Base
has_many :plane_seating_notes
scope :for_plane_id ->(plane_id) { joins(plane_seating_notes: [:plane_seating]).where(plane_seating_notes: {plane_seating: {plane_id: plane_id}) }
end
For a specific seat on a specific plane, you'd typically see something like this in a controller:
@seat = PlaneSeat.find params[:id]
@plane = @seat.plane
@notes = Note.joins(:plane_seating_notes).where(plane_seating_notes: {plane_seating_id: @seat.id})
But since you have a HMT you could just do
@seat = PlaneSeat.find params[:id]
@plane = @seat.plane
@notes = @seat.notes
A couple "Rails-way" notes:
Upvotes: 2