#ruby_on_rails
Дело обстоит в Ruby on Rails 4.2.0 на Ruby 2.1.0. Есть следующая миграция: class CreateStateTemplates < ActiveRecord::Migration def change create_table :state_templates do |t| t.string :name t.references :next t.references :prev t.timestamps null: false end end end ...такая модель: class StateTemplate < ActiveRecord::Base has_one :prev, :class_name => "StateTemplate", :foreign_key => "prev_id" belongs_to :state_template, :class_name => "StateTemplate", :foreign_key => "prev_id" has_one :next, :class_name => "StateTemplate", :foreign_key => "next_id" belongs_to :state_template, :class_name => "StateTemplate", :foreign_key => "next_id" end Если выполнить следующее: StateTemplate.find(1).update(:next => StateTemplate.find(2)) StateTemplate.find(2).update(:next => StateTemplate.find(3), :prev => StateTemplate.find(1)) StateTemplate.find(3).update(:next => StateTemplate.find(4), :prev => StateTemplate.find(2)) StateTemplate.find(4).update(:next => StateTemplate.find(5), :prev => StateTemplate.find(3)) StateTemplate.find(5).update(:prev => StateTemplate.find(4)) Происходит нечто странное. Получение одного StateTemplate в консоли показывает следующее: 2.1.0 :007 > StateTemplate.find(2) StateTemplate Load (0.1ms) SELECT "state_templates".* FROM "state_templates" WHERE "state_templates"."id" = ? LIMIT 1 [["id", 2]] => #Что неверно, next_id должен быть 3. При этом метод next показывает следующее: 2.1.0 :008 > StateTemplate.find(2).next StateTemplate Load (0.1ms) SELECT "state_templates".* FROM "state_templates" WHERE "state_templates"."id" = ? LIMIT 1 [["id", 2]] StateTemplate Load (0.0ms) SELECT "state_templates".* FROM "state_templates" WHERE "state_templates"."next_id" = ? LIMIT 1 [["next_id", 2]] => # А это уже верно. Почему id в записи перепутаны местами, но получение ассоциированных записей при этом работает верно?
Ответы
Ответ 1
Потому что вы перепутали has_one и belongs_to. Для обеих сторон. К тому же, сейчас у вас дважды определена ассоциация state_template, работать будет только последнее из этих определений. Уже это указывает, что что-то с определениями не так. Посмотрим на next. Проблема тут: has_one :next, :class_name => "StateTemplate", :foreign_key => "next_id" belongs_to :state_template, :class_name => "StateTemplate", :foreign_key => "next_id" Это должно быть: belongs_to :next, :class_name => "StateTemplate" И симметрично для prev. Что происходит? Вы, наверное, думаете, что эти две строчки ведут себя примерно одинаково: StateTemplate.find(1).update(:next => StateTemplate.find(2)) StateTemplate.find(1).update(:next_id => 2) Но из ваших ассоциаций следует, что первая строчка изменяет второй объект (который в аргументе), ставя ему next_id = 1. Несмотря на то, что обновляете вы, казалось бы, первый. Вы неправильно определили ассоциацию next. Сейчас ассоциированный — объект, у которого next_id равен id владельца. Ибо has_one. А хотели вы наоборот: получить объект, id которого равен next_id владельца. Это belongs_to. Запись, которая хранит в себе ключ ассоциированного объекта, относится к нему через belongs_to. А вот has_one и has_many хранят ключ не "в себе", а в ассоциированных объектах. "Минус на минус даёт плюс". Апдейты сделали совсем не то, что вы подумали. И поиск ассоциированных записей работает не так, как вы хотите. Но оба пользуются одним определением и в сумме они работают верно: запись определённой записи в next действительно заставляет метод next у этого объекта возвращать эту запись.
Комментариев нет:
Отправить комментарий