Если вы хотите связать воедино открытый список условий (имен и значений атрибутов), я бы предложил использовать таблицу arel.
Немного сложно дать конкретику, поскольку ваш вопрос настолько расплывчатый, поэтому я просто объясню, как это сделать, для простого случая модели Post
и нескольких атрибутов, скажем title
, summary
и user_id
(то есть пользователь has_many
сообщений).
Во-первых, возьмите таблицу арелей для модели:
table = Post.arel_table
Затем начните строить свой предикат (который вы в конечном итоге будете использовать для создания SQL-запроса):
relation = table[:title].eq("Foo")
relation = relation.or(table[:summary].eq("A post about foo"))
relation = relation.and(table[:user_id].eq(5))
Здесь table[:title]
, table[:summary]
и table[:user_id]
являются представлениями столбцов в таблице posts
. Когда вы вызываете table[:title].eq("Foo")
, вы создаете предикат, примерно эквивалентный условию поиска (получите все строки, столбец заголовка которых равен «Foo»). Эти предикаты могут быть соединены вместе с and
и or
.
Когда ваш агрегированный предикат готов, вы можете получить результат с помощью:
Post.where(relation)
, который сгенерирует SQL:
SELECT "posts".* FROM "posts"
WHERE (("posts"."title" = "Foo" OR "posts"."summary" = "A post about foo")
AND "posts"."user_id" = 5)
Вы получите все сообщения с заголовком «Foo» или резюме «Сообщение о Foo», и , принадлежащие пользователю с идентификатором 5.
Обратите внимание на то, как предикаты верблюдов могут бесконечно объединяться в цепочку для создания все более сложных запросов. Это означает, что если у вас есть (скажем) хэш пар атрибут / значение и есть какой-то способ узнать, использовать ли AND
или OR
для каждой из них, вы можете циклически просматривать их один за другим и создавать свое условие :
relation = table[:title].eq("Foo")
hash.each do |attr, value|
relation = relation.and(table[attr].eq(value))
# or relation = relation.or(table[attr].eq(value)) for an OR predicate
end
Post.where(relation)
Помимо простоты условий объединения, еще одним преимуществом таблиц arel является то, что они независимы от базы данных, поэтому вам не нужно беспокоиться о том, будет ли ваш запрос MySQL работать в PostgreSQL и т. Д.
Вот Railscast с подробностями об арене: http://railscasts.com/episodes/215-advanced-queries-in-rails-3?view=asciicast
Надеюсь, это поможет.