Подтвердить что ты не робот

Как указать несколько значений, где с интерфейсом AR-запроса в rails3

В разделе 2.2 руководства по направляющим по интерфейсу запросов Active Record здесь:

который, как представляется, указывает, что я могу передать строку, определяющую условие (ы), а затем массив значений, который должен быть заменен в какой-то момент, в то время как isl строится. Таким образом, у меня есть инструкция, которая генерирует строку условий, которая может быть различным числом атрибутов, соединенных вместе с И или ИЛИ между ними, и я передаю массив как второй аргумент методу where, и я получаю:

ActiveRecord:: PreparedStatementInvalid: неверное число переменных привязки (1 для 5)

что заставляет меня поверить, что я делаю это неправильно. Однако я не нахожу ничего о том, как это сделать правильно. Чтобы повторить проблему другим способом, мне нужно передать строку методу where, например "table.attribute =? AND table.attribute1 =? OR table.attribute1 =?" с неизвестным числом этих условий и вместе или вместе, а затем передать что-то, что, как я думал, будет массивом в качестве второго аргумента, который будет использоваться для подстановки значений в строке условий первого аргумента. Это правильный подход, или я просто пропустил какую-то другую огромную концепцию где-то, и я прихожу на все это неправильно? Я бы подумал, что так или иначе, это должно быть возможно, а не просто генерировать необработанную строку sql.

4b9b3361

Ответ 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])

делает то же самое