У меня есть следующие классы в моей ActiveRecord модели:Rails: Инициализация атрибутов, которые зависят друг от друга
def Property < ActiveRecord::Base
# attribute: value_type (can hold values like :integer, :string)
end
def PropertyValue < ActiveRecord::Base
belongs_to property
# attribute: string_value
# attribute: integer_value
end
объект
PropertyValue предназначен для хранения только строковое значение или целое значение, в зависимости от типа , указанный в атрибуте value_type связанного объекта Property. Очевидно, что мы не должны беспокоить пользователя класса PropertyValue этим базовым механизмом string_value/integer_value. Поэтому я хотел бы использовать виртуальный атрибут «значение» на PropertyValue, что делает что-то вроде этого:
def value
unless property.nil? || property.value_type.nil?
read_attribute((property.value_type.to_s + "_value").to_sym)
end
end
def value=(v)
unless property.nil? || property.value_type.nil?
write_attribute((property.value_type.to_s + "_value").to_sym, v)
end
end
Я хочу предложить пользователю вид заполнить кучу значений свойств, а когда вид , я хотел бы, чтобы объекты PropertyValue создавались на основе списка атрибутов, передаваемых из представления. Для этого я использую операцию сборки (атрибутов). Однако теперь возникает проблема, что я не контролирую порядок, в котором происходит инициализация атрибута. Таким образом, присвоение атрибута value не будет работать, если ассоциация с атрибутом Property еще не была сделана, поскольку параметр value_type не может быть определен. Каков правильный способ «Rails» справиться с этим?
Кстати, в качестве обходного пути я попытался следующие:
def value=(v)
if property.nil? || property.value_type.nil?
@temp_value = v
else
write_attribute((property.value_type.to_s + "_value").to_sym, v)
end
end
def after_initialize
value = @temp_value
end
Помимо того, что я думаю, что это довольно уродливое решение, оно фактически не работает с операцией «строить». Значение @temp_value устанавливается в операции «value = (v)». Кроме того, «after_initialize» выполняется. Но «значение = @temp_value» не вызывает операцию «value = (v)» как ни странно! Поэтому я действительно застрял.
EDIT: код сборки Я действительно понял, что код для создания объектов Property был бы удобен. Я делаю это из класса Product, у которого есть ассоциация has_many с Property. Код будет выглядеть следующим образом:
def property_value_attributes=(property_value_attributes)
property_value_attributes.each do |attributes|
product_property_values.build(attributes)
end
end
В то же время я понял, что я сделал неправильно в операции after_initialize; следует читать:
def after_initialize
@value = @temp_value
end
Другая проблема состоит в том, что имущество объединения на новом объекте property_value никогда не будет установлен, пока фактическая не сохранить() имеет место, что после «after_initialize». Я получил это для работы, добавив value_type соответствующего объекта свойства в представление и затем передал его через атрибуты, установленные после сообщения. Таким образом, мне не нужно создавать экземпляр объекта Property только для получения значения value_type. Недостаток: мне нужен избыточный аксессуар «value_type» в классе PropertyValue.
Так оно работает, но меня все еще очень интересует, если есть более чистый способ сделать это. Еще один способ - убедиться, что объект свойства сначала привязан к новому PropertyValue, прежде чем инициализировать его другими атрибутами, но затем механизм просочится в «клиентский объект», который также не слишком чист.
Я ожидал бы некоторого способа переопределить функциональность инициализатора таким образом, чтобы я мог повлиять на порядок присвоения атрибутов. Что-то очень распространенное в таких языках, как C# или Java. Но в Rails ...?
Можете ли вы разместить свой код для создания PropertyValue? –