Get rid of InternalHelpers, refactor scoped views for more performant behavior.

This commit is contained in:
José Valim
2012-01-02 22:01:28 +01:00
parent aa2d15aa33
commit d9df632671
10 changed files with 182 additions and 204 deletions

View File

@@ -2,7 +2,7 @@ class Devise::ConfirmationsController < DeviseController
# GET /resource/confirmation/new
def new
build_resource({})
render_with_scope :new
render :new
end
# POST /resource/confirmation
@@ -12,7 +12,7 @@ class Devise::ConfirmationsController < DeviseController
if successfully_sent?(resource)
respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
else
respond_with_navigational(resource){ render_with_scope :new }
respond_with_navigational(resource){ render :new }
end
end
@@ -25,7 +25,7 @@ class Devise::ConfirmationsController < DeviseController
sign_in(resource_name, resource)
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
else
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render_with_scope :new }
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
end
end

View File

@@ -4,7 +4,7 @@ class Devise::PasswordsController < DeviseController
# GET /resource/password/new
def new
build_resource({})
render_with_scope :new
render :new
end
# POST /resource/password
@@ -14,7 +14,7 @@ class Devise::PasswordsController < DeviseController
if successfully_sent?(resource)
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
else
respond_with_navigational(resource){ render_with_scope :new }
respond_with_navigational(resource){ render :new }
end
end
@@ -22,7 +22,7 @@ class Devise::PasswordsController < DeviseController
def edit
self.resource = resource_class.new
resource.reset_password_token = params[:reset_password_token]
render_with_scope :edit
render :edit
end
# PUT /resource/password
@@ -35,7 +35,7 @@ class Devise::PasswordsController < DeviseController
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
else
respond_with_navigational(resource){ render_with_scope :edit }
respond_with_navigational(resource){ render :edit }
end
end

View File

@@ -5,7 +5,7 @@ class Devise::RegistrationsController < DeviseController
# GET /resource/sign_up
def new
resource = build_resource({})
respond_with_navigational(resource){ render_with_scope :new }
respond_with_navigational(resource){ render :new }
end
# POST /resource
@@ -24,13 +24,13 @@ class Devise::RegistrationsController < DeviseController
end
else
clean_up_passwords(resource)
respond_with_navigational(resource) { render_with_scope :new }
respond_with_navigational(resource) { render :new }
end
end
# GET /resource/edit
def edit
render_with_scope :edit
render :edit
end
# PUT /resource
@@ -50,7 +50,7 @@ class Devise::RegistrationsController < DeviseController
respond_with resource, :location => after_update_path_for(resource)
else
clean_up_passwords(resource)
respond_with_navigational(resource){ render_with_scope :edit }
respond_with_navigational(resource){ render :edit }
end
end

View File

@@ -6,7 +6,7 @@ class Devise::SessionsController < DeviseController
def new
resource = build_resource
clean_up_passwords(resource)
respond_with_navigational(resource, stub_options(resource)){ render_with_scope :new }
respond_with_navigational(resource, stub_options(resource)){ render :new }
end
# POST /resource/sign_in

View File

@@ -4,7 +4,7 @@ class Devise::UnlocksController < DeviseController
# GET /resource/unlock/new
def new
build_resource({})
render_with_scope :new
render :new
end
# POST /resource/unlock
@@ -14,7 +14,7 @@ class Devise::UnlocksController < DeviseController
if successfully_sent?(resource)
respond_with({}, :location => new_session_path(resource_name))
else
respond_with_navigational(resource){ render_with_scope :new }
respond_with_navigational(resource){ render :new }
end
end
@@ -26,7 +26,7 @@ class Devise::UnlocksController < DeviseController
set_flash_message :notice, :unlocked if is_navigational_format?
respond_with_navigational(resource){ redirect_to new_session_path(resource) }
else
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render_with_scope :new }
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
end
end
end

View File

