Rails / SQL:使用数组作为搜索参数

时间:2016-07-29 20:17:44

标签: sql ruby-on-rails postgresql ruby-on-rails-4 rails-activerecord

在电子商务商店应用程序中,我想检索与通过搜索表单输入的first_name匹配的所有订单,其中pay == true。搜索表单通过参数Parameters: {"utf8"=>"✓", "search"=>"john", "commit"=>"Search"}提交搜索词。在控制器中

@users = User.search(params[:search]) #returns all users with the matching first_name, e.g. 'john'
@order = Order.where('user_id = ? AND paid = ?',  @users.ids, true )

@order中的查询工作得很好,如果只返回一个user,例如只有一个用户名为john。但是,如果多个用户名为John,则会返回多个用户ID,并返回错误消息ActiveRecord::StatementInvalid。我的理解是,一旦`@users.ids是一个具有多个值的数组,查询就会停止工作。

如何构造以下查询:对于每个user_id,返回所有支付等于true的订单(user.orders)。

Models
user.rb
has_many :orders

order.rb
belongs_to :users

3 个答案:

答案 0 :(得分:0)

您应该使用带有WHERE IN子句

的嵌套查询,而不是两个查询
SELECT * from Order WHERE user_id IN (SELECT user_id FROM users WHERE first_name LIKE ?) AND paid = true

答案 1 :(得分:0)

这应该做:

Order.joins(:user).where(users: { name: params[:search] }, paid: true)

它使用INNER JOIN生成一个查询:

SELECT "orders".*
  FROM "orders"
    INNER JOIN "users" ON "users"."id" = "orders"."user_id"
  WHERE "users"."name" = 'Test User' AND "orders"."paid" = 't'

答案 2 :(得分:0)

有很多方法可以解决这个问题。

您可以使用Nic Nilov建议使用JOIN,但如果使用范围构建@users查询并且您不想手动内联这些范围,则可能会很困难。

您也可以使用子查询,因为Rails4中的ActiveRecord足够聪明当您在where中使用关系时,您需要使用where的哈希形式:

@users = User.search(params[:search])
# @users should be a User::ActiveRecord_Relation now.
@orders = Order.where(:user_id => @users, :paid => true)

最终将使用SQL:

select *
from orders
where paid = 't'
  and user_id in (
    select id
    from users
    where /* whatever `search` does... */
)

这里的优势在于,只要它返回ActiveRecord关系,您就不需要知道User.search的作用。

如果您的@users实际上是一个数组(id个或整个User个实例),那么您完全按照相同的方式执行此操作:

# Suppose @users is an array of Users or an array of User ids...
@orders = Order.where(:user_id => @users, :paid => true)

和ActiveRecord将在不必做任何额外操作的情况下弄清楚如何处理@users数组。