コピペコードで快適生活

明日使えるソースを自分のために

Rubyのinclude,extend,prepend,Concernの使い方メモ

なんとなく理解が怪しかったので復習をかねて。

includeだけでクラスメソッドとインスタンスメソッドを同時に追加する

module MyModule
  def self.included(base)
    base.extend(ClassMethods)
  end
 
  module ClassMethods
    def hogehoge
      puts 'hogehoge!'
    end
  end
 
  def fugafuga
    puts 'fugafuga'
  end
end

class TargetModel
  include MyModule

  # 略
end

・includeは、モジュールのメソッドをインスタンスメソッドとして追加する。
・extendは、レシーバ自身に対してメソッドを追加する。
 クラス.extend モジュール の場合はクラスメソッドとして
 インスタンス.extend モジュール の場合はインスタンスメソッドとして追加される。
・モジュールにincludedを定義しておくと、includeされたときに呼び出される。
 引数はincludeを行ったクラスやモジュール。

ActiveSupport::Concernを使う場合

require 'active_support/concern'
module ConsernModule
  extend ActiveSupport::Concern

  # インスタンスメソッドとして使える
  def hogehoge
    # do something
  end 

 # アクセサやscopeの定義はincludedの中で行う
  included do
    attr_accessor :fugafuga
    scope :favorites, -> { where(favirite_flag: true) }
  end

  # クラスメソッドの定義はclass_methodsの中で行う
  class_methods do
    def piyopiyo
      # do something
    end
  end

  # privateインスタンスメソッド
  private
  def wiblewible
    # do something
  end
end

class TargetModel
  include ConsernModule

  # 略
end

prependを使う

module TargetModelPatch
  def self.prepended(base)
    base.extend(ClassMethods)

    base.has_many :childrens
    base.scope :without_deleted, { where(deleted_at: nil) }
  end
 
  module ClassMethods
    def hogehoge
      puts 'hogehoge!'
    end
  end
 
  def fugafuga
    puts 'fugafuga'
  end
end

TargetModel.prepend TargetModelPatch

includeと基本的な動きは同じだけど、同じメソッドがあった場合はモジュール側のメソッドで上書きになる。
これは、prependが継承チェインの「先頭」にモジュールを差し込むため。
なお、includeの場合は取り込んだクラス側のメソッドが優先になる。


※参考にさせていただきました。
いつも忘れるRubyの include, prepend, extend の意味。そしてActiveSupport::Concernについても。 - Qiita
www.techscore.com