我有四个型号:
其中每个可以具有多个类别。唯一的逻辑规则是,每个类的类别完全分开,因此,帖子不能具有ArticleCategory,位置不能具有ProductCatgory,等等。
选项1:多个类别模型
型号:
has_many的模型通过:
这可行,但是不遵循DRY(不要重复自己)的哲学。那么,如何使用STI?
选项2:具有STI的单一类别模型
型号:
子模型:
这似乎很好,但是如果列相同并且逻辑相同,我不知道是否需要使用STI。它们之间的唯一区别是关联。
选项3:没有STI的单一类别模型?
最好有一个“ category_class”列,并执行以下操作:
class Post < ApplicationRecord
has_many :categories, -> { where category_class: "Post" }
end
节省类和子类的数量,并简化整个解决方案。我以前使用过此功能,但未在具有多态关联的功能上使用过,这行得通吗?
答案 0 :(得分:2)
也许我误会了。但是,在我看来...
您可以使用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 :(得分:1)
我认为@jvillian建议在这种情况下使用枚举。但是,我并不特别喜欢验证规则……用户不应看到不属于他尝试分类的对象的类别。在这种情况下,我将创建一个有范围的关系,因此我将像这样定义Post
模型:
class Post < ApplicationRecord
has_many :categorizations, as: :categorizeable
has_many :categories, -> { where(categorizes: 0)}, through: :categorizations
end
并通过关系has_many建立关联:
f.association :categories