Модели с несколькими категориями против модели с одной категорией с STI? - Рельсы - PullRequest
1 голос
/ 16 мая 2019

У меня есть четыре модели:

  • Пост
  • Продукт
  • Артикул
  • Местоположение

Каждая изони могут иметь несколько категорий.Единственное логическое правило состоит в том, что категории полностью отделены для каждого класса, поэтому у публикации не может быть категории статей, у местоположения не может быть категории продуктов и т. Д.

Опция 1: несколько моделей категорий

Модели:

  • PostCategory
  • ProductCategory
  • ArticleCategory
  • LocationCategory

Модели для has_many:

  • PostCategorization
  • ProductCategorization
  • ArticleCategorization
  • LocationCategorization

Это работает, но этоне придерживается философии СУХОЙ (не повторяйся).Итак, как насчет использования STI?

Вариант 2: Модель одной категории с STI

Модели:

  • Категория
  • Категоризация

Подмодели:

  • PostCategory << Категория </li>
  • ProductCategory << Категория </li>
  • ArticleCategory << Категория </li>
  • LocationCategory << Категория </li>

Это кажется нормальным, но я не знаю, нужно ли мне даже использовать STI, если столбцы одинаковы, а логика одинакова.Единственная разница между ними заключается в ассоциациях.

Вариант 3: Модель одной категории без ИППП?

Было бы лучше иметь столбец "category_class" и выполнитьпримерно так:

class Post < ApplicationRecord

  has_many :categories, -> { where category_class: "Post" }

end

Чтобы сэкономить на количестве классов и подклассов и упростить все решение.Я использовал это раньше, но не с полиморфными ассоциациями, будет ли это работать?

Ответы [ 2 ]

2 голосов
/ 16 мая 2019

Возможно, я неправильно понимаю.Но, мне кажется ...

Вы можете использовать enum, чтобы указать, к какой категории относится каждая запись Category.Что-то вроде:

# == Schema Information
#
# Table name: categories
#
#  id                :integer          not null, primary key
#  name              :string           not null
#  categorizes       :integer          not null
#  created_at        :datetime         not null
#  updated_at        :datetime         not null
#
class Category < ApplicationRecord
  has_many :categorizations
  has_many :categorizeables, through: :categorizations

  enum categorizes: {
    post:         0,
    product:      1,
    article:      2,
    location:     3
  }

  class << self 

    def not_for(categorizeable_type)
      where.not(categorizes: categorizeable_type)
    end

  end

end

Затем вы можете использовать свою модель полиморфного соединения, Categorization Что-то вроде:

# == Schema Information
#
# Table name: categorizations
#
#  id                   :integer          not null, primary key
#  category_id          :integer          not null
#  categorizeable_id    :integer          not null
#  categorizeable_type  :string           not null
#  created_at           :datetime         not null
#  updated_at           :datetime         not null
#
class Categorization < ApplicationRecord
  belongs_to :category
  belongs_to :categorizeable, polymorphic: true
end

И затем вы можете связать свои categorizations и categoriesиспользуя has :many, through:

# == Schema Information
#
# Table name: posts
#
#  id                   :integer          not null, primary key
#  created_at           :datetime         not null
#  updated_at           :datetime         not null
#
class Post < ApplicationRecord
  has_many :categorizations, as: :categorizeable
  has_many :categories, through: :categorizations

  validate :correct_categorization

  def correct_categorization
    if categories.not_for(:post).any?
      errors.add(:categorization, "is incorrect")
    end
  end

end

Я добавил эту проверку, так как вы заявили, что «категории являются совершенно отдельными для каждого класса».Возможно, вам придется немного повозиться с этим, но, надеюсь, это даст вам представление о том, как это может работать.

1 голос
/ 16 мая 2019

Я думаю, что @jvillian сделал отличное предложение использовать enum в этом случае.Тем не менее, мне не особенно нравится правило проверки ... пользователь не должен видеть категории, которые не принадлежат объекту, который он пытается классифицировать.В этом случае я бы создал отношение с ограничением, поэтому я бы определил модель Post следующим образом:

class Post < ApplicationRecord
  has_many :categorizations, as: :categorizeable
  has_many :categories, -> { where(categorizes: 0)}, through: :categorizations
end

И построил ассоциацию через отношение has_many through:

f.association :categories
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...