@@ -1,4 +1,169 @@
# All Devise controllers are inherited from here.
class DeviseController < Devise.parent_controller.constantize
include Devise::Controllers::InternalHelpers
include Devise::Controllers::ScopedViews
helper DeviseHelper
helpers = %w(resource scope_name resource_name signed_in_resource
resource_class devise_mapping devise_controller?)
hide_action *helpers
helper_method *helpers
prepend_before_filter :assert_is_devise_resource!
respond_to *Mime::SET.map(&:to_sym) if mimes_for_respond_to.empty?
# Gets the actual resource stored in the instance variable
def resource
instance_variable_get(:"@#{resource_name}")
end
# Proxy to devise map name
def resource_name
devise_mapping.name
end
alias :scope_name :resource_name
# Proxy to devise map class
def resource_class
devise_mapping.to
end
# Returns a signed in resource from session (if one exists)
def signed_in_resource
warden.authenticate(:scope => resource_name)
end
# Attempt to find the mapped route for devise based on request path
def devise_mapping
@devise_mapping ||= request.env["devise.mapping"]
end
# Overwrites devise_controller? to return true
def devise_controller?
true
end
protected
# Checks whether it's a devise mapped resource or not.
def assert_is_devise_resource! #:nodoc:
unknown_action! <<-MESSAGE unless devise_mapping
Could not find devise mapping for path #{request.fullpath.inspect}.
Maybe you forgot to wrap your route inside the scope block? For example:
devise_scope :user do
match "/some/route" => "some_devise_controller"
end
MESSAGE
end
# Returns real navigational formats which are supported by Rails
def navigational_formats
@navigational_formats ||= Devise.navigational_formats.select { |format| Mime::EXTENSION_LOOKUP[format.to_s] }
end
def unknown_action!(msg)
logger.debug "[Devise] #{msg}" if logger
raise ActionController::UnknownAction, msg
end
# Sets the resource creating an instance variable
def resource=(new_resource)
instance_variable_set(:"@#{resource_name}", new_resource)
end
# Build a devise resource.
def build_resource(hash=nil)
hash ||= params[resource_name] || {}
self.resource = resource_class.new(hash)
end
# Helper for use in before_filters where no authentication is required.
#
# Example:
# before_filter :require_no_authentication, :only => :new
def require_no_authentication
assert_is_devise_resource!
return unless is_navigational_format?
no_input = devise_mapping.no_input_strategies
authenticated = if no_input.present?
args = no_input.dup.push :scope => resource_name
warden.authenticate?(*args)
else
warden.authenticated?(resource_name)
end
if authenticated
resource = warden.user(resource_name)
flash[:alert] = I18n.t("devise.failure.already_authenticated")
redirect_to after_sign_in_path_for(resource)
end
end
# Helper for use after calling send_*_instructions methods on a resource.
# If we are in paranoid mode, we always act as if the resource was valid
# and instructions were sent.
def successfully_sent?(resource)
notice = if Devise.paranoid
resource.errors.clear
:send_paranoid_instructions
elsif resource.errors.empty?
:send_instructions
end
if notice
set_flash_message :notice, notice if is_navigational_format?
true
end
end
# Sets the flash message with :key, using I18n. By default you are able
# to setup your messages using specific resource scope, and if no one is
# found we look to default scope.
# Example (i18n locale file):
#
# en:
# devise:
# passwords:
# #default_scope_messages - only if resource_scope is not found
# user:
# #resource_scope_messages
#
# Please refer to README or en.yml locale file to check what messages are
# available.
def set_flash_message(key, kind, options={}) #:nodoc:
options[:scope] = "devise.#{controller_name}"
options[:default] = Array(options[:default]).unshift(kind.to_sym)
options[:resource_name] = resource_name
message = I18n.t("#{resource_name}.#{kind}", options)
flash[key] = message if message.present?
end
def clean_up_passwords(object) #:nodoc:
object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
end
def respond_with_navigational(*args, &block)
respond_with(*args) do |format|
format.any(*navigational_formats, &block)
end
end
def request_format
@request_format ||= request.format.try(:ref)
end
def is_navigational_format?
Devise.navigational_formats.include?(request.format.try(:ref))
end
# Override prefixes to consider the scoped view.
def _prefixes
@_prefixes ||= if self.class.scoped_views?
super.unshift("#{devise_mapping.scoped_path}/#{controller_name}")
else
super
end
end
end

View File

@@ -16,7 +16,6 @@ module Devise
module Controllers
autoload :Helpers, 'devise/controllers/helpers'
autoload :InternalHelpers, 'devise/controllers/internal_helpers'
autoload :Rememberable, 'devise/controllers/rememberable'
autoload :ScopedViews, 'devise/controllers/scoped_views'
autoload :UrlHelpers, 'devise/controllers/url_helpers'

View File

