Concerns in Rails

作者:周星 发布:2017-09-20

自从 Rails4 开始,初始化项目时会默认在 controller 和 model 目录下生成 concerns 文件夹,concern 是一个有用且强大的概念,它可以减少我们的重复代码,让程序变得合理易维护,直接来看一个例子:

# app/models/post.rb
class Post < ActiveRecord::Base
  has_many :comments, as: :commentable

  def comments_by_user(id)
    comments.where(user_id: id)
  end
end

# app/models/image.rb
class Image < ActiveRecord::Base
  has_many :comments, as: :commentable

  def comments_by_user(id)
    comments.where(user_id: id)
  end
end

#app/models/comment.rb
class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end


这是一个很典型Rails关系模型中的多态,文章有很多评论,图片同时也可以有很多评论,从它们各自的 model 上可以看出它们有很多一样的代码,下面请 concern 开始它的表演:

#app/models/concerns/commentable.rb
module Commentable
  def self.included(base)
    base.class_eval do
      has_many :comments, as: :commentable
    end
  end

  def comments_by_user(id)
    comments.where(user_id: id)
  end
end

然后 Image 和 Post 模型引入这个 concern

# app/models/post.rb
class Post < ActiveRecord::Base
  include Commentable
end

# app/models/Image.rb
class Image < ActiveRecord::Base
  include Commentable
end


使用 ActiveSupport::Concern 可以让我们更容易的实现 mixin,重构上面的 commentable 模块

module Commentable  
  extend ActiveSupport::Concern

  included do
    has_many :comments, as: :commentable
  end

  def comments_by_user(id)
    comments.where(user_id: id)
  end
​end

同理,当多个 controller 复用同样的代码时,或者有公共逻辑可以提出去时,你也可以通过同样的方式把它们提到 concerns 里,concern 的命令习惯一般是 able 后缀,意为“可以被什么什么,有什么什么能力的”,当一个类 include 了这个 concern 后,说明这个类也拥有了这个能力。

注意,本文提到的 concern 和 ActiveSupport::Concern 是完全不一样的东西,不要混淆了,

Ruby 中的 mixin 和 ActiveSupport::Concern 的知识不在本文范围之内,Ruby 中的很多“魔法”都是它们产生的,比如 hook 等,这部分以后会单独拿出来谈。

支付宝扫码赞助博主


评论(0)