Concerns 在rails3已经支持,但是在Rails4中,它变得更加”official“。Concerns 或 Service Objects 是否是最好的办法存在着一些争议。DHH支持Concerns,但OO支持者倾向于选择Service Objects。我相信他们都有自己的存在意义,并且可以一起使用。

看个例子

选择一个ActiveRecord model 来看看这样提取的道理,刚开始,我为Concerns单独创建了validations, assocations, 和 accessors等验证,例如:

  # app/models/trader.rb
  class Trader
    include Accessors
    include Validations
    include Associations
    ...
  end

后来,我觉得这并不是很好的idea

1.如果我添加新的Trader行为,那我可能会需要改变一个以上的Concerns。
2.这样是不可取的,我要重用这些Concerns到别的model。

后来我试图根据 topic 区分代码,于是有了以下:

  # app/models/trader.rb
  class Trader
    include BasicInfo
    include FriendlyURL
    include Location
    include OpeningHours
    include Schedule
    include Permissions
  end

一般情况下,我认为一个Concerns应该在域概念之后被命名,我想上述是对的,也许除了FriendlyURL。
再来看一个Schedule concern的例子:

  # app/models/concerns/trader/schedule.rb
  class Trader
    module Schedule
      extend ActiveSupport::Concern
  
      included do
        attr_accessible :market_days_ids
  
        has_many :appearances
        has_many :market_days, :through => :appearances
      end
  
      def open?
        ...
      end
  
      def closed?
        ...
      end
    end
  end

像上面那样,它可以包括混合的validations, accessibilty, associations 以及 plain 方法,这是一个更好的方法来区分相关的功能。

共享Concerns

文档和看过的其他文章让我很模糊:Concerns之间如以共享多个model。比方说,有两个名称相同的Concerns:

app/models/concerns/schedule.rb
app/models/concerns/trader/schedule.rb

而model是这样:

  # app/models/trader.rb
  class Trader
    include Schedule
  end

这种情况下 Concerns在app/models/concerns/trader/schedule.rb的就被调用。
但是,如果Concerns被删除,model就会获取其他的Concerns了。也就是说,model会首先查找它自己的Concerns的直接路径 ,没有找到就会向它的顶层去找; 要证明共享Concerns,有一个更形象的方法:

  # app/models/trader.rb
  class Trader
    include Shared::Schedule
  end
  
  # app/models/concerns/shared/schedule.rb
  module Shared::Schedule
    extend ActiveSupport::Concern
    ...
  end

希望这对你也有帮助。

: 原文出自andywaite