#ruby-on-rails-5 #arel
Вопрос:
У меня возникла проблема с получением запроса для работы.
По сути, я пытаюсь написать что-то вроде следующего SQL, с 5
заменой литерала переменной:
SELECT *
FROM "my_table"
WHERE 5 BETWEEN "my_table"."minimum" AND "my_table"."maximum"
Это то, что у меня есть на данный момент:
MyModel.where(
Arel::Nodes::Between.new(
my_variable, (MyModel.arel_table[:minimum]).and(MyModel.arel_table[:maximum])
)
)
Пожалуйста , не обращайте внимания на то, как я использую arel_table
, фактический запрос имеет несколько соединений и является более сложным, но это самый минимальный воспроизводимый пример, который я могу продемонстрировать проблему.
Ошибка, как и в предмете вопроса, заключается в следующем:
undefined method `and' for #<Arel::Attributes::Attribute:0x00007f55e15514f8>
Ответ №1:
and
метод предназначен для Arel::Nodes::Node
, т. е. MyModel.arel_attribute[:name].eq(Arel::Nodes::Quoted.new('engineersmnky'))
Это и есть Arel::Nodes::Equality
, и вы можете связать and
его .
Это, как говорится, вы можете построить Arel::Nodes::And
для себя с помощью
Arel::Nodes::And.new([left,right])
Затем мы можем передать это Between
классу вот так
Arel::Nodes::Between.new(
Arel::Nodes::Quoted.new(my_variable),
Arel::Nodes::And.new([
MyModel.arel_table[:minimum],
MyModel.arel_table[:maximum]])
)
Arel::Nodes::Quoted
(также: Arel::Nodes.build_quoted(arg)
) в вашем случае не требуется, так как ваш объект my_variable
Integer
можно посетить и он будет рассматриваться как объект, Arel::Nodes::SqlLiteral
но я считаю, что лучше позволить arel решить, как обращаться с цитированием my_variable
, если вы окажетесь каким-то другим недоступным для посещения Object
Существуют другие способы создания a Between
и другие способы создания an And
в зависимости от того, с какими объектами вы имеете дело.
between
является a Arel::Predication
, и эти предикации доступны для Arel::Nodes::Attribute
объектов, например
MyModel.arel_table[:minimum].between([1,6])
and
как уже упоминалось, доступно Arel::Nodes::Node
и экземпляры этого класса предоставляют удобный метод ( create_and
) для создания And
, чтобы мы могли сделать следующее:
Arel::Nodes::Node.new.create_and([
MyModel.arel_table[:minimum],
MyModel.arel_table[:maximum]])
Существует множество других способов взломать эту функциональность вместе с помощью других Arel
классов, но это должно направить вас в правильном направлении.
Комментарии:
1. Удивительное понимание и решение, большое вам спасибо!