@@ -1,169 +0,0 @@
module Devise
module Controllers
# Those helpers are used only inside Devise controllers and should not be
# included in ApplicationController since they all depend on the url being
# accessed.
module InternalHelpers #:nodoc:
extend ActiveSupport::Concern
include Devise::Controllers::ScopedViews
included do
helper DeviseHelper
helpers = %w(resource scope_name resource_name signed_in_resource
resource_class devise_mapping devise_controller?)
hide_action *helpers
helper_method *helpers
prepend_before_filter :assert_is_devise_resource!
respond_to *Mime::SET.map(&:to_sym) if mimes_for_respond_to.empty?
end
# Gets the actual resource stored in the instance variable
def resource
instance_variable_get(:"@#{resource_name}")
end
# Proxy to devise map name
def resource_name
devise_mapping.name
end
alias :scope_name :resource_name
# Proxy to devise map class
def resource_class
devise_mapping.to
end
# Returns a signed in resource from session (if one exists)
def signed_in_resource
warden.authenticate(:scope => resource_name)
end
# Attempt to find the mapped route for devise based on request path
def devise_mapping
@devise_mapping ||= request.env["devise.mapping"]
end
# Overwrites devise_controller? to return true
def devise_controller?
true
end
protected
# Checks whether it's a devise mapped resource or not.
def assert_is_devise_resource! #:nodoc:
unknown_action! <<-MESSAGE unless devise_mapping
Could not find devise mapping for path #{request.fullpath.inspect}.
Maybe you forgot to wrap your route inside the scope block? For example:
devise_scope :user do
match "/some/route" => "some_devise_controller"
end
MESSAGE
end
# Returns real navigational formats which are supported by Rails
def navigational_formats
@navigational_formats ||= Devise.navigational_formats.select{ |format| Mime::EXTENSION_LOOKUP[format.to_s] }
end
def unknown_action!(msg)
logger.debug "[Devise] #{msg}" if logger
raise ActionController::UnknownAction, msg
end
# Sets the resource creating an instance variable
def resource=(new_resource)
instance_variable_set(:"@#{resource_name}", new_resource)
end
# Build a devise resource.
def build_resource(hash=nil)
hash ||= params[resource_name] || {}
self.resource = resource_class.new(hash)
end
# Helper for use in before_filters where no authentication is required.
#
# Example:
# before_filter :require_no_authentication, :only => :new
def require_no_authentication
assert_is_devise_resource!
return unless is_navigational_format?
no_input = devise_mapping.no_input_strategies
authenticated = if no_input.present?
args = no_input.dup.push :scope => resource_name
warden.authenticate?(*args)
else
warden.authenticated?(resource_name)
end
if authenticated
resource = warden.user(resource_name)
flash[:alert] = I18n.t("devise.failure.already_authenticated")
redirect_to after_sign_in_path_for(resource)
end
end
# Helper for use after calling send_*_instructions methods on a resource.
# If we are in paranoid mode, we always act as if the resource was valid
# and instructions were sent.
def successfully_sent?(resource)
notice = if Devise.paranoid
resource.errors.clear
:send_paranoid_instructions
elsif resource.errors.empty?
:send_instructions
end
if notice
set_flash_message :notice, notice if is_navigational_format?
true
end
end
# Sets the flash message with :key, using I18n. By default you are able
# to setup your messages using specific resource scope, and if no one is
# found we look to default scope.
# Example (i18n locale file):
#
# en:
# devise:
# passwords:
# #default_scope_messages - only if resource_scope is not found
# user:
# #resource_scope_messages
#
# Please refer to README or en.yml locale file to check what messages are
# available.
def set_flash_message(key, kind, options={}) #:nodoc:
options[:scope] = "devise.#{controller_name}"
options[:default] = Array(options[:default]).unshift(kind.to_sym)
options[:resource_name] = resource_name
message = I18n.t("#{resource_name}.#{kind}", options)
flash[key] = message if message.present?
end
def clean_up_passwords(object) #:nodoc:
object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
end
def respond_with_navigational(*args, &block)
respond_with(*args) do |format|
format.any(*navigational_formats, &block)
end
end
def request_format
@request_format ||= request.format.try(:ref)
end
def is_navigational_format?
Devise.navigational_formats.include?(request.format.try(:ref))
end
end
end
end

View File

@@ -12,22 +12,6 @@ module Devise
@scoped_views = value
end
end
protected
# Render a view for the specified scope. Turned off by default.
# Accepts just :controller as option.
def render_with_scope(action, path=self.controller_path)
if self.class.scoped_views?
begin
render :template => "#{devise_mapping.scoped_path}/#{path.split("/").last}/#{action}"
rescue ActionView::MissingTemplate
render :template => "#{path}/#{action}"
end
else
render :template => "#{path}/#{action}"
end
end
end
end
end

View File

@@ -1,7 +1,6 @@
require 'test_helper'
class MyController < ApplicationController
include Devise::Controllers::InternalHelpers
class MyController < DeviseController
end
class HelpersTest < ActionController::TestCase