Rails3: невозможно обновить атрибут без первой перезагрузки записи при динамическом создании родителя - PullRequest
1 голос
/ 02 апреля 2011

Сводка

Если City имеет много Locations (ассоциация HABTM), создайте дочернюю запись, например:

a = Location.create(:name=>'Site 1', :city => City.create(:name=>'A City'))

Проблема: a.city_id нельзя изменить в базе данных, пока не будет перезагружен файл.Пример:

a.city_id = 99
a.save  # => true
a.city_id # => 11

Подробности

class City < ActiveRecord::Base
  has_many :locations
end

class Location < ActiveRecord::Base
  belongs_to :city
end

a = Location.create(:name=>'Site 1', :city => City.create(:name=>'A City'))
# Create a record manually for comparison
b = Location.create(:name=>a.name, :city_id=>a.city_id)

a.city_id = 99
a.save  # => true
b.city_id = 99
b.save  # => true

a.city_id # => 11
b.city_id # => 99

И a, и b выглядят одинаково при создании, но ведут себя по-разному.Хотя a отображается как действительное после изменения city_id и успешно сохраняется, city_id не изменяется.

Однако, если запись a перезагружается до ее изменения,изменить «работает»:

a = Location.create(:name=>'Site 1', :city => City.create(:name=>'A City'))
a.reload 
a.city_id = 99
a.save
a.city_id # => 99

Это может показаться довольно загадочным, поскольку сначала можно просто создать родительский объект, но я обнаружил проблему с помощью FactoryGirl,

factory :city do   
  name 'Jos'
end

factory :location do
  name 'Site 1'
  city { |a| a.association :city }
end

Factory (:location) показывает то же поведение с неизменным :city_id, пока он не будет перезагружен из базы данных.Прошло много времени, прежде чем я понял, что происходит, почему мои тесты провалились из-за того, что изменения не произошли, как я ожидал.

Из проверки нового location я вижу, что он содержит целый объект city, а после перезагрузки его нет, так что это должно быть ключом, но что именно здесь происходит?Разумно ли ожидать, что FactoryGirl автоматически перезагрузит объект перед возвратом, или это что-то сломает?Конечно, я мог бы сделать это с помощью обратного вызова, но меня интересует простота.

(Если вам интересно, почему я просто не говорю location.city = new_city, а не location.city_id = 99, это потому, что я писал тест и хотел создать «бесхозные» записи с недействительными ссылками.)

...