ActiveRecord按值对查询

时间:2017-12-14 12:37:20

标签: sql ruby-on-rails activerecord ruby-on-rails-5 rails-activerecord

我使用Rails 5.1+,并且我想根据两个条件查询模型,这两个条件可以有多个值但总是两个两个。

我们假设我有一个User模型,其中包含first_namelast_name。 我正在寻找具有以下任何一个的用户:

first_name: "John"
last_name: "Doe"

first_name: "Jane"
last_name: "Snow"

如何编写指定此查询的查询? 我总是可以生成一个SQL查询字符串,我将其传递给where子句,但我想知道是否有更好的方法。

4 个答案:

答案 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) })