我使用Rails 5.1+,并且我想根据两个条件查询模型,这两个条件可以有多个值但总是两个两个。
我们假设我有一个User
模型,其中包含first_name
和last_name
。
我正在寻找具有以下任何一个的用户:
first_name: "John"
last_name: "Doe"
或
first_name: "Jane"
last_name: "Snow"
如何编写指定此查询的查询?
我总是可以生成一个SQL查询字符串,我将其传递给where
子句,但我想知道是否有更好的方法。
答案 0 :(得分:2)
您可以尝试在模型中定义辅助方法并使用or
方法(未测试):
class User
def self.where_in_pairs(values = [])
values.map { |(first_name, last_name)|
where(first_name: first_name, last_name: last_name)
}.reduce(:or)
end
end
并且这样打电话:
User.where_in_pairs([["John", "Doe"], ["Jane", "Snow"]])
你也可以使用普通的arel(测试):
class User
def self.where_in_pairs(values = [])
where(
values.map { |(first_name, last_name)|
arel_table[:first_name].eq(first_name).and(
arel_table[:last_name].eq(last_name)
)
}.reduce(:or)
}
end
end
答案 1 :(得分:1)
怎么样?
SELECT * FROM users WHERE CONCAT(first_name, ' ', last_name) IN ("John Doe", "Jane Snow")
在rails中
first_name_last_names = ["John Doe", "Jane Snow"]
USER.where("CONCAT(first_name, ' ', last_name) IN (?)", first_name_last_names)
答案 2 :(得分:0)
您可以尝试使用ransack(gem install ransack
)并调用类似的内容:
User.ransack(first_name_and_last_name_cont: “John Smith”)
https://github.com/activerecord-hackery/ransack/blob/master/README.md(请注意,您无需使用搜索表单来使用搜索结果)
另一种选择是写两个范围,一个用于名字,一个用于姓氏并链接它们。
class User
scope :by_first_name, -> (first_name) { where(first_name: first_name) }
scope :by_last_name, -> (last_name) { where(last_name: last_name) }
end
User.by_first_name(“John”).by_last_name(“Smith”)
答案 3 :(得分:0)
你可以使用Rails OR运算符,但这是一个递归调用,所以我不知道是否有比这更好的东西:
first_name, last_name = names.pop
users = User.where(first_name: first_name, last_name: last_name)
while ((first_name, last_name) = names.pop) do
users = User.where(first_name: first_name, last_name: last_name).or(users)
end
#your result is in 'users'
另一种解决方案是添加name
列,并使用带有self.name = "#{first_name} #{last_name}"
的before_save回调来使用User.where(name:[])
第三种解决方案(但每个名称产生1个SQL请求):
User.where(id: names.each { |first_name, last_name| User.where(first_name: f, last_name, l).pluck(:id) })