Тип вводит виртуальный атрибут модели ActiveRecord
У меня есть модель с некоторыми атрибутами и виртуальным атрибутом.
Этот виртуальный атрибут используется для создания флажка в форме создания.
class Thing < ActiveRecord::Base
attr_accessor :foo
attr_accessible :foo
end
Так как поле является флажком в форме, атрибут foo
получит значение '0'
или '1'
как значение. Я бы хотел, чтобы он был логическим из-за следующего кода:
class Thing < ActiveRecord::Base
attr_accessor :foo
attr_accessible :foo
before_validation :set_default_bar
private
def set_default_bar
self.bar = 'Hello' if foo
end
end
Проблема здесь в том, что условие будет истинным, даже если foo
'0'
. Я хотел бы использовать механизм кастомизации типа ActiveRecord, но единственное, что я нашел для этого, это следующее:
class Thing < ActiveRecord::Base
attr_reader :foo
attr_accessible :foo
before_validation :set_default_bar
def foo=(value)
@foo = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
private
def set_default_bar
self.bar = 'Hello' if foo
end
end
Но я чувствую себя грязным, делая это таким образом. Есть ли лучшая альтернатива без повторной записи метода преобразования?
Спасибо
Ответы
Ответ 1
Ваше решение из исходного сообщения выглядит как лучшее решение для меня.
class Thing < ActiveRecord::Base
attr_reader :foo
def foo=(value)
@foo = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
end
Если вы хотите немного почистить вещи, вы всегда можете создать вспомогательный метод, который определяет ваш метод записи foo=
для вас, используя value_to_boolean
.
Я бы, вероятно, создал модуль с методом под названием bool_attr_accessor
, чтобы упростить вашу модель следующим образом:
class Thing < ActiveRecord::Base
bool_attr_accessor :foo
end
Кажется, что ActiveModel должен предоставить нам что-то подобное, так что виртуальные атрибуты действуют скорее как "реальные" (ActiveRecord-persisted) атрибуты. Приведение этого типа важно, когда у вас есть логический виртуальный атрибут, который отправляется из формы.
Возможно, мы должны отправить патч Rails...
Ответ 2
В Rails 5 вы можете использовать метод attribute
. Этот метод определяет атрибут с типом в этой модели. При необходимости он переопределит тип существующих атрибутов.
class Thing < ActiveRecord::Base
attribute :foo, :boolean
end
Предупреждение: неправильное поведение этой функции attribute
в рельсах 5.0.0 для моделей, загружаемых из db. Поэтому используйте рельсы 5.0.1 или новее.
Ответ 3
Посмотрите validates_acceptance_of
код (нажмите Показать источник).
Они реализовали его по сравнению с "0".
Я использую его в формах регистрации таким образом:
class User < ActiveRecord::Base
validates_acceptance_of :terms_of_service
attr_accessible :terms_of_service
end
Если вам действительно нужна передача из строки и т.д., вы можете использовать это:
def foo=(value)
self.foo=(value == true || value==1 || value =~ (/(true|t|yes|y|1)$/i)) ? true:false
end
Или добавьте метод typecast для класса String
и используйте его в модели:
class String
def to_bool
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
end
end
Ответ 4
Почему вы этого не делаете:
def foo=(value)
@foo = value
@bar = 'Hello' if value == "1"
end