У меня такой запрос:

select * from email_contacts
where extract(month from created_at) = 4
and call_type = 'Membership NPS'
and email NOT IN
(
    select invite_email from nps_responses
    where extract(month from fs_created_at) = 4
    and invite_email is not null
)

Затем у меня есть приложение rails 4, в котором есть две соответствующие модели: EmailContact и NpsResponse.

Как я могу преобразовать этот запрос для выполнения в моем методе контроллера в Rails? Мне нужно выбрать все email_contacts с указанными выше критериями.

1
Luigi 17 Апр 2014 в 04:05

2 ответа

Лучший ответ

Возможно, это не идеальное решение "Rails way", но вы можете сделать это, используя find_by_sql. Использование find_by_sql по-прежнему будет извлекать экземпляры объектов для вашего объекта модели:

EmailContact.find_by_sql(your_sql_statement)

Использовать переменные привязки

Чтобы предотвратить внедрение SQL, вы должны использовать привязать переменные с методом find_by_sql (привязать переменные являются параметрами-заполнителями, представленными символом ?. Метод find_by_sql связывает значения параметров перед выполнением оператора.) Это настоятельно рекомендуется с точки зрения безопасности.

Вот пример использования вашего оператора SQL с переменными связывания в методе find_by_sql:

EmailContact.find_by_sql("select * from email_contacts
          where extract(month from created_at) = ?
          and call_type = ?
          and email NOT IN
          (
              select invite_email from nps_responses
              where extract(month from fs_created_at) = ?
              and invite_email is not null
          )", 4, 'Membership NPS', 4)

На что обратить внимание:

  • Первым параметром метода find_by_sql является оператор SQL в виде строкового значения. В этой конкретной строке SQL есть три символа ? в качестве переменных-заполнителей.
  • Следующие три параметра в find_by_sql - это значения, которые должны быть привязаны к символу ? в операторе SQL.
  • Порядок параметров важен - первый параметр связываемой переменной будет привязан к первому символу ? и т. Д.
  • Вы можете иметь переменное количество параметров связываемой переменной, пока количество ? совпадает с количеством параметров связываемой переменной.

Для лучшей организации кода у вас может быть какой-то вспомогательный метод для создания оператора SQL с переменными связывания. Примерно так:

def email_contacts_SQL
   sql = "select * from email_contacts
          where extract(month from created_at) = ?
          and call_type = ?
          and email NOT IN
          (
              select invite_email from nps_responses
              where extract(month from fs_created_at) = ?
              and invite_email is not null
          )"
end

А затем используйте find_by_sql со своим вспомогательным методом:

EmailContact.find_by_sql(email_contacts_SQL, 4, 'Membership NPS', 4)

В официальном документе Rails API есть больше примеров того, как используйте find_by_sql.

Предупреждение : если вы используете find_by_sql, вы теряете независимые от базы данных преобразования, предоставленные ActiveRecord. Метод find_by_sql выполняет инструкцию SQL как есть.

1
richsinn 17 Апр 2014 в 21:02

Что-то близкое к тому, что вы написали бы в ActiveRecord, это использует переменные связывания и защищает от внедрения sql

EmailContact.where("month from created_at ?", some_value).
  where(:call_type => 'Membership NPS').
  where("email NOT IN (
              select invite_email from nps_responses
              where extract(month from fs_created_at) = ?
              and invite_email is not null
          )", some_value).all
1
bjhaid 17 Апр 2014 в 02:48