为什么这个方法实际上不影响SQL查询?

Wil*_*ill 1 ruby ruby-on-rails

我有一个方法,它可以根据一组标准从数据库中返回一些项目:

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
}
Run Code Online (Sandbox Code Playgroud)

它被称为Item.expired_not_marked nil.当我从IRB运行它时,我得到了很多结果,但它显示正在执行的SQL查询:

SELECT `items`.* FROM `items` 
Run Code Online (Sandbox Code Playgroud)

显然这不是原作者的意图.结果,一遍又一遍地处理相同的项目.

为什么会破坏,我该如何解决它.where子句似乎是正确的.上述方法在item.rb模型中.

mu *_*ort 5

你的问题是你lambda有时会返回nil,返回的范围nil不会做任何有用的事情.

lambda将返回其最后一个表达式的值.在你的情况下,该表达式将是unless.所以,如果client不是nil,它将返回:

items.where('items.client_id = ?', client.id)
Run Code Online (Sandbox Code Playgroud)

一切都会好的.但如果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
}
Run Code Online (Sandbox Code Playgroud)

这样,您始终拥有清晰,明确且定义明确的返回值.


ActiveRecord的查询界面指南建议您使用类方法带参数的范围:

使用类方法是接受范围参数的首选方法.

如果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
}
Run Code Online (Sandbox Code Playgroud)

当然,您不必使用类方法.而且您不必将查询分解where为每个组件的一堆小调用,但这样可能更容易阅读.