views:

271

answers:

4

I'm wondering to what extent I can use associations in Rails. Take into consideration the following:

class User < ActiveRecord::Base
    has_one :provider
    has_many :businesses, :through => :provider
end

class Provider < ActiveRecord::Base
    has_many :businesses
    has_many :bids, :through => :businesses
    belongs_to :user
end

class Business < ActiveRecord::Base
    has_many :bids
    belongs_to :provider
end

class Bid < ActiveRecord::Base
    belongs_to :business
end

I am able to set up these nifty shortcuts like User.businesses and Provider.bids but what about doing something like User.bids? Is it possible to associate an association, so to speak?

+1  A: 

Although it is a very useful thing to have, you can't has_many :through a has_many :through relationship. This is a limitation of the join engine.

The alternatives are either to use a clever sub-select, or in this case a sub-sub select, or to deliberately denormalize the tables enough to reduce the join depth.

For example, since a Business is defined within the context of a Provider, it stands to reason that any Bid elements are also assigned, indirectly, to a Provider. Building a direct association between Bid and Provider would make querying bids directly easy.

tadman
+3  A: 

This is entirely possible, but needs a little extra work. The following model definitions used in conjunction with the nested_has_many plugin you can fetch all bids belonging to a user with just @user.bids

class User < ActiveRecord::Base
    has_one :provider
    has_many :businesses, :through => :provider
    has_many :bids, :through => :businesses
end

class Provider < ActiveRecord::Base
    has_many :businesses
    has_many :bids, :through => :businesses
    belongs_to :user
end

class Business < ActiveRecord::Base
    has_many :bids
    belongs_to :provider
end

class Bid < ActiveRecord::Base
    belongs_to :business
end

However getting a user from a bid will take a more work.

EmFi
It is possible, but need to be careful about how deeply you nest, because you can bog down your database and rails app. That being said, I've written a blog post that details how use nested_has_many_through to do this: http://kconrails.com/2010/01/28/nesting-has_many-through-relationships-in-ruby-on-rails/
Jaime Bellmyer
A: 

There's nothing stopping you doing something like this afaik:

class User < ActiveRecord::Base
    has_one :provider
    has_many :businesses, :through => :provider

    def bids
        user_bids = []
        businesses.each |business| do
            user_bids += business.bids
        end
        user_bids
    end
end

class Provider < ActiveRecord::Base
    has_many :businesses
    has_many :bids, :through => :businesses
    belongs_to :user
end

class Business < ActiveRecord::Base
    has_many :bids
    belongs_to :provider
end

class Bid < ActiveRecord::Base
    belongs_to :business
end

Then calling @user.bids should produce the desired result, you can also cache the bids and do other fancy stuff if you want.

ridecar2
A: 

If you just want to fetch the records, why not use use #delegate? It works just fine, at least in the scenario you've described.

class User < ActiveRecord::Base
    has_one :provider
    delegates :bids, :to => :provider
end

class Provider < ActiveRecord::Base
    has_many :businesses
    has_many :bids, :through => :businesses
    belongs_to :user
end

class Business < ActiveRecord::Base
    has_many :bids
    belongs_to :provider
end

class Bid < ActiveRecord::Base
    belongs_to :business
end

Although in my not-so-humble-opinion you should just chain the methods because it's more straightforward, and you're no longer achieving the performance boost unless you go with some crazy custom SQL as tadman says.

floyd