Обновление ассоциаций AR через атрибуты _id не обновляет связанный объект (до проверки)

Допустим, у меня есть две модели ActiveRecord: LineItem и Article.

class LineItem < ActiveRecord::Base
  belongs_to :article
  ...
end

Я наблюдаю следующее поведение в LineItems (Rails 2.3.11):

>> l = LineItem.new
=> #<LineItem id: nil, article_id: nil, ...>
>> l.article_id=10
=> 10
>> l.article
=> #<Article id: 10, ...>
>> l.article_id=20
=> 20
>> l.article
=> #<Article id: 10, ...>

Таким образом, если article_id уже имеет значение, последующее изменение больше не меняет ассоциацию статьи. (По крайней мере, не сразу — только после сохранения ему будет присвоено новое значение.)

Это вызывает у меня проблемы в моем методе проверки при обновлении существующих LineItems. В моем LineItems-Controller я обновляю так:

def update
  @line_item = LineItem.find(params[:id])
  @line_item.attributes = params[:data] #params[:data] contains article_id
  ...      
  @line_item.save!
  ...
end

В моем классе LineItem у меня есть много таких проверок (упрощенных):

def validate
  if self.article.max_size < self.size
    errors.add_to_base("Too big for chosen article.")
  end
end

При обновлении эта проверка действует на «старую» статью, так как новая находится только в self.article_id (но не в self.article) на данный момент. Я мог бы заменить self.article на Article.find(self.article_id) в приведенном выше условии, но это не похоже на то, что должно быть.

Это ошибка в рельсах (2.3.11) или я что-то не так делаю? Большое спасибо.


person MichMech    schedule 06.09.2011    source источник


Ответы (1)


Это не ошибка, с которой вы столкнулись, а поведение кэша ассоциации AR. Вы можете принудительно перезагрузить ассоциацию во время проверки, передав true методу ассоциации: self.article(true).

Вы также можете очистить все кэшированные ассоциации для экземпляра LineItem, вызвав #clear_association_cache.

ОБНОВИТЬ:

На самом деле это была ошибка, но она была исправлена! (см. комментарий Алекса)

person Wizard of Ogz    schedule 06.09.2011
comment
Спасибо, это помогает. Примечания. Хотя передача значения true для ассоциации всегда работает, self.clear_association_cache не работает в приведенном выше примере irb, поскольку оно не действует на новые (несохраненные) записи. Но использование его в обратном вызове before_validation обычно должно быть в порядке. - person MichMech; 16.09.2011
comment
На самом деле это ошибка, довольно ужасная, которая сеет хаос в Интернете. Это исправлено в 3.1 или 3.2, но я часто сталкиваюсь с этим в 3.0 и некоторых более ранних версиях. Если на ассоциацию ссылаются до изменения _id (не редкость в фильтрах моделей), ассоциация не изменяется. - person Alex Neth; 28.09.2012