#ruby-on-rails #activerecord
#ruby-on-rails #activerecord
Вопрос:
Мне нужно создать метод, который динамически фильтрует модель по столбцу. Он должен получить столбец, по которому я хочу отфильтровать (вызываемый attr_name
), operator
как строку и value
как строку.
Мне нужно сначала привести строковое значение к типу столбца базы данных, чтобы затем я мог выполнить sql-запрос.
scope :filtered_by_attribute, (lambda do |attr_name, operator, value|
comparing_value = Customer.attribute_types[attr_name].cast(value)
casting_error = !value.nil? amp;amp; comparing_value.nil?
raise I18n.t('api.errors.unaplicable_customer_scope') if casting_error
sql_query = sanitize_sql("#{attr_name} #{operator} ?")
where(sql_query, comparing_value)
end)
Проблема выше, когда дело доходит до enums
. Перечисления — это целые числа в базе данных, но когда я выполняю приведение, оно возвращает то же строковое значение, поскольку для rails это строка. Затем в запросе where происходит сбой, поскольку в базе данных он сравнивает столбец integer со строкой.
Вы знаете, как я приводил строковое значение в соответствие с типом столбца в базе данных?
Спасибо!
Комментарии:
1. Покажите пример вызова области видимости с атрибутом enum.
Ответ №1:
cast
Метод приводит значение из пользовательского ввода, когда оно присваивается экземпляру. В случае enum
когда вы присваиваете строковое значение, оно остается строковым значением. Оно преобразуется в целое число только тогда, когда оно сохраняется в базе данных.
class Order < ActiveRecord::Base
enum status: {confirmed: 1, cancelled: 2}
end
# this is where the `cast` method is called
@order.status = "cancelled"
# still a string since the `cast` method didn't do anything.
@order.status # => "cancelled"
Что вам действительно нужно, так это serialize
метод. Он преобразует значение из типа ruby в тип, который база данных знает, как понять.
Order.attribute_types["status"].serialize("cancelled") # => 2