неопределенный метод «и» для #

#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. Удивительное понимание и решение, большое вам спасибо!