ActiveRecord Association缓存条件子句中的Date值

时间:2008-10-07 08:30:59

标签: ruby-on-rails

我的Account模型有以下两种关联:

has_many  :expenses, 
          :order => 'expenses.dated_on DESC', 
          :dependent => :destroy

has_many  :recent_expenses, 
          :class_name => 'Expense', 
          :conditions => "expenses.dated_on <= '#{Date.today}'",
          :order => 'dated_on DESC', 
          :limit => 5

在我的一个观点中,我正在渲染最近的费用:

<% @account.recent_expenses.each do |expense| %>
...
<% end %>

在我的开发计算机上,在登台服务器(在生产模式下运行)以及生产控制台上,@account.recent_expenses返回正确的列表。但是,在我们的实时生产服务器上,不会返回最近的费用。

如果我在视图中将@account.recent_expenses替换为@account.expenses,则显示最近的费用 ,因此我的猜测是条件的#{Date.today}部分在第一次执行时,子句以某种方式被缓存。如果我重新启动生产Mongrel集群,则会正确返回所有最新费用。

任何人都可以想到为什么会发生这种情况以及如何更改:recent_expenses查询以防止这种情况发生?

我正在使用Rails 2.1.0。

3 个答案:

答案 0 :(得分:6)

Rails在加载时构建查询,然后每次调用@ account.recent_expenses时都会重新使用该查询,这正是您所遇到的。

如果你正在使用Rails 2.1,你可以使用named_scope来实现你想要的。

费用模型中,输入以下内容:

named_scope :recent, lambda { {:conditions => ["expenses.dated_on <= ?", Date.today], :order => 'dated_on DESC', :limit => 5 } }

lambda用于确保rails每次都重建查询。

帐户删除:

has_many :recent_expenses ...

然后致电:

<% @account.expenses.recent.each do |expense| %>
...
<% end %>

答案 1 :(得分:3)

就像Andrew说的那样,在应用程序启动时会读取关联宏,因此在那时会解析任何动态位(如Date.today)。如果您使用Rails 2.1或更高版本,他的解决方案就可以工作;对于早期版本,您可以使用has_finder gem,或者只在Expense模型上创建以下方法:

def self.recent
  find(:all, :conditions => ['dated_on <= ?', Date.today], :limit => 5, :order => 'dated_on DESC')
end

像这样的类方法暴露给关联,并且是适当的范围 - 它们和named_scopes之间的区别在于你不能链接它们。

答案 2 :(得分:1)

以下是Rails 3中的内容:

scope :recent, lambda { where("expenses.dated_on <= ?", Date.today).order('dated_on DESC').limit(5) }

警告: 注意未包含在lambda中的链式范围。您可能认为链的一部分是在运行时评估的,但可以在应用服务器启动时进行评估。确保lambda包装将使用这些其他范围的任何范围。这里的解释: http://www.slashdotdash.net/2010/09/25/rails-3-scopes-with-chaining/