简体   繁体   中英

rails has_many :through has_many :through

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?

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.

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
    delegate :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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM