2014-10-21 2 views
0

Заказы имеют много элементов LineItems. У LineItems есть имена, такие как «автомобиль». Я хочу найти все заказы с позициями с именами, соответствующими одному шаблону.Когда запрос включает отношения, как я могу использовать сопоставление шаблонов на включенной таблице?

Я знаю, что могу сделать LineItem.where('name ~* :pat', pat: 'car'), например.

Я также знаю, что могу сделать

Order.where.not(state: "cancelled") 
    .includes(:line_items) 
    .where(line_items: { name: "car" }) 

Я не уверен на синтаксис для объединения двух запросов. Я думаю, что это что-то вроде:

Orders.where.not(state: 'cancelled') 
     .includes(:line_items) 
     .where(line_items: ['name ~* :pat', pat: 'car']) 

Это сложно для Google, поэтому я подумал, что поставлю его вам.

ПРИМЕЧАНИЕ: в прошлый раз у меня возник вопрос о Rails activerecord, частью решения было проверить SQL. В этом случае, однако, использование метода includes приводит к некоторому сумасшедшему страшному SQL. Попробуйте что-то вроде этого:

Order.includes(:line_items).where(line_item: { name: "car"}).to_sql 

в вашем рельсовом пульте для приятного времяпровождения!

ПРИМЕЧАНИЯ: Мне нужна помощь в названии этого вопроса.

ответ

0

Как уже упоминалось в rails guide,

Используя где, как это будет работать только тогда, когда вы передаете его Hash. Для SQL-фрагментов вам нужно использовать ссылки, чтобы заставить объединение таблиц:

Post.includes(:comments).where("comments.visible = true").references(:comments) 

Так что в моем случае, запрос будет:

Orders.where.not(state: 'cancelled') 
     .includes(:line_items) 
     .where('line_items.name ~* ?', 'car').references(:line_items) 

Это возвращает все заказы с позицией, имеющими имена сопоставляя заданное регулярное выражение с предварительно загруженными позициями. Если вы предпочитаете не предварительно загружать позиции, используйте joins вместо includes.

Я не уверен, что вы сделали бы, если бы захотелось предварительно загрузить все позиции для каждого заказа, независимо от условия (но, надеюсь, мне не понадобится^o^//).

EDIT: this article пролил много света на то, что именно происходит, и ответил на мой второй вопрос. Чтобы предварительно загрузить все позиции, которые вы должны использовать ... preload ha!

Orders.where.not(state: 'cancelled') 
     .joins(:line_items) # note the joins 
     .where('line_items.name ~* ?', 'car').references(:line_items) 
     .preload(:line_items) 

Если вы используете .includes снова здесь, вы разочаруетесь. Это должно быть preload. Этот запрос получает мне заказы, которые я хочу, и предварительно загружает все позиции независимо от того, соответствуют ли они регулярному выражению, используемому для фильтрации заказов.