开发者

Creating a Rails 3 named scope involving 3 tables

Running Rails 3.0.7 on Mac OS X with Ruby 1.9.2

I have three models with tables behind them (sqlite3 for dev, postgres for prod). They are as follows (validations and other irrelevant lines truncated):

class ServiceProvider < ActiveRecord::Base
  has_many :services
  has_many :advertisements, :through => :services
  scope :active, where("service_providers.active = ?", true)
end

class Service < ActiveRecord::Base
  belongs_to :service_provider
  has_many :advertisements
  scope :active, joins(:service_provider).where("services.active = ?", true) & ServiceProvider.active
end

class Advertisement < ActiveRecord::Base
  belongs_to :service
  scope :ranked, where("advertisements.rank > 0")
  scope :current, where("start_date <= ? AND end_date >= ?", Date.today, Date.today)
  scope :service_active, joins(:service) & Service.active
  scope :active, ranked.current.service_active
end

As you can see, each service provider has many services and each service can have many advertisements. The advertisements table has the service_id foreign key in it and the services table has the service_provider_id foreign key in it. All pretty standard many to one relationships. Service Providers can be made inactive through an "active" flag as can individual services in a similar way.

What I want to be able to do is create a named scope on the Advertisement model to give me a list of all advertisements which are ranked and current and who's parent service is active and in turn who's service_provider is active. In other words, if a service is made inactive then all advertisements pointing to it should become inactive and if a service provider is made inactive then all services, and in turn all advertisements under those services should become inactive.

I have made a stab at creating the required named scopes above and it works as expected at the Service.active and ServiceProvider.active levels but if I type in Advertisement.active I get an error:

ActiveRecord::ConfigurationError: Association named 'service_provider' w开发者_如何学Pythonas not found; perhaps you misspelled it? 

I think this is because I don't have service_provider_id as a foreign key field in the advertisers table but I didn't think I would need that because it should access the service_provider via the service_provider_id field on the services table. It feels like I need a belongs_to :service_provider, :through => :service clause in my Advertisement model but this isn't possible as far as I know. I have tried various things to get this working but I'm struggling to make progress.

Can anyone tell me a nice elegant way to achieve the above, ideally without changing my table structure? I need it to be quite efficient as this query will be run for every page load on my website (sidebar ads on each page).

Many thanks, Craig.


I think the following would work:

class Advertisement
    scope :service_active, joins(:service => :service_provider)
                           .where(:services => { :active => true })
                           .where(:service_providers => { :active => true })
end

Then you should be able to call

Advertisement.ranked.current.service_active

and get the expected result.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