tapitapi’s blog

1日1杯タピオカ!エンジニア

【Ruby on Rails: cancancan】canの旅 (ソースコードリーディング)第五回

目指せ!ruby&railsマスター!

 

ということで、cancancanソースコードリーディング第五回はじめます。

 

前回まではコチラ

第一回第二回第三回第四回

 

前回はControllerResourceクラスのadd_before_actionの引数まで見ていきました!

 

今回はControllerResource.add_before_actionの内部を扱っていきます。

 

require_relative 'controller_resource_loader.rb'

 

module CanCan
 class ControllerResource # :nodoc:
  include ControllerResourceLoader

 

  def self.add_before_action(controller_class, method, *args)
   options = args.extract_options!
   resource_name = args.first
   before_action_method = before_callback_name(options)


   controller_class.send(before_action_method, options.slice(:only, :except, :if, :unless)) do |controller|


    controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except, :if, :unless)).send(method)

 

    end


   end

 

  def self.before_callback_name(options)
   options.delete(:prepend) ? :prepend_before_action : :before_action
  end

 

  def initialize(controller, *args)
   @controller = controller
   @params = controller.params
   @options = args.extract_options!
   @name = args.first
  end

 

  def load_and_authorize_resource
   load_resource
   authorize_resource
  end

 

 end

end

 

 *options = args.extract_options!

extract_options!で、optionsに、ハッシュで入った値が入ります。

qiita.com

 

下記の場合、:only => [:index, :show]がoptionsになりま-す!!

load_and_authorize_resource :only => [:index, :show]

 

*resource_name = args.first

resourvce_nameはargsの最初の要素。

下記の場合、:only => [:index, :show]がresource_name。

load_and_authorize_resource :only => [:index, :show] 

 

*before_action_method = before_callback_name(options)

before_callback_nameは下記。

options.delete(:prepend) ? :prepend_before_action : :before_action

つまり、optionsの中に:prependが入っていれば、before_action_method = :prepend_before_action。それ以外なら:before_action。

 

before_actionとprepend_before_actionの違いは下記が参考になれば。

tapitapi.hatenadiary.com

 

*controller_class.send(before_action_method, options.slice(:only, :except, :if, :unless)) do |controller| ~ end

 

出たー!なんでもありのsend method!! 

send methodを実行しているオブジェクト「controller_class」 は、load_and_authorize_resourceを実行したコントローラ(例えばUsers_controller など)になります!

send methodを使うことで、controller_classが実行できるmethod を全て実行できまするー!privateやprotected の意味、、、とも思いますが、ruby性善説に基づいて作られてる???Matz様は良い人なんだろな、、(勝手な予想)

 

第一引数のbefore_action_methodは:prepend_before_action または:before_action。実行したいmethodをシンボル(:   付きの文字列。文字列と思いきや、内部では数値なので処理が軽い)で指定します。

 

第二引数は、第一引数のmethodに渡す引数。

下記の場合、optionsには:only => [:index, :show], :except => [:edit, :create]がhashで入ってる。

load_and_authorize_resource :only => [:index, :show] , :except => [:edit, :create]

 

options.slice(:only, :except, :if, :unless)で、options内から、:only, :except, :if, :unlessのもののみ取り出す。

 

なんでdo ~ end文になってるかは分からないけど、:prepend_before_actionまたは:before_actionは実行後にコントローラの名前をarray で返すのかな??

 

*controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except, :if, :unless)).send(method)

 

controller.class.cancan_resource_class.newで、initialize が呼ばれて、

@controller = controller (Uses_controllerなど)
@params = controller.params (コントローラのparams. Users_controllerなら例えばname, ageなど)
@options = args.extract_options! (:only => [:index, :show]など)
@name = args.first (:only => [:index, :show]など)

がセットされます

 

send(method)で、methodには:load_and_authorize_resourceが入っているので、:load_and_authorize_resource が実行されます!

 

def load_and_authorize_resource
   load_resource
   authorize_resource
  end 

 

今日はここまでー!

次回はload_resourece methodを扱っていきます。

 

おやすみなさいいいいぃぃぃ