devise_for

Deviseを使うとき、 routes.rbに書く devise_for が何をやっているか。

devse_for?

devise/rails/routes.rb の devise_for のコメント欄のところ

# Includes devise_for method for routes. This method is responsible to
# generate all needed routes for devise, based on what modules you have
# defined in your model.

モデル上でDeviseのモジュール設定をベースとして、routesの設定をする。

また、

devise/mapping.rb の先頭のコメント。

# Responsible for handling devise mappings and routes configuration. Each
 # resource configured by devise_for in routes is actually creating a mapping
 # object. You can refer to devise_for in routes for usage options.

devise_for の定義は、実質はDevise::Mapping のインスタンスを作成している。

mappingオブジェクト作った後に、 devise_scope を呼び出して、 devise_#{module name} を呼び出すことで、routesを定義している。

# devise_for メソッドの最下部で、devise_scope を呼び出している箇所。
devise_scope mapping.name do
  with_devise_exclusive_scope mapping.fullpath, mapping.name, options do
    routes.each { |mod| send("devise_#{mod}", mapping, mapping.controllers) }
  end
end

例えば、passwordモジュールのroutesは下記のように定義されてる

def devise_password(mapping, controllers) #:nodoc:
  resource :password, only: [:new, :create, :edit, :update],
    path: mapping.path_names[:password], controller: controllers[:passwords]
end

mappingオブジェクトの設定を元に resource の設定をしてる。

devise_scope?

devise_scope :resource_name &block で、ブロックにroutesを定義する処理を指定できる。

devise_for でモジュール毎の基本的な設定と各種オプションでの調整はできる。

devise_scope はもっと自由にroutesをカスタマイズするときに使うとのこと。

constraints (配下のネストされたルートに制約をかける処理)で request.env["devise.mapping"] に Devise.mappings[scoep]を設定して、

scope :resource_name に、上記で定義したroute情報を渡している

constraints の処理は、initializeのときではなく、実際に対象のrouteにアクセスがあったときに走るので、

deviseのroutesのリクエスト毎に request.env["devise.mapping"] にMapping情報を設定している(目的は謎。)

まとめ

Railsのroutes周りの仕組みをハックして、deviseの各モジュールで必要なroutesの設定を、簡単で、柔軟な形で行えるようにしているイメージ。