为什么Rails 5使用ApplicationRecord而不是ActiveRecord::Base?

72

我们知道Rails 5添加了ApplicationRecord作为一个抽象类,它被我们的模型(ActiveRecord)所继承。

但基本上,我认为我们使用ApplicationRecord完成的每个技术需求也同样可以使用ActiveRecord::Base来完成。例如:

module MyFeatures
  def do_something
    puts "Doing something"
  end
end

class ApplicationRecord < ActiveRecord::Base
  include MyFeatures
  self.abstract_class = true
end

现在每个模型都将附加MyFeatures的行为。但是我们也可以在Rails 4中实现这一点:

ActiveRecord::Base.include(MyFeatures)

那么使用ApplicationRecord有什么好处呢?你认为添加ApplicationRecord是必要的吗?

2个回答

90

在基本的Rails应用程序中可能看起来相同,但是一旦您开始使用rails引擎、插件/宝石或直接使用ActiveRecord::Base的方法,实际上存在一个重要的区别。

  • ActiveRecord::Base.include(MyFeatures)将功能直接混入ActiveRecord::Base中,它会一直存在于所有后续使用ActiveRecord::Base的代码中(无法“取消混合”),并且在混合之后再也没有任何方式来获取原始的ActiveRecord::Base。如果某些混合的功能更改了默认的ActiveRecord行为,或者例如两个引擎/宝石尝试包含同名方法,则这很容易导致问题。

  • 另一方面,ApplicationRecord方法使得这些功能仅适用于继承它们的类(模型),其他类以及直接使用ActiveRecord::Base都保持原样,不受模块功能的干扰。

当使用引擎或Rails插件时,这特别重要,因为它允许它们将自己的模型逻辑与主应用程序的模型逻辑分开,这在ApplicationRecord之前是不可能的。

所有这些内容在此博客文章此Github评论中也有很好的描述。


4
由于这个更改,每一个扩展ActiveRecord::Base的宝石现在都会出现问题吗?如果是这样的话,那将会产生大量的维护和技术债务。 - Kelsey Hannan
1
感谢BoraMa提供如此详细的答案,并提到博客链接。请务必访问博客链接,因为它通过示例非常清楚地解释了问题。作为Rails的新手,这对我非常有帮助。 - Dhrumil Panchal

11
这是对@BoraMa的答案的补充,并希望能够澄清一些关于ActiveRecord::Base.abstract_class的困惑。 ActiveRecord::Base.abstract_class 至少可以追溯到Rails 3.2.0(发布于2012年1月20日),具体可参考此链接:http://api.rubyonrails.org/v3.2.0/classes/ActiveRecord/Inheritance/ClassMethods.html
Rails 4.0.0改进了文档,具体可参考此链接:http://api.rubyonrails.org/v4.0.0/classes/ActiveRecord/Inheritance/ClassMethods.html
因此,对于认为ApplicationRecord是彻底新的人,请注意,它不是。这是一种改进,而不是破坏性的变化。没有添加任何东西到ActiveRecord::Base以使其工作。
我在一个使用UUID代替整数ID的Rails 4.2.6项目上也做了同样的事情,这需要更改默认的 ORDER BY。所以,我使用了一个UuidModel类和self.abstract_class = true来继承,而没有使用复制粘贴或关注(concern)。

我记得在 Rails 2.x 中有 abstract_class - skalee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接