我有一个方法,它可以根据一组标准从数据库中返回许多项目:
scope :expired_not_marked, lambda { |client|
items = where('items.status > 0 AND items.expires_at < ? AND items.expired_at IS NULL AND (winning_bid_id IS NULL OR winner_id IS NULL)', Time.now)
unless client.nil?
items.where('items.client_id = ?', client.id)
end
}
它被称为Item.expired_not_marked nil
。当我从IRB运行它时,我得到了很多结果,但它显示了执行的SQL查询:
SELECT `items`.* FROM `items`
很明显,这不是原作者的意图。结果,一遍又一遍地处理相同的项目。
为什么会破坏,我该如何修复它。 where子句似乎是正确的。上述方法属于item.rb
模型。
答案 0 :(得分:5)
您的问题是,lambda
有时会返回nil
,而返回nil
的范围将无效。
lambda
将返回其最后一个表达式的值。在您的情况下,该表达式将是unless
。因此,如果client
不是nil
,则会返回此信息:
items.where('items.client_id = ?', client.id)
一切都会好的。但如果client.nil?
为真,则unless
将评估为nil
,您的范围将返回nil
。我认为你会用这样的东西变得更好:
scope :expired_not_marked, lambda { |client|
items = where('items.status > 0 AND items.expires_at < ? AND items.expired_at IS NULL AND (winning_bid_id IS NULL OR winner_id IS NULL)', Time.now)
unless client.nil?
items = items.where('items.client_id = ?', client.id)
end
items
}
通过这种方式,您始终可以获得清晰,明确且定义明确的返回值。
ActiveRecord Query Interface Guide建议您对带参数的作用域使用类方法:
使用类方法是接受范围参数的首选方法。
所以如果lambda
方法过于嘈杂,你也可以这样做:
def self.expired_not_marked(client)
items = where('items.status > 0')
items = items.where('items.expires_at < ?', Time.now)
items = items.where('items.expired_at IS NULL')
items = items.where('winning_bid_id IS NULL OR winner_id IS NULL')
unless client.nil?
items = items.where('items.client_id = ?', client.id)
end
items
}
当然,您不必使用类方法。而且您不必将查询分解为每个组件的一堆小where
调用,但这样可能更容易阅读。
答案 1 :(得分:1)
lambda一直没有返回任何内容。如果没有明确的return
语句,则lambda的最后一个求值表达式将是它的返回值。
scope :expired_not_marked, lambda { |client|
items = where('items.status > 0 AND items.expires_at < ? AND items.expired_at IS NULL AND (winning_bid_id IS NULL OR winner_id IS NULL)', Time.now)
unless client.nil?
items.where('items.client_id = ?', client.id)
end
items
}
如果我写这篇文章,我会建议一个scoped
对象。这将确保只执行一个SQL查询。
scope :expired_not_marked, lambda { |client|
items = Items.scoped.where('items.status > 0 AND items.expires_at < ? AND items.expired_at IS NULL AND (winning_bid_id IS NULL OR winner_id IS NULL)', Time.now)
items = items.where('items.client_id = ?', client.id) unless client.nil?
items.all
}