【问题标题】:How can I mix Polymorphism and Inheritance in Rails(5.0.0.1)如何在 Rails(5.0.0.1) 中混合多态性和继承
【发布时间】:2017-04-27 23:39:48
【问题描述】:

我已经尝试了 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,因为我会丢失Course 内部拥有的列,例如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

【问题讨论】:

    标签: inheritance methods polymorphism associations polymorphic-associations


    【解决方案1】:

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

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

    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 中,课程将是一种内容类型。学生也将是一种内容。但永远,永远,永远不要说课程有内容。这在任何方面、形状或形式上都是不正确的。

    在 STI 中,Content 表将包含 Course 的所有列以及任何其他想要成为课程的表的所有列。对于本质上数据相同或几乎相同(似乎很多您描述的内容)并且您不想在所有子类中重复代码的资源,这是一种很好的做法。所有 STI 都可以在没有 STI 的情况下实现,只需在每个子类中重复父类代码即可。

    所以,简短的回答(有点晚了,不是吗?)。不,你不能做你想做的事。你可以

    1. 只需重复每个资源中的列(首次实现的首选方式,简单、快速且标准)
    2. 使用 STI 和 ONE TABLE 表示所有可能“共享”内容信息的资源
    3. 使用多态性和辅助方法来做你想做的事。但不要忘记访问器不是唯一的。想想诸如def title=之类的方法。你要重新实现所有这些吗?

    抱歉,这个错误已经看到太多次了。

    【讨论】:

      猜你喜欢
      • 2021-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多