创建一个涉及3个表的Rails 3命名范围

时间:2011-06-16 18:18:37

标签: ruby-on-rails ruby-on-rails-3

使用Ruby 1.9.2在Mac OS X上运行Rails 3.0.7

我有三个模型,后面有表格(sqlite3表示dev,postgres表示prod)。它们如下(验证和其他不相关的行被截断):

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

如您所见,每个服务提供商都有许多服务,每个服务都可以有很多广告。广告表中包含service_id外键,services表中包含service_provider_id外键。所有相当标准的多对一关系。可以通过“活动”标志使服务提供者处于非活动状态,就像个别服务一样。

我希望能够做的是在广告模型上创建一个命名范围,以便为我提供所有广告的列表,这些广告是排名和当前以及谁的父服务是活动的,反过来谁的service_provider是活动的。换句话说,如果某个服务处于非活动状态,那么指向该服务的所有广告都将变为非活动状态,如果服务提供商变为非活动状态,则所有服务都将变为非活动状态,而这些服务下的所有广告将变为非活动状态。

我已经开始创建上面所需的命名范围,它在Service.active和ServiceProvider.active级别按预期工作,但是如果我输入Advertisement.active,我会收到错误:

ActiveRecord::ConfigurationError: Association named 'service_provider' was not found; perhaps you misspelled it? 

我认为这是因为我没有将service_provider_id作为广告商表中的外键字段,但我认为我不需要它,因为它应该通过服务表上的service_provider_id字段访问service_provider。感觉我需要belongs_to:service_provider,:through =&gt; :我的广告模型中的service子句,但据我所知,这是不可能的。我已经尝试了各种各样的方法来实现这个目标,但我正在努力取得进展。

有人能告诉我一个很好的方法来实现上述目标,理想情况下不会改变我的表结构吗?我需要它非常有效,因为此查询将针对我网站上的每个页面加载运行(每页上的侧边栏广告)。

非常感谢, 克雷格。

1 个答案:

答案 0 :(得分:7)

我认为以下内容可行:

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

然后你应该可以打电话了

Advertisement.ranked.current.service_active

并获得预期结果。