I have the following models:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class AddOn < ActiveRecord::Base | |
has_many :pricing_plans, :dependent => :destroy | |
end | |
class PricingPlan < ActiveRecord::Base | |
has_many :subscriptions | |
end | |
class Subscription < ActiveRecord::Base | |
belongs_to :person | |
belongs_to :pricing_plan | |
end | |
class Person < ActiveRecord::Base | |
has_many :subscriptions | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
person = Person.first | |
person.add_ons |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
select * from add_ons | |
inner join pricing_plans on add_ons.id = pricing_plans.add_on_id | |
inner join subscriptions on pricing_plans.id = subscriptions.pricing_plan_id | |
inner join people on people.id = subscriptions.person_id | |
where people.id = 1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# i started with the following, which i thought would work with no problem: | |
AddOn.joins(:pricing_plans).joins(:subscriptions) | |
# returned this error: | |
# ActiveRecord::ConfigurationError: | |
# Association named 'subscriptions' was not found; perhaps you misspelled it? | |
# trying to get at it from the other direction: | |
PricingPlan.joins(:subscriptions).joins(:person) | |
# of course this didn't work either | |
# ActiveRecord::ConfigurationError: Association named 'person' was not found; perhaps you misspelled it? | |
# here i shoot in the dark hoping something Arel-like would magically happen: | |
AddOn.joins(:pricing_plans).joins(:subscriptions).on(pricing_plans[id].eq(subscriptions[pricing_plan_id])) | |
# of course not. (this is embarrassing) | |
# NameError: undefined local variable or method `pricing_plans' for #<Object:0x1001d52a8> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Person | |
# ... | |
def add_ons | |
AddOn.joins(:pricing_plans => {:subscriptions => :person}).where(:subscriptions => {:person_id => self}) | |
end | |
# ... | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
person = Person.first | |
add_on = AddOn.first | |
person.add_ons.exists?(add_on) |
Rails 3 is awesome. You might find `has_many :through` useful for doing this sort of thing.
ReplyDeletei didn't think :through would help with the double hop: Person -> PricingPlan -> Subscription -> AddOn. maybe it does?
ReplyDeletehas_many :through doesn't chain, so you definitely came up with the best solution here. Had to do a similar thing for a Rails 2 project, once.
ReplyDeleteI think you missed sting
ReplyDeletebelongs_to :add_on
in class PricingPlan.
You sir, just saved my bacon. Much appreciated! Here's a scope example of the above:
ReplyDeletescope :active, lambda { joins(:order_item => {:order => :payment}).where(:payments => {:status => ["Status1", "Status2"]}) }
Thank you... this was very helpful
ReplyDeleteThanks! Had the exact same problem. Funny, I also started with something like:
ReplyDeleteAddOn.joins(:pricing_plans).joins(:subscriptions)
Maybe that would be the intuitive way rails should accommodate?
hi brian,
ReplyDeleteyour post was very helpfu, thank you
learning rails but got stuck
dont know if i could ask this question here
if not i m sorry
models
bill
attr_accessible :billdt, :billno, bill_amt
has_many :parbills, :dependent => :destroy
has_many :particulars, :through => :parbills
particulars
attr_accessible :description, :name
has_many :parbills
has_many :bills, :through => :parbills
parbill
attr_accessible :bill_id, :paramt, :particular_id
belongs_to :bill
belongs_to :particular
client
attr_accessible :name, :ctype
has_one :bill, :dependent => :destroy
able to query particulars billed for a given date
@rpar = Parbill.where(:particular_id => params[:particular_id])
@rparbills = @rpar.joins(:bill).where('bills.billdt between ? and ?', @sdate, @edate)
but trying to query particulars billed for a given date on ctype(client type in client model)
please suggest