Reputation: 5105
I have the following models set up:
class Sound < ActiveRecord::Base
has_many :tenders, :as => :tenderable
belongs_to :event
end
class Stage < ActiveRecord::Base
has_many :tenders, :as => :tenderable
belongs_to :event
end
class Tender < ActiveRecord::Base
attr_accessible :event_id, :user_id, :estimate, :tenderable_id, :tenderable_type
belongs_to :tenderable, :polymorphic => :true
end
class Event < ActiveRecord::Base
attr_accessible :name
has_one :stage
has_one :sound
accepts_nested_attributes_for :stage, :allow_destroy => true
accepts_nested_attributes_for :sound, :allow_destroy => true
end
Each Event a variety of Tenderable's attached to it (eg. stage, sound), I can access these through Event.find(id).tenderables, but I need to work out which 'opportunities' are available regardless of the Event they're attached to.
At the moment I don't have a model for 'Opportunity' as I'm trying to keep things simple.
Really what I want to do is something like Tenderables.all which will return all the 'Sounds', 'Stages' and anything else I define as 'tenderable'.
What's the best way to achieve this?
Thanks ;)
Upvotes: 2
Views: 1357
Reputation: 1057
The accepted answer is correct, but inefficient.
Tender.distinct.pluck(:tendable_type)
This does more work in the database, and doesn't require each unique object to be instantiated in order to call a method on it.
Tender.where.not(tendable: nil).includes(:tendable).map(&:tendable)
This eager loads the association data all at once, instead of every time the loop runs. This will still load every record into memory, but it may be significantly more performant depending on the number of records you have. The accepted answer will hit the database on every Tender.
Upvotes: 0
Reputation: 50057
Afaik the list of all Tenderables
, in the meaning of things that could have a Tender
attached to it, is not possible to build from the database or model structure. In the database you would be able to find all Tenderable
that have a Tender
attached to it, but not in an easy way (think union of queries for each tenderable_type
).
But the primary property of a polymorphic relation is actually that any kind of object could be attached to it, so you will have to manage the complete list of objects that could have a tender yourself.
I am not complete sure why you would want that, but you must do a union of Sound.all
and Stage.all
and whatever table will become tenderable later.
Now when writing this, I am thinking: to be able to do a union, those tables have to be pretty similar. If they are, in your case, you might need to introduce the Tenderable
object for real, and use STI. For what you want right now that would be the best solution.
Whatever is Tenderable
has to fit in a single table, with a type (Sound, Stage, ...) and then you get a normal relation to Tenderable. A Stage or Sound inherit from Tenderable. You can then easily select all Tenderables, or all Sounds/Stages seperately as well.
Hope this helps.
Upvotes: 3
Reputation: 8954
Tender.select("DISTINCT tendable_type").collect(&:tendable_type).compact
Will give you the name of all associated Models that have already been used at least once.
For all Objects that have been associated as tendable
Tender.where("tendable_type IS NOT NULL").collect(&:tendable)
Upvotes: 3