0

В приложении для магазина электронной торговли я хотел бы получить все заказы, соответствующие first_name, которые были введены с помощью формы поиска и где платная == истина. Форма поиска представляет собой поисковый запрос с помощью параметров Parameters: {"utf8"=>"✓", "search"=>"john", "commit"=>"Search"}. В контроллереRails/SQL: использование массива в качестве параметра поиска

@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, возвращается несколько идентификаторов пользователей и возвращается сообщение об ошибке ActiveRecord::StatementInvalid. Я понимаю, что запрос перестает работать после того, как `@users.ids - это массив с более чем одним значением.

Как создать следующий запрос: для каждого user_id вернуть все заказы (user.orders), где платная равна true.

Models 
user.rb 
has_many :orders 

order.rb 
belongs_to :users 

ответ

0

Существуют различные способы решения этой проблемы.

Вы можете использовать ОБЪЕДИНЕНИЕ как Nic Nilov, но это может быть сложно, если ваш запрос @users построен с использованием областей и вы не хотите вручную устанавливать эти области вручную.

Вы также можете использовать подзапрос, поскольку ActiveRecord в Rails4 достаточно сделать правильную вещь умный, когда вы используете соотношение в 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... */ 
) 

преимущество здесь в том, что вам не нужно знать, что делает User.search до тех пор, как он возвращается в отношения ActiveRecord.

Если ваш @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 массива без необходимости делать что-либо дополнительно.

0

Вместо двух запросов, вы должны использовать вложенный запрос с пунктом WHERE IN

SELECT * from Order WHERE user_id IN (SELECT user_id FROM users WHERE first_name LIKE ?) AND paid = true 
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' 
+0

Проблема в том, что вы считаете, что 'User.search (s)' действительно 'User.where (: name => s)', а не, скажем, запрос LIKE. –

Смежные вопросы