mirror of
https://github.com/heartcombo/devise.git
synced 2022-11-09 12:18:31 -05:00
Merge branch 'master' into lm-rails-4-2
This commit is contained in:
commit
8482e485d1
26 changed files with 358 additions and 23 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -1,7 +1,16 @@
|
|||
### Unreleased
|
||||
|
||||
* enhancements
|
||||
* bug fixes
|
||||
* The Simple Form templates follow the same change from 3.3.0 by using `Log in` and adding
|
||||
a hint about the minimum password length when `validatable` is enabled (by @aried3r)
|
||||
* Remove reloading of routes when eager loading is enabled. This change was added during Rails 3 and it doesn't seem to be relevant to currently supported Rails versions (by @fgro)
|
||||
* Controller generator added as `devise:controllers SCOPE`. You can use the `-c` flag
|
||||
to pick which controllers (`unlocks`, `confirmations`, etc) you want to generate. (by @Chun-Yang)
|
||||
* bug fix
|
||||
* Fixed a regression where the devise generator would fail with a `ConnectionNotEstablished`
|
||||
exception when executed inside a mountable engine
|
||||
* Ensure to return symbols in find_scope! fixing a previous regression from 3.3.0 (by @micat)
|
||||
* Ensure all causes of failed login have the same error message (by @pjungwir)
|
||||
|
||||
### 3.3.0
|
||||
|
||||
|
|
18
README.md
18
README.md
|
@ -186,7 +186,7 @@ When you customize your own views, you may end up adding new attributes to forms
|
|||
|
||||
There are just three actions in Devise that allows any set of parameters to be passed down to the model, therefore requiring sanitization. Their names and the permitted parameters by default are:
|
||||
|
||||
* `sign_in` (`Devise::SessionsController#new`) - Permits only the authentication keys (like `email`)
|
||||
* `sign_in` (`Devise::SessionsController#create`) - Permits only the authentication keys (like `email`)
|
||||
* `sign_up` (`Devise::RegistrationsController#create`) - Permits authentication keys plus `password` and `password_confirmation`
|
||||
* `account_update` (`Devise::RegistrationsController#update`) - Permits authentication keys plus `password`, `password_confirmation` and `current_password`
|
||||
|
||||
|
@ -282,15 +282,25 @@ rails generate devise:views -v registrations confirmations
|
|||
|
||||
If the customization at the views level is not enough, you can customize each controller by following these steps:
|
||||
|
||||
1. Create your custom controller, for example a `Admins::SessionsController`:
|
||||
1. Create your custom controllers using the generator which requires a scope:
|
||||
|
||||
```console
|
||||
rails generate devise:controllers [scope]
|
||||
```
|
||||
|
||||
If you specify `admins` as the scope, controllers will be created in `app/controllers/admins/`.
|
||||
And the sessions controller will look like this:
|
||||
|
||||
```ruby
|
||||
class Admins::SessionsController < Devise::SessionsController
|
||||
# GET /resource/sign_in
|
||||
# def new
|
||||
# super
|
||||
# end
|
||||
...
|
||||
end
|
||||
```
|
||||
|
||||
Note that in the above example, the controller needs to be created in the `app/controllers/admins/` directory.
|
||||
|
||||
2. Tell the router to use this controller:
|
||||
|
||||
```ruby
|
||||
|
|
|
@ -12,7 +12,7 @@ en:
|
|||
invalid: "Invalid email or password."
|
||||
locked: "Your account is locked."
|
||||
last_attempt: "You have one more attempt before your account is locked."
|
||||
not_found_in_database: "Invalid email address or password."
|
||||
not_found_in_database: "Invalid email or password."
|
||||
timeout: "Your session expired. Please sign in again to continue."
|
||||
unauthenticated: "You need to sign in or sign up before continuing."
|
||||
unconfirmed: "You have to confirm your email address before continuing."
|
||||
|
|
|
@ -33,7 +33,7 @@ module Devise
|
|||
def self.find_scope!(obj)
|
||||
case obj
|
||||
when String, Symbol
|
||||
return obj
|
||||
return obj.to_sym
|
||||
when Class
|
||||
Devise.mappings.each_value { |m| return m.name if obj <= m.to }
|
||||
else
|
||||
|
|
|
@ -10,9 +10,6 @@ module Devise
|
|||
Devise.warden_config = config
|
||||
end
|
||||
|
||||
# Force routes to be loaded if we are doing any eager load.
|
||||
config.before_eager_load { |app| app.reload_routes! }
|
||||
|
||||
initializer "devise.url_helpers" do
|
||||
Devise.include_helpers(Devise::Controllers)
|
||||
end
|
||||
|
|
|
@ -36,7 +36,6 @@ module Devise
|
|||
result = resource && resource.valid_for_authentication?(&block)
|
||||
|
||||
if result
|
||||
decorate(resource)
|
||||
true
|
||||
else
|
||||
if resource
|
||||
|
@ -47,7 +46,7 @@ module Devise
|
|||
end
|
||||
|
||||
# Get values from params and set in the resource.
|
||||
def decorate(resource)
|
||||
def remember_me(resource)
|
||||
resource.remember_me = remember_me? if resource.respond_to?(:remember_me=)
|
||||
end
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ module Devise
|
|||
encrypted = false
|
||||
|
||||
if validate(resource){ encrypted = true; resource.valid_password?(password) }
|
||||
remember_me(resource)
|
||||
resource.after_database_authentication
|
||||
success!(resource)
|
||||
end
|
||||
|
|
|
@ -25,15 +25,18 @@ module Devise
|
|||
end
|
||||
|
||||
if validate(resource)
|
||||
remember_me(resource)
|
||||
extend_remember_me_period(resource)
|
||||
success!(resource)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def decorate(resource)
|
||||
super
|
||||
resource.extend_remember_period = mapping.to.extend_remember_period if resource.respond_to?(:extend_remember_period=)
|
||||
def extend_remember_me_period(resource)
|
||||
if resource.respond_to?(:extend_remember_period=)
|
||||
resource.extend_remember_period = mapping.to.extend_remember_period
|
||||
end
|
||||
end
|
||||
|
||||
def remember_me?
|
||||
|
|
|
@ -83,7 +83,8 @@ RUBY
|
|||
end
|
||||
|
||||
def postgresql?
|
||||
ActiveRecord::Base.connection.adapter_name.downcase == "postgresql"
|
||||
config = ActiveRecord::Base.configurations[Rails.env]
|
||||
config && config['adapter'] == 'postgresql'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
44
lib/generators/devise/controllers_generator.rb
Normal file
44
lib/generators/devise/controllers_generator.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
require 'rails/generators/base'
|
||||
|
||||
module Devise
|
||||
module Generators
|
||||
class ControllersGenerator < Rails::Generators::Base
|
||||
CONTROLLERS = %w(confirmations passwords registrations sessions unlocks omniauth_callbacks).freeze
|
||||
|
||||
desc <<-DESC.strip_heredoc
|
||||
Create inherited Devise controllers in your app/controllers folder.
|
||||
|
||||
User -c to specify which controller you want to overwrite.
|
||||
If you do no specify a controller, all controllers will be created.
|
||||
For example:
|
||||
|
||||
rails generate devise:controllers users -c=sessions
|
||||
|
||||
This will create a controller class at app/controllers/users/sessions_controller.rb like this:
|
||||
|
||||
class Users::ConfirmationsController < Devise::ConfirmationsController
|
||||
content...
|
||||
end
|
||||
DESC
|
||||
|
||||
source_root File.expand_path("../../templates/controllers", __FILE__)
|
||||
argument :scope, required: true,
|
||||
desc: "The scope to create controllers in, e.g. users, admins"
|
||||
class_option :controllers, aliases: "-c", type: :array,
|
||||
desc: "Select specific controllers to generate (#{CONTROLLERS.join(', ')})"
|
||||
|
||||
def create_controllers
|
||||
@scope_prefix = scope.blank? ? '' : (scope.camelize + '::')
|
||||
controllers = options[:controllers] || CONTROLLERS
|
||||
controllers.each do |name|
|
||||
template "#{name}_controller.rb",
|
||||
"app/controllers/#{scope}/#{name}_controller.rb"
|
||||
end
|
||||
end
|
||||
|
||||
def show_readme
|
||||
readme "README" if behavior == :invoke
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
14
lib/generators/templates/controllers/README
Normal file
14
lib/generators/templates/controllers/README
Normal file
|
@ -0,0 +1,14 @@
|
|||
===============================================================================
|
||||
|
||||
Some setup you must do manually if you haven't yet:
|
||||
|
||||
Ensure you have overridden routes for generated controllers in your route.rb.
|
||||
For example:
|
||||
|
||||
Rails.application.routes.draw do
|
||||
devise_for :users, controllers: {
|
||||
sessions: 'sessions'
|
||||
}
|
||||
end
|
||||
|
||||
===============================================================================
|
|
@ -0,0 +1,28 @@
|
|||
class <%= @scope_prefix %>ConfirmationsController < Devise::ConfirmationsController
|
||||
# GET /resource/confirmation/new
|
||||
# def new
|
||||
# super
|
||||
# end
|
||||
|
||||
# POST /resource/confirmation
|
||||
# def create
|
||||
# super
|
||||
# end
|
||||
|
||||
# GET /resource/confirmation?confirmation_token=abcdef
|
||||
# def show
|
||||
# super
|
||||
# end
|
||||
|
||||
# protected
|
||||
|
||||
# The path used after resending confirmation instructions.
|
||||
# def after_resending_confirmation_instructions_path_for(resource_name)
|
||||
# super(resource_name)
|
||||
# end
|
||||
|
||||
# The path used after confirmation.
|
||||
# def after_confirmation_path_for(resource_name, resource)
|
||||
# super(resource_name, resource)
|
||||
# end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
class <%= @scope_prefix %>OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
# You should configure your model like this:
|
||||
# devise :omniauthable, omniauth_providers: [:twitter]
|
||||
|
||||
# You should also create an action method in this controller like this:
|
||||
# def twitter
|
||||
# end
|
||||
|
||||
# More info at:
|
||||
# https://github.com/plataformatec/devise#omniauth
|
||||
|
||||
# GET|POST /resource/auth/twitter
|
||||
# def passthru
|
||||
# super
|
||||
# end
|
||||
|
||||
# GET|POST /users/auth/twitter/callback
|
||||
# def failure
|
||||
# super
|
||||
# end
|
||||
|
||||
# protected
|
||||
|
||||
# The path used when omniauth fails
|
||||
# def after_omniauth_failure_path_for(scope)
|
||||
# super(scope)
|
||||
# end
|
||||
end
|
32
lib/generators/templates/controllers/passwords_controller.rb
Normal file
32
lib/generators/templates/controllers/passwords_controller.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
class <%= @scope_prefix %>PasswordsController < Devise::PasswordsController
|
||||
# GET /resource/password/new
|
||||
# def new
|
||||
# super
|
||||
# end
|
||||
|
||||
# POST /resource/password
|
||||
# def create
|
||||
# super
|
||||
# end
|
||||
|
||||
# GET /resource/password/edit?reset_password_token=abcdef
|
||||
# def edit
|
||||
# super
|
||||
# end
|
||||
|
||||
# PUT /resource/password
|
||||
# def update
|
||||
# super
|
||||
# end
|
||||
|
||||
# protected
|
||||
|
||||
# def after_resetting_password_path_for(resource)
|
||||
# super(resource)
|
||||
# end
|
||||
|
||||
# The path used after sending reset password instructions
|
||||
# def after_sending_reset_password_instructions_path_for(resource_name)
|
||||
# super(resource_name)
|
||||
# end
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
class <%= @scope_prefix %>RegistrationsController < Devise::RegistrationsController
|
||||
# before_filter :configure_sign_up_params, only: [:create]
|
||||
# before_filter :configure_account_update_params, only: [:update]
|
||||
|
||||
# GET /resource/sign_up
|
||||
# def new
|
||||
# super
|
||||
# end
|
||||
|
||||
# POST /resource
|
||||
# def create
|
||||
# super
|
||||
# end
|
||||
|
||||
# GET /resource/edit
|
||||
# def edit
|
||||
# super
|
||||
# end
|
||||
|
||||
# PUT /resource
|
||||
# def update
|
||||
# super
|
||||
# end
|
||||
|
||||
# DELETE /resource
|
||||
# def destroy
|
||||
# super
|
||||
# end
|
||||
|
||||
# GET /resource/cancel
|
||||
# Forces the session data which is usually expired after sign
|
||||
# in to be expired now. This is useful if the user wants to
|
||||
# cancel oauth signing in/up in the middle of the process,
|
||||
# removing all OAuth session data.
|
||||
# def cancel
|
||||
# super
|
||||
# end
|
||||
|
||||
# protected
|
||||
|
||||
# You can put the params you want to permit in the empty array.
|
||||
# def configure_sign_up_params
|
||||
# devise_parameter_sanitizer.for(:sign_up) << :attribute
|
||||
# end
|
||||
|
||||
# You can put the params you want to permit in the empty array.
|
||||
# def configure_account_update_params
|
||||
# devise_parameter_sanitizer.for(:account_update) << :attribute
|
||||
# end
|
||||
|
||||
# The path used after sign up.
|
||||
# def after_sign_up_path_for(resource)
|
||||
# super(resource)
|
||||
# end
|
||||
|
||||
# The path used after sign up for inactive accounts.
|
||||
# def after_inactive_sign_up_path_for(resource)
|
||||
# super(resource)
|
||||
# end
|
||||
end
|
25
lib/generators/templates/controllers/sessions_controller.rb
Normal file
25
lib/generators/templates/controllers/sessions_controller.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
class <%= @scope_prefix %>SessionsController < Devise::SessionsController
|
||||
# before_filter :configure_sign_in_params, only: [:create]
|
||||
|
||||
# GET /resource/sign_in
|
||||
# def new
|
||||
# super
|
||||
# end
|
||||
|
||||
# POST /resource/sign_in
|
||||
# def create
|
||||
# super
|
||||
# end
|
||||
|
||||
# DELETE /resource/sign_out
|
||||
# def destroy
|
||||
# super
|
||||
# end
|
||||
|
||||
# protected
|
||||
|
||||
# You can put the params you want to permit in the empty array.
|
||||
# def configure_sign_in_params
|
||||
# devise_parameter_sanitizer.for(:sign_in) << :attribute
|
||||
# end
|
||||
end
|
28
lib/generators/templates/controllers/unlocks_controller.rb
Normal file
28
lib/generators/templates/controllers/unlocks_controller.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
class <%= @scope_prefix %>UnlocksController < Devise::UnlocksController
|
||||
# GET /resource/unlock/new
|
||||
# def new
|
||||
# super
|
||||
# end
|
||||
|
||||
# POST /resource/unlock
|
||||
# def create
|
||||
# super
|
||||
# end
|
||||
|
||||
# GET /resource/unlock?unlock_token=abcdef
|
||||
# def show
|
||||
# super
|
||||
# end
|
||||
|
||||
# protected
|
||||
|
||||
# The path used after sending unlock password instructions
|
||||
# def after_sending_unlock_instructions_path_for(resource)
|
||||
# super(resource)
|
||||
# end
|
||||
|
||||
# The path used after unlocking the resource
|
||||
# def after_unlock_path_for(resource)
|
||||
# super(resource)
|
||||
# end
|
||||
end
|
|
@ -65,7 +65,7 @@ Devise.setup do |config|
|
|||
# :database = Support basic authentication with authentication key + password
|
||||
# config.http_authenticatable = false
|
||||
|
||||
# If http headers should be returned for AJAX requests. True by default.
|
||||
# If 401 status code should be returned for AJAX requests. True by default.
|
||||
# config.http_authenticatable_on_xhr = true
|
||||
|
||||
# The realm used in Http Basic Authentication. 'Application' by default.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<div class="form-inputs">
|
||||
<%= f.input :email, required: true, autofocus: true %>
|
||||
<%= f.input :password, required: true %>
|
||||
<%= f.input :password, required: true, hint: ("#{@minimum_password_length} characters minimum" if @validatable) %>
|
||||
<%= f.input :password_confirmation, required: true %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<h2>Sign in</h2>
|
||||
<h2>Log in</h2>
|
||||
|
||||
<%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
|
||||
<div class="form-inputs">
|
||||
|
@ -8,7 +8,7 @@
|
|||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<%= f.button :submit, "Sign in" %>
|
||||
<%= f.button :submit, "Log in" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -13,6 +13,12 @@ class RoutesTest < ActionController::TestCase
|
|||
assert_equal @controller.send(:"#{prepend_path}#{name}_url", :user),
|
||||
send(:"#{prepend_path}user_#{name}_url")
|
||||
|
||||
# With string
|
||||
assert_equal @controller.send(:"#{prepend_path}#{name}_path", "user"),
|
||||
send(:"#{prepend_path}user_#{name}_path")
|
||||
assert_equal @controller.send(:"#{prepend_path}#{name}_url", "user"),
|
||||
send(:"#{prepend_path}user_#{name}_url")
|
||||
|
||||
# Default url params
|
||||
assert_equal @controller.send(:"#{prepend_path}#{name}_path", :user, param: 123),
|
||||
send(:"#{prepend_path}user_#{name}_path", param: 123)
|
||||
|
|
48
test/generators/controllers_generator_test.rb
Normal file
48
test/generators/controllers_generator_test.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
require "test_helper"
|
||||
|
||||
class ControllersGeneratorTest < Rails::Generators::TestCase
|
||||
tests Devise::Generators::ControllersGenerator
|
||||
destination File.expand_path("../../tmp", __FILE__)
|
||||
setup :prepare_destination
|
||||
|
||||
test "Assert no controllers are created with no params" do
|
||||
run_generator
|
||||
assert_no_file "app/controllers/sessions_controller.rb"
|
||||
assert_no_file "app/controllers/registrations_controller.rb"
|
||||
assert_no_file "app/controllers/confirmations_controller.rb"
|
||||
assert_no_file "app/controllers/passwords_controller.rb"
|
||||
assert_no_file "app/controllers/unlocks_controller.rb"
|
||||
assert_no_file "app/controllers/omniauth_callbacks_controller.rb"
|
||||
end
|
||||
|
||||
test "Assert all controllers are properly created with scope param" do
|
||||
run_generator %w(users)
|
||||
assert_class_names 'users'
|
||||
|
||||
run_generator %w(admins)
|
||||
assert_class_names 'admins'
|
||||
end
|
||||
|
||||
test "Assert specified controllers with scope" do
|
||||
run_generator %w(users -c sessions)
|
||||
assert_file "app/controllers/users/sessions_controller.rb"
|
||||
assert_no_file "app/controllers/users/registrations_controller.rb"
|
||||
assert_no_file "app/controllers/users/confirmations_controller.rb"
|
||||
assert_no_file "app/controllers/users/passwords_controller.rb"
|
||||
assert_no_file "app/controllers/users/unlocks_controller.rb"
|
||||
assert_no_file "app/controllers/users/omniauth_callbacks_controller.rb"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assert_class_names(scope, options = {})
|
||||
base_dir = "app/controllers#{scope.blank? ? '' : ('/' + scope)}"
|
||||
scope_prefix = scope.blank? ? '' : (scope.camelize + '::')
|
||||
controllers = options[:controllers] ||
|
||||
%w(confirmations passwords registrations sessions unlocks omniauth_callbacks)
|
||||
|
||||
controllers.each do |c|
|
||||
assert_file "#{base_dir}/#{c}_controller.rb", /#{scope_prefix + c.camelize}/
|
||||
end
|
||||
end
|
||||
end
|
|
@ -42,7 +42,7 @@ class HttpAuthenticationTest < ActionDispatch::IntegrationTest
|
|||
sign_in_as_new_user_with_http("unknown")
|
||||
assert_equal 401, status
|
||||
assert_equal "application/xml; charset=utf-8", headers["Content-Type"]
|
||||
assert_match "<error>Invalid email address or password.</error>", response.body
|
||||
assert_match "<error>Invalid email or password.</error>", response.body
|
||||
end
|
||||
|
||||
test 'returns a custom response with www-authenticate and chosen realm' do
|
||||
|
|
|
@ -62,6 +62,7 @@ class MappingTest < ActiveSupport::TestCase
|
|||
test 'find scope for a given object' do
|
||||
assert_equal :user, Devise::Mapping.find_scope!(User)
|
||||
assert_equal :user, Devise::Mapping.find_scope!(:user)
|
||||
assert_equal :user, Devise::Mapping.find_scope!("user")
|
||||
assert_equal :user, Devise::Mapping.find_scope!(User.new)
|
||||
end
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ class CreateTables < ActiveRecord::Migration
|
|||
t.string :unlock_token # Only if unlock strategy is :email or :both
|
||||
t.datetime :locked_at
|
||||
|
||||
t.timestamps
|
||||
t.timestamps null: false
|
||||
end
|
||||
|
||||
create_table :admins do |t|
|
||||
|
@ -60,7 +60,7 @@ class CreateTables < ActiveRecord::Migration
|
|||
## Attribute for testing route blocks
|
||||
t.boolean :active, default: false
|
||||
|
||||
t.timestamps
|
||||
t.timestamps null: false
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -27,3 +27,4 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
|||
require "rails/generators/test_case"
|
||||
require "generators/devise/install_generator"
|
||||
require "generators/devise/views_generator"
|
||||
require "generators/devise/controllers_generator"
|
||||
|
|
Loading…
Reference in a new issue