如何在Rails中混合多态和继承(5.0.0.1)

时间:2016-12-13 00:59:49

标签: inheritance methods polymorphism associations polymorphic-associations

我一直试图找到一个解决方案2天就没有了。

我有一个名为Course的模型,其中包含以下列:

create_table :courses do |c|
  c.integer :member_limit
  c.string :color
  c.float :rating

  c.timestamps
end

我还有一个Content模型,其中Course的列受益,但也有益于我数据库中的其他模型,例如:

create_table :contents do |c|
    c.references :contentable, polymorphic: true, index: true
    c.string :title
    c.text :description
    c.text :script
    c.string :cover
    c.string :media_type
    ...
    c.integer :creator_id, index: true, foreign_key: :user_id
end    

我无法设置Course < Content,因为我会丢失课程内部的列,例如member_limit等等,所以我选择了Polymorphic。不过,我希望避免拨打course.content.title,只需撰写course.title,但也可以同样方式访问course.member_limit,并使用course.save保存这两个字段。

您建议采用哪种最佳方法?

目前的结构。

课程:

class Course < ApplicationRecord
    has_one :content, as: :contentable, dependent: :destroy

    after_initialize :init

    def init
      if self.new_record?
        self.content ||= build_content    
      end
    end
end

内容:

class Content < ApplicationRecord
   belongs_to :creator, optional: true, class_name: 'User'
end

1 个答案:

答案 0 :(得分:0)

我认为你的前提是错误的,因为不应该做你想做的事情。我解释一下:

你想要什么,可以通过这样的辅助方法来完成:

class Course < AR
  def title
    content.title
  end
end

哪个是丑陋的,违反了有史以来编写的所有编码论点,以及它的不良做法。但是,除了一些可以避免必须逐个编写辅助方法的元魔法(注意我说写,因为最终,它们将被实现),最终结果必须是这样的。没有其他办法可以做到这一点。所以我的答案是,不要这样做。

理解多态并不容易。它易于实现但很难知道何时。你想要一个包含几个其他资源的列的抽象框,因为。在创建“......内容模型,其中包含课程受益但也有益于我的数据库中的其他模型的内容模型”时,您没有给出任何理由。我问。为什么?有什么好处?为什么这样?它的运作和预期一样好吗?它更容易使用和扩展吗?它被封装了吗?它是干燥的,休息的,固体的,以及最近使用的所有其他首字母缩略词吗?

简短的回答是否定的。事实并非如此。所以不要这样做。让课程课程有标题。如果另一张桌子也有标题,那又怎样?你知道世界上有多少个表有“名称”栏吗?如果我们都希望以你的方式实现它,我们会有类似的东西:

class School < Ar
  belongs_to :name

  def full_name 
    name.body
  end
end

class Student < Ar
  belongs_to :name

  def full_name 
    name.body
  end
end

显然没用。因此,如果它对一列无用,为什么它对更多列有用呢?

结论:

  1. 多态性不用于重复使用列,从不。
  2. STI用于重复使用列(排序)
  3. 多态性可以理解为可以附加到多个资源的东西。如:通知,日志,地址......基本上说课程有地址,学生也有地址。学生和课程都可以解决。但从来没有,永远不要说内容是一种地址。这在任何方面,形状或形式都是不正确的。
  4. 在STI中,资源成为父类型,因此在STI中,课程将是A TYPE OF Content。学生也将是A TYPE OF Content。但从来没有,永远不要说课程有内容。这在任何方面,形状或形式都是不正确的。
  5. 在STI中,“内容”表中的所有列都将包含所有要成为课程的其他表的列。对于资源来说,这是一种很好的做法,基本上,数据是相同的或几乎(看起来很像你所描述的),并且你不想在所有子类中重复代码。通过在每个子类中重复父类代码,可以在没有STI的情况下实现所有STI。

    那么,简短的回答(有点晚了没有?)。不,你不能做你想做的事。你可以

    1. 只需重复每个资源中的列(第一个实现的优选方式,简单,快速和标准)
    2. 使用STI和ONE TABLE表示将“共享”内容信息的所有资源
    3. 使用多态并使用辅助方法来执行您想要的操作。但是不要忘记访问者不是唯一的访问者。考虑def title=等方法。你要重新实施所有这些吗?
    4. 对不起长度,只看到这个错误太多次了。