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.
精彩评论