Как указать несколько значений, где с интерфейсом AR-запроса в rails3
В разделе 2.2 руководства по направляющим по интерфейсу запросов Active Record здесь:
который, как представляется, указывает, что я могу передать строку, определяющую условие (ы), а затем массив значений, который должен быть заменен в какой-то момент, в то время как isl строится. Таким образом, у меня есть инструкция, которая генерирует строку условий, которая может быть различным числом атрибутов, соединенных вместе с И или ИЛИ между ними, и я передаю массив как второй аргумент методу where, и я получаю:
ActiveRecord:: PreparedStatementInvalid: неверное число переменных привязки (1 для 5)
что заставляет меня поверить, что я делаю это неправильно. Однако я не нахожу ничего о том, как это сделать правильно. Чтобы повторить проблему другим способом, мне нужно передать строку методу where, например "table.attribute =? AND table.attribute1 =? OR table.attribute1 =?" с неизвестным числом этих условий и вместе или вместе, а затем передать что-то, что, как я думал, будет массивом в качестве второго аргумента, который будет использоваться для подстановки значений в строке условий первого аргумента. Это правильный подход, или я просто пропустил какую-то другую огромную концепцию где-то, и я прихожу на все это неправильно? Я бы подумал, что так или иначе, это должно быть возможно, а не просто генерировать необработанную строку sql.
Ответы
Ответ 1
Похоже, вы делаете что-то вроде этого:
Model.where("attribute = ? OR attribute2 = ?", [value, value])
Если вам нужно сделать это:
# notice the lack of an array as the last argument
Model.where("attribute = ? OR attribute2 = ?", value, value)
Посмотрите http://guides.rubyonrails.org/active_record_querying.html#array-conditions для более подробной информации о том, как это работает.
Ответ 2
Это на самом деле довольно просто:
Model.where(attribute: [value1,value2])
Ответ 3
Вместо того, чтобы передавать один и тот же параметр несколько раз до where()
, как этот
User.where(
"first_name like ? or last_name like ? or city like ?",
"%#{search}%", "%#{search}%", "%#{search}%"
)
вы можете легко обеспечить хэш
User.where(
"first_name like :search or last_name like :search or city like :search",
{search: "%#{search}%"}
)
что делает ваш запрос более понятным для длинных списков аргументов.
Ответ 4
Похоже, вы делаете что-то вроде этого:
Model.where("attribute = ? OR attribute2 = ?", [value, value])
Если вам нужно сделать это:
#notice the lack of an array as the last argument
Model.where("attribute = ? OR attribute2 = ?", value, value) Have a
посмотреть http://guides.rubyonrails.org/active_record_querying.html#array-conditionsдля более подробной информации о том, как это работает.
Было очень близко. Вы можете превратить массив в список аргументов с помощью * my_list.
Model.where("id = ? OR id = ?", *["1", "2"])
ИЛИ
params = ["1", "2"]
Model.where("id = ? OR id = ?", *params)
Должен работать
Ответ 5
Если вы хотите связать открытый список условий (имена и значения атрибутов), я бы предложил использовать таблицу isl.
Немного сложно дать специфику, так как ваш вопрос настолько расплывчатый, поэтому я просто объясню, как это сделать для простого случая модели 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.
Обратите внимание, что предикаты arel могут быть бесконечно соединены вместе, чтобы создавать все более сложные запросы. Это означает, что если у вас есть (скажем) хэш пар атрибут/значение и некоторый способ узнать, следует ли использовать 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)
Помимо удобства условий цепочки, еще одно преимущество таблиц isl заключается в том, что они не зависят от базы данных, поэтому вам не нужно беспокоиться, будет ли ваш запрос MySQL работать в PostgreSQL и т.д.
Здесь Railscast с большим количеством символов isl: http://railscasts.com/episodes/215-advanced-queries-in-rails-3?view=asciicast
Надеюсь, что это поможет.
Ответ 6
Вы можете использовать хеш, а не строку. Создайте хэш с каким-либо количеством условий и соответствующими значениями, которые у вас есть, и поместите их в первый аргумент метода where.
Ответ 7
НЕПРАВИЛЬНО
Это то, что я когда-то делал.
keys = params[:search].split(',').map!(&:downcase)
# keys are now ['brooklyn', 'queens']
query = 'lower(city) LIKE ?'
if keys.size > 1
# I need something like this depending on number of keys
# 'lower(city) LIKE ? OR lower(city) LIKE ? OR lower(city) LIKE ?'
query_array = []
keys.size.times { query_array << query }
#['lower(city) LIKE ?','lower(city) LIKE ?']
query = query_array.join(' OR ')
# which gives me 'lower(city) LIKE ? OR lower(city) LIKE ?'
end
# now I can query my model
# if keys size is one then keys are just 'brooklyn',
# in this case it is 'brooklyn', 'queens'
# @posts = Post.where('lower(city) LIKE ? OR lower(city) LIKE ?','brooklyn', 'queens' )
@posts = Post.where(query, *keys )
теперь, однако, да - это очень просто. как упоминалось nfriend21
Model.where(attribute: [value1,value2])
делает то же самое