Обходной путь для AssociationTypeMismatch? - PullRequest
0 голосов
/ 07 мая 2019

Я нахожусь в процессе рефакторинга, где я написал новые модели для новых входящих данных, которые будут находиться за флагом функции, одновременно сохраняя старые модели активными для входящих данных для людей, у которых пока нет этой функции.флаг.Старая и новая модели взаимодействуют с одной и той же таблицей в базе данных.

т.е.


class Poem < ApplicationRecord
   belongs_to: :author
   belongs_to: :anthology, optional: true
end

class Anthology < ApplicationRecord
   belongs_to: :author
   has_many: :poems
end

class Author < ApplicationRecord
   has_many: :anthologies
   has_many: :poems
end


class NewPoem < ApplicationRecord
   self.table_name = 'poems'

   belongs_to: :author, class_name: 'NewAuthor'
   belongs_to: :anthology, class_name: 'NewAnthology', optional: true
end

class NewAnthology < ApplicationRecord
   self.table_name = 'anthologies'

   belongs_to: :author, class_name: 'NewAuthor'
   has_many: :poems, class_name: 'NewPoem'
end

class NewAuthor < ApplicationRecord
   self.table_name = 'authors'
   has_many: :anthologies, class_name: 'NewAnthology'
   has_many: :poems, class_name: 'NewPoem'
end

Когда у меня создаются новые книги, я хочу назначить новую книгу автору

anthology = Anthology.find(1)
@poem = NewPoem.new
@poem.author = anthology.author

Что дает мне ошибку

ActiveRecord::AssociationTypeMismatch (NewAuthor(#70008442274840) expected, got Author(#47031421032620)):

Есть ли способ обойти это?или я не смогу связать модели со старыми моделями без переноса данных?

Ответы [ 3 ]

0 голосов
/ 07 мая 2019

Похоже, что новые модели - это просто надмножества старых. Вы можете определить NewPoem (и остальные новые модели) как:

class NewPoem < Poem
  validates :new_colums

  def new_cool_stuff
  end
end

Таким образом, вы можете избежать переопределения ассоциаций.

0 голосов
/ 08 мая 2019

ActiveRecord на самом деле имеет встроенный механизм наследования отдельных таблиц, который вы можете использовать здесь.

Начните с добавления столбца с именем type в таблицу:

class AddTypeToPoems < ActiveRecord::Migration[5.2]
  def change
    add_column :poems, :type, :string
    add_index :poems, :type
  end
end

Затем установите классы для наследования:

class Poem < ApplicationRecord
end

class NewPoem < Poem
  # gets its table name from the parent class
end

ActiveRecord автоматически устанавливает столбец type и даже использует его при извлечении записей:

irb(main):001:0> NewPoem.create
   (0.3ms)  BEGIN
  NewPoem Create (1.3ms)  INSERT INTO "poems" ("created_at", "updated_at", "type") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", "2019-05-08 19:17:45.086947"], ["updated_at", "2019-05-08 19:17:45.086947"], ["type", "NewPoem"]]
   (0.7ms)  COMMIT
=> #<NewPoem id: 1, title: nil, created_at: "2019-05-08 19:17:45", updated_at: "2019-05-08 19:17:45", type: "NewPoem">
irb(main):002:0> Poem.first
  Poem Load (0.7ms)  SELECT  "poems".* FROM "poems" ORDER BY "poems"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<NewPoem id: 1, title: nil, created_at: "2019-05-08 19:17:45", updated_at: "2019-05-08 19:17:45", type: "NewPoem">
irb(main):003:0> 

Таким образом, даже если мы используем Poem.first, он создает экземпляр NewPoem из результата. Если вы используете искатели на рельсах подклассов, они автоматически прицеливаются:

irb(main):003:0> NewPoem.all
  NewPoem Load (1.8ms)  SELECT  "poems".* FROM "poems" WHERE "poems"."type" IN ('NewPoem') LIMIT $1  [["LIMIT", 11]]

Если вам нужен только «старый» тип, который вам нужно использовать:

Poem.where(type: [nil, 'Poem'])
0 голосов
/ 07 мая 2019

Вам нужно изменить первую строку, которая выбирает запись Anthology. В настоящее время он получает запись модели Anthology как anthology = Anthology.find(1). Тем не менее, эта модель относится к старой модели Author.
В следующей строке @poem = NewPoem.new создает экземпляр объекта модели NewPoem, а в следующей строке пытается назначить ему автора. Тем не менее, @poem.author будет объектом класса NewAuthor, но ему присваивается значение @poem.author = anthology.author, где anthology.author по-прежнему ссылается на старую таблицу Author.

Изменение первой строки на anthology = NewAnthology.find(1) решит проблему. Он получит ту же запись, что и Anthology.find(1), поскольку они запрашивают одну и ту же таблицу.
Общий код становится:

anthology = NewAnthology.find(1)
@poem = NewPoem.new
@poem.author = anthology.author
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...