Как заставить объект composed_of value обновляться или заново создавать себя при изменении его полей?

#ruby-on-rails #activerecord

#ruby-on-rails #activerecord

Вопрос:

Я работаю над приложением rails-2.3, которое использует composed_of для создания класса адресов, который, помимо прочего, знает, как геокодировать сам себя. Это все хорошо, но учитывая загруженную модель, у которой есть адрес, когда я изменяю поля, из которых состоит адрес в модели, экземпляр address не изменяется и не воссоздается автоматически, и, боюсь, я не могу придумать самый чистый способ принудительно заставить это произойти.

Код модели прост:

 class Model < ActiveRecord::Base

  composed_of :address, :mapping => [%w(address1 address1), %w(address2 address2), %w(city city), %w(state state), %w(postal_code postal_code), %w(country_code country), %w(longitude lng), %w(latitude lat)]

end
  

Есть предложения?

Впоследствии я ответил на это, но уже не могу ответить на свой собственный вопрос, так что вот:

Оказывается, composed_of создает метод reader, который имеет (недокументированный) параметр force_reload . Я пользуюсь этим и создаю методы доступа для каждого из составленных полей:

   composed_of :address, :mapping => ADDRESS_MAPPING                                                      
  ADDRESS_MAPPING.each do |field, composed_field|                                                        
    next if %w(latitude longitude).include?(field)                                                       
    define_method "#{field}=" do |value|                                                                 
      self[field] = value                                                                                
      if send("#{field}_changed?")                                                                       
        self[:longitude] = nil                                                                           
        self[:latitude] = nil                                                                            
        address(true)                                                                                    
      end                                                                                                
    end                                                                                                  
  end                                                                                                    
  

Это немного хитро, но это работает.

Я мог бы подумать о факторинге, который это изменило? проверьте в методе composed_of reader на основе.

Комментарии:

1. только что отредактировал свой ответ, мне нравятся вызовы 😉

Ответ №1:

Вы могли бы либо reload создать переменную вручную:

 @my_variable.reload
  

или сделайте так, чтобы это происходило в after_save обратном вызове (также в вашей модели).

Редактировать:

Вы могли бы сделать следующее:

 @my_variable.clear_aggregation_cache
  

(конечно, оберните это обратным вызовом)

Смотрите модуль ActiveRecord::Aggregations

Комментарии:

1. Хотя это довольно неэффективно. Это добавляет ненужный переход к базе данных только для воссоздания объекта value, состоящего из полей, которые уже есть в памяти. Я уверен, что могу сделать лучше, чем это.

2. Хорошо, давайте найдем что-нибудь получше!

Ответ №2:

Вы можете определить пользовательский конвертер, а затем напрямую назначить пользовательские данные атрибуту:address.