Рельсовые ассоциации с полиморфизмом и абстрактными классами - PullRequest
1 голос
/ 12 июня 2019

Этот действительно заставляет меня чесать голову.Я работаю с полиморфными отношениями, связанными с несколькими классами, которые все наследуются от одного абстрактного класса.Это работает хорошо, но я сталкиваюсь с ошибкой, когда пытаюсь получить доступ к связанному объекту из полиморфных отношений.Вот моя реализация:

class Foo < ApplicationRecord
  belongs_to :options, polymorphic: true
  accepts_nested_attributes_for :options

  def build_options(params)
    self.options = options_type.constantize.new(params)
  end
end

module Mod
  class Option < ApplicationRecord
    self.abstract_class = true
    has_one :foo, as: :options

    self.table_name_prefix
      'foo_'
    end
  end

  class Bar < Options
  end

  class Baz < Options
  end
end

До сих пор это работало хорошо, но сейчас я сталкиваюсь с проблемой, когда пытаюсь что-то вроде этого:

Bar.first.foo

Я получаю эту ошибку:

ActiveRecord::AssociationNotFoundError (Association named 'foo' was not found on Foo::Bar; perhaps you misspelled it?)

Что делает меня странным, так это то, что если я позвоню Bar.first.methods, я получу :foo в качестве опции.

Любая идея, что мне нужно сделать, чтобыисправить это и все еще использовать наследование класса Options?Я знаю, что могу просто определить has_one на подклассах, но он применим ко всем дочерним элементам Options, и если я смогу сохранить связь там, я бы хотел.

Редактировать: Сюжетгустеет!Немного поиграв, я понял, что у НЕКОТОРЫХ дочерних классов ассоциация работает, а у некоторых нет.Я также не могу найти разницу между классами, которые работают, и теми, которые не работают.

Ответы [ 2 ]

1 голос
/ 20 июня 2019
# /app/models/user.rb
class User < ActiveRecord::Base
  has_one :profile, as: :profileable, dependent: :destroy
end

# /app/models/business.rb
class Business < ActiveRecord::Base
  has_one :profile, as: :profileable, dependent: :destroy
end

# /app/models/profile.rb
class Profile < ActiveRecord::Base
  belongs_to :profileable, polymorphic: true
end

см. Пример выше.

0 голосов
/ 19 июня 2019

У вас могут быть проблемы с перегибами, belongs_to должен быть одиночным, а не множественным (option вместо options). То же самое для has_one :foo, as: :options, который будет изменен на as: :option.

table_name_prefix здесь не обязательно, в STI все классы будут иметь одну и ту же таблицу.

Этот код не отображает проблему для меня:

# app/models/foo.rb
class Foo < ApplicationRecord
  belongs_to :option, polymorphic: true
end

# app/models/mod/option.rb
module Mod
  class Option < ApplicationRecord
    self.abstract_class = true
    has_one :foo, as: :option

    self.table_name = "mod_options"
  end
end

# app/models/mod/baz.rb
module Mod
  class Baz < Option
  end
end

# app/models/bar.rb
module Mod
  class Bar < Option
  end
end
...