The idea is that you can upgrade your bike by adding an accessory, and
the upgrade price is often less than the accessory price would normally
be. So the Upgrades table has id, bicycle_id, accessory_id, and price.
class Bicycle
has_many :upgrades
has_many :accessories, :through => :upgrades
end
class Upgrade
belongs_to :bicycle
belongs_to :accessory
# price defined in table
end
Now my question is, I need to query the upgrades for a bicycle for a
specific accessory.
Otherwise, if there are only upgrade accessories, you can bypass a step:
bike.accessories.find_by_description(“headlight”)
Though in terms of good design (no dependency chaining), it might be a good idea to add a method to one of the models to hide this away. Say, Updgrade#find_accessory_by_description
So if I am tracking with you here, you are looking for Accessories
associated with a Bicycle as joined by the Upgrades. You should be
able to just call bicycle.accessories.find(accessory) if you have an
accessory, since Accessories are now associated with the Bicycle object
via the has_many :though declaration. The has_many :through takes care
of the need to go to the Upgrades object first from Bicycles since you
specified the relationship in the model.
Almost but not quite - what I need is the Upgrade row, not the
Accessory row, because I need to know the price for the upgrade given
the desired accessory.
So bicycle.accessories.find_by_description("headlight") returns an
Accessory object, but I still don't know the upgrade price.
That's why this is a bit tricky - I want an upgrade row, selected by
the accessory description. Since the description is not in the join
table, it seems I have to do two lookups - one to find the accessory,
and the other to find the upgrade row given the accessory id (yuck).
first toss the price and the id columns from your through table. you
never need id and it might be screwing some thing up. the total order
price should be calculated at run time and the accessory price should be
in the accessories table.
I have a real join model here, not a simple habtm, because an upgrade
price is different from the normal accessory price. Sorry if I wasn't
clear about that.
(ID columns never "screw things up", btw).
def get_accessory(upgrade_type){
self.upgrades().each() do |up|
return up if up.description == "headlight"
end
}this should cut down your proccessing to as it eliminates a costly DB
query.(assuming there are not a huge amount of upgrades assigned to that
bike)
Actually, self.upgrades will result in a query against the database...
plus you've got another performance hit by iterating through the
objects (I would suggest a .detect here instead of .each, btw).
It sounds like your model might need abstraction needs some work, although
more information is needed to know what you are trying to accomplish. You
might need to sit down and rethink the relationships between the models and
what information should be in which table.
Why are you using an upgrades table? Are accessories available as
non-upgrades? If an accessory is accessed as an upgrade is the information
different than when as an accessory only? Is there a reason you don't want
to put the upgrade fields into your accessory model and bypass the has_many
:through association completely?