Showing preview only (723K chars total). Download the full file or copy to clipboard to get everything.
Repository: heartcombo/devise
Branch: main
Commit: 5d202775d75c
Files: 272
Total size: 656.7 KB
Directory structure:
gitextract_4bqfrk55/
├── .devcontainer/
│ └── devcontainer.json
├── .github/
│ ├── code-scanning.yml
│ ├── dependabot.yml
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .yardopts
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Gemfile
├── ISSUE_TEMPLATE.md
├── MIT-LICENSE
├── README.md
├── Rakefile
├── app/
│ ├── controllers/
│ │ ├── devise/
│ │ │ ├── confirmations_controller.rb
│ │ │ ├── omniauth_callbacks_controller.rb
│ │ │ ├── passwords_controller.rb
│ │ │ ├── registrations_controller.rb
│ │ │ ├── sessions_controller.rb
│ │ │ └── unlocks_controller.rb
│ │ └── devise_controller.rb
│ ├── helpers/
│ │ └── devise_helper.rb
│ ├── mailers/
│ │ └── devise/
│ │ └── mailer.rb
│ └── views/
│ └── devise/
│ ├── confirmations/
│ │ └── new.html.erb
│ ├── mailer/
│ │ ├── confirmation_instructions.html.erb
│ │ ├── email_changed.html.erb
│ │ ├── password_change.html.erb
│ │ ├── reset_password_instructions.html.erb
│ │ └── unlock_instructions.html.erb
│ ├── passwords/
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ ├── registrations/
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ ├── sessions/
│ │ └── new.html.erb
│ ├── shared/
│ │ ├── _error_messages.html.erb
│ │ └── _links.html.erb
│ └── unlocks/
│ └── new.html.erb
├── bin/
│ └── test
├── config/
│ └── locales/
│ └── en.yml
├── devise.gemspec
├── gemfiles/
│ ├── Gemfile-rails-7-0
│ ├── Gemfile-rails-7-1
│ ├── Gemfile-rails-7-2
│ ├── Gemfile-rails-8-0
│ └── Gemfile-rails-main
├── guides/
│ └── bug_report_templates/
│ └── integration_test.rb
├── lib/
│ ├── devise/
│ │ ├── controllers/
│ │ │ ├── helpers.rb
│ │ │ ├── rememberable.rb
│ │ │ ├── responder.rb
│ │ │ ├── scoped_views.rb
│ │ │ ├── sign_in_out.rb
│ │ │ ├── store_location.rb
│ │ │ └── url_helpers.rb
│ │ ├── delegator.rb
│ │ ├── encryptor.rb
│ │ ├── failure_app.rb
│ │ ├── hooks/
│ │ │ ├── activatable.rb
│ │ │ ├── csrf_cleaner.rb
│ │ │ ├── forgetable.rb
│ │ │ ├── lockable.rb
│ │ │ ├── proxy.rb
│ │ │ ├── rememberable.rb
│ │ │ ├── timeoutable.rb
│ │ │ └── trackable.rb
│ │ ├── mailers/
│ │ │ └── helpers.rb
│ │ ├── mapping.rb
│ │ ├── models/
│ │ │ ├── authenticatable.rb
│ │ │ ├── confirmable.rb
│ │ │ ├── database_authenticatable.rb
│ │ │ ├── lockable.rb
│ │ │ ├── omniauthable.rb
│ │ │ ├── recoverable.rb
│ │ │ ├── registerable.rb
│ │ │ ├── rememberable.rb
│ │ │ ├── timeoutable.rb
│ │ │ ├── trackable.rb
│ │ │ └── validatable.rb
│ │ ├── models.rb
│ │ ├── modules.rb
│ │ ├── omniauth/
│ │ │ ├── config.rb
│ │ │ └── url_helpers.rb
│ │ ├── omniauth.rb
│ │ ├── orm/
│ │ │ ├── active_record.rb
│ │ │ └── mongoid.rb
│ │ ├── orm.rb
│ │ ├── parameter_filter.rb
│ │ ├── parameter_sanitizer.rb
│ │ ├── rails/
│ │ │ ├── routes.rb
│ │ │ └── warden_compat.rb
│ │ ├── rails.rb
│ │ ├── strategies/
│ │ │ ├── authenticatable.rb
│ │ │ ├── base.rb
│ │ │ ├── database_authenticatable.rb
│ │ │ └── rememberable.rb
│ │ ├── test/
│ │ │ ├── controller_helpers.rb
│ │ │ └── integration_helpers.rb
│ │ ├── time_inflector.rb
│ │ ├── token_generator.rb
│ │ └── version.rb
│ ├── devise.rb
│ └── generators/
│ ├── active_record/
│ │ ├── devise_generator.rb
│ │ └── templates/
│ │ ├── migration.rb
│ │ └── migration_existing.rb
│ ├── devise/
│ │ ├── controllers_generator.rb
│ │ ├── devise_generator.rb
│ │ ├── install_generator.rb
│ │ ├── orm_helpers.rb
│ │ └── views_generator.rb
│ ├── mongoid/
│ │ └── devise_generator.rb
│ └── templates/
│ ├── README
│ ├── controllers/
│ │ ├── README
│ │ ├── confirmations_controller.rb
│ │ ├── omniauth_callbacks_controller.rb
│ │ ├── passwords_controller.rb
│ │ ├── registrations_controller.rb
│ │ ├── sessions_controller.rb
│ │ └── unlocks_controller.rb
│ ├── devise.rb
│ ├── markerb/
│ │ ├── confirmation_instructions.markerb
│ │ ├── email_changed.markerb
│ │ ├── password_change.markerb
│ │ ├── reset_password_instructions.markerb
│ │ └── unlock_instructions.markerb
│ └── simple_form_for/
│ ├── confirmations/
│ │ └── new.html.erb
│ ├── passwords/
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ ├── registrations/
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ ├── sessions/
│ │ └── new.html.erb
│ └── unlocks/
│ └── new.html.erb
└── test/
├── controllers/
│ ├── custom_registrations_controller_test.rb
│ ├── custom_strategy_test.rb
│ ├── helper_methods_test.rb
│ ├── helpers_test.rb
│ ├── inherited_controller_i18n_messages_test.rb
│ ├── internal_helpers_test.rb
│ ├── load_hooks_controller_test.rb
│ ├── passwords_controller_test.rb
│ ├── sessions_controller_test.rb
│ └── url_helpers_test.rb
├── delegator_test.rb
├── devise_test.rb
├── failure_app_test.rb
├── generators/
│ ├── active_record_generator_test.rb
│ ├── controllers_generator_test.rb
│ ├── devise_generator_test.rb
│ ├── install_generator_test.rb
│ ├── mongoid_generator_test.rb
│ └── views_generator_test.rb
├── helpers/
│ └── devise_helper_test.rb
├── integration/
│ ├── authenticatable_test.rb
│ ├── confirmable_test.rb
│ ├── database_authenticatable_test.rb
│ ├── http_authenticatable_test.rb
│ ├── lockable_test.rb
│ ├── mounted_engine_test.rb
│ ├── omniauthable_test.rb
│ ├── recoverable_test.rb
│ ├── registerable_test.rb
│ ├── rememberable_test.rb
│ ├── timeoutable_test.rb
│ └── trackable_test.rb
├── mailers/
│ ├── confirmation_instructions_test.rb
│ ├── email_changed_test.rb
│ ├── mailer_test.rb
│ ├── reset_password_instructions_test.rb
│ └── unlock_instructions_test.rb
├── mapping_test.rb
├── models/
│ ├── authenticatable_test.rb
│ ├── confirmable_test.rb
│ ├── database_authenticatable_test.rb
│ ├── lockable_test.rb
│ ├── omniauthable_test.rb
│ ├── recoverable_test.rb
│ ├── registerable_test.rb
│ ├── rememberable_test.rb
│ ├── serializable_test.rb
│ ├── timeoutable_test.rb
│ ├── trackable_test.rb
│ └── validatable_test.rb
├── models_test.rb
├── omniauth/
│ ├── config_test.rb
│ └── url_helpers_test.rb
├── orm/
│ ├── active_record.rb
│ └── mongoid.rb
├── parameter_sanitizer_test.rb
├── rails_app/
│ ├── Rakefile
│ ├── app/
│ │ ├── active_record/
│ │ │ ├── admin.rb
│ │ │ ├── shim.rb
│ │ │ ├── user.rb
│ │ │ ├── user_on_engine.rb
│ │ │ ├── user_on_main_app.rb
│ │ │ ├── user_with_validations.rb
│ │ │ └── user_without_email.rb
│ │ ├── controllers/
│ │ │ ├── admins/
│ │ │ │ └── sessions_controller.rb
│ │ │ ├── admins_controller.rb
│ │ │ ├── application_controller.rb
│ │ │ ├── application_with_fake_engine.rb
│ │ │ ├── custom/
│ │ │ │ └── registrations_controller.rb
│ │ │ ├── home_controller.rb
│ │ │ ├── publisher/
│ │ │ │ ├── registrations_controller.rb
│ │ │ │ └── sessions_controller.rb
│ │ │ ├── streaming_controller.rb
│ │ │ ├── users/
│ │ │ │ └── omniauth_callbacks_controller.rb
│ │ │ └── users_controller.rb
│ │ ├── helpers/
│ │ │ └── application_helper.rb
│ │ ├── mailers/
│ │ │ └── users/
│ │ │ ├── from_proc_mailer.rb
│ │ │ ├── mailer.rb
│ │ │ └── reply_to_mailer.rb
│ │ ├── mongoid/
│ │ │ ├── admin.rb
│ │ │ ├── shim.rb
│ │ │ ├── user.rb
│ │ │ ├── user_on_engine.rb
│ │ │ ├── user_on_main_app.rb
│ │ │ ├── user_with_validations.rb
│ │ │ └── user_without_email.rb
│ │ └── views/
│ │ ├── admins/
│ │ │ ├── index.html.erb
│ │ │ └── sessions/
│ │ │ └── new.html.erb
│ │ ├── home/
│ │ │ ├── admin_dashboard.html.erb
│ │ │ ├── index.html.erb
│ │ │ ├── join.html.erb
│ │ │ ├── private.html.erb
│ │ │ └── user_dashboard.html.erb
│ │ ├── layouts/
│ │ │ └── application.html.erb
│ │ └── users/
│ │ ├── edit_form.html.erb
│ │ ├── index.html.erb
│ │ ├── mailer/
│ │ │ └── confirmation_instructions.erb
│ │ └── sessions/
│ │ └── new.html.erb
│ ├── bin/
│ │ ├── bundle
│ │ ├── rails
│ │ └── rake
│ ├── config/
│ │ ├── application.rb
│ │ ├── boot.rb
│ │ ├── database.yml
│ │ ├── environment.rb
│ │ ├── environments/
│ │ │ ├── development.rb
│ │ │ ├── production.rb
│ │ │ └── test.rb
│ │ ├── initializers/
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── devise.rb
│ │ │ ├── inflections.rb
│ │ │ ├── secret_token.rb
│ │ │ └── session_store.rb
│ │ └── routes.rb
│ ├── config.ru
│ ├── db/
│ │ ├── migrate/
│ │ │ └── 20100401102949_create_tables.rb
│ │ └── schema.rb
│ ├── lib/
│ │ ├── lazy_load_test_module.rb
│ │ ├── shared_admin.rb
│ │ ├── shared_user.rb
│ │ ├── shared_user_without_email.rb
│ │ └── shared_user_without_omniauth.rb
│ └── public/
│ ├── 404.html
│ ├── 422.html
│ └── 500.html
├── rails_test.rb
├── routes_test.rb
├── support/
│ ├── action_controller/
│ │ └── record_identifier.rb
│ ├── assertions.rb
│ ├── helpers.rb
│ ├── http_method_compatibility.rb
│ ├── integration.rb
│ ├── locale/
│ │ ├── de.yml
│ │ ├── en.yml
│ │ └── pt-BR.yml
│ ├── mongoid.yml
│ └── webrat/
│ ├── integrations/
│ │ └── rails.rb
│ └── matchers.rb
├── test/
│ ├── controller_helpers_test.rb
│ └── integration_helpers_test.rb
├── test_helper.rb
└── test_models.rb
================================================
FILE CONTENTS
================================================
================================================
FILE: .devcontainer/devcontainer.json
================================================
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/ruby
{
"name": "Ruby",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/ruby:0-3-bullseye",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {}
},
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "bundle install",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
================================================
FILE: .github/code-scanning.yml
================================================
paths-ignore:
- test/**
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
permissions:
contents: read
on:
push:
branches:
- main
pull_request:
workflow_dispatch:
jobs:
test:
strategy:
fail-fast: false
matrix:
gemfile:
- Gemfile
- gemfiles/Gemfile-rails-main
- gemfiles/Gemfile-rails-7-0
- gemfiles/Gemfile-rails-7-1
- gemfiles/Gemfile-rails-7-2
- gemfiles/Gemfile-rails-8-0
ruby:
- '4.0'
- '3.4'
- '3.3'
- '3.2'
- '3.1'
- '3.0'
- '2.7'
orm:
- active_record
- mongoid
exclude:
- gemfile: Gemfile
ruby: '3.1'
- gemfile: Gemfile
ruby: '3.0'
- gemfile: Gemfile
ruby: '2.7'
- gemfile: gemfiles/Gemfile-rails-main
ruby: '3.2'
- gemfile: gemfiles/Gemfile-rails-main
ruby: '3.1'
- gemfile: gemfiles/Gemfile-rails-main
ruby: '3.0'
- gemfile: gemfiles/Gemfile-rails-main
ruby: '2.7'
- gemfile: gemfiles/Gemfile-rails-8-0
ruby: '3.1'
- gemfile: gemfiles/Gemfile-rails-8-0
ruby: '3.0'
- gemfile: gemfiles/Gemfile-rails-8-0
ruby: '2.7'
- gemfile: gemfiles/Gemfile-rails-7-2
ruby: '3.0'
- gemfile: gemfiles/Gemfile-rails-7-2
ruby: '2.7'
runs-on: ubuntu-latest
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
DEVISE_ORM: ${{ matrix.orm }}
steps:
- uses: actions/checkout@v6
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true # runs bundle install and caches installed gems automatically
- uses: supercharge/mongodb-github-action@1.12.1
if: ${{ matrix.orm == 'mongoid' }}
- run: bundle exec rake
================================================
FILE: .gitignore
================================================
test/rails_app/log/*
test/rails_app/tmp/*
*~
coverage/*
*.sqlite3
.bundle
rdoc/*
pkg
log
test/tmp/*
gemfiles/*.lock
================================================
FILE: .yardopts
================================================
--protected
--no-private
--embed-mixin ClassMethods
-
README.md
CHANGELOG.rdoc
CONTRIBUTING.md
MIT-LICENSE
================================================
FILE: CHANGELOG.md
================================================
### 5.0.3 - 2026-03-16
* security fixes
* Fix race condition vulnerability on confirmable "change email" which would allow confirming an email they don't own CVE-2026-32700 [#5783](https://github.com/heartcombo/devise/pull/5783) [#5784](https://github.com/heartcombo/devise/pull/5784)
### 5.0.2 - 2026-02-18
* enhancements
* Allow resource class scopes to override the global configuration for `sign_in_after_change_password` behaviour. [#5825](https://github.com/heartcombo/devise/pull/5825)
* _Note_: some users ran into an issue with this change because `RegistrationsController` now relies on a setting from the `:registerable` module. These users were configuring their own routes pointing to the `RegistrationsController` for resource edit/update actions mostly, without relying on the other registration actions (e.g. user sign up.), so they omitted `:registerable` from the model declaration. While using just a portion of the controller functionality is a valid use for `:registerable` (or any module really), the module must still be declared in the model, much like the other modules must be declared if you plan on using just a portion of their behavior. Please check [this issue](https://github.com/heartcombo/devise/pull/5828#issuecomment-3926822788) for more info.
* Add `sign_in_after_reset_password?` check hook to passwords controller, to allow it to be customized by users. [#5826](https://github.com/heartcombo/devise/pull/5826)
### 5.0.1 - 2026-02-13
* bug fixes
* Fix translation issue with German `E-Mail` on invalid authentication messages caused by previous fix for incorrect grammar [#5822](https://github.com/heartcombo/devise/pull/5822)
### 5.0.0 - 2026-01-23
no changes
### 5.0.0.rc - 2025-12-31
* breaking changes
* Drop support to Ruby < 2.7
* Drop support to Rails < 7.0
* Remove deprecated `:bypass` option from `sign_in` helper, use `bypass_sign_in` instead. [#5803](https://github.com/heartcombo/devise/pull/5803)
* Remove deprecated `devise_error_messages!` helper, use `render "devise/shared/error_messages", resource: resource` instead. [#5803](https://github.com/heartcombo/devise/pull/5803)
* Remove deprecated `scope` second argument from `sign_in(resource, :admin)` controller test helper, use `sign_in(resource, scope: :admin)` instead. [#5803](https://github.com/heartcombo/devise/pull/5803)
* Remove deprecated `Devise::TestHelpers`, use `Devise::Test::ControllerHelpers` instead. [#5803](https://github.com/heartcombo/devise/pull/5803)
* Remove deprecated `Devise::Models::Authenticatable::BLACKLIST_FOR_SERIALIZATION` [#5598](https://github.com/heartcombo/devise/pull/5598)
* Remove deprecated `Devise.activerecord51?` method.
* Remove `SecretKeyFinder` and use `app.secret_key_base` as the default secret key for `Devise.secret_key` if a custom `Devise.secret_key` is not provided.
This is potentially a breaking change because Devise previously used the following order to find a secret key:
```
app.credentials.secret_key_base > app.secrets.secret_key_base > application.config.secret_key_base > application.secret_key_base
```
Now, it always uses `application.secret_key_base`. Make sure you're using the same secret key after the upgrade; otherwise, previously generated tokens for `recoverable`, `lockable`, and `confirmable` will be invalid.
[#5645](https://github.com/heartcombo/devise/pull/5645)
* Change password instructions button label on devise view from `Send me reset password instructions` to `Send me password reset instructions` [#5515](https://github.com/heartcombo/devise/pull/5515)
* Change `<br>` tags separating form elements to wrapping them in `<p>` tags [#5494](https://github.com/heartcombo/devise/pull/5494)
* Replace `[data-turbo-cache=false]` with `[data-turbo-temporary]` on `devise/shared/error_messages` partial. This has been [deprecated by Turbo since v7.3.0 (released on Mar 1, 2023)](https://github.com/hotwired/turbo/releases/tag/v7.3.0).
If you are using an older version of Turbo and the default devise template, you'll need to copy it over to your app and change that back to `[data-turbo-cache=false]`.
* enhancements
* Add Rails 8 support.
- Routes are lazy-loaded by default in test and development environments now so Devise loads them before `Devise.mappings` call. [#5728](https://github.com/heartcombo/devise/pull/5728)
* New apps using Rack 3.1+ will be generated using `config.responder.error_status = :unprocessable_content`, since [`:unprocessable_entity` has been deprecated by Rack](https://github.com/rack/rack/pull/2137).
Latest versions of [Rails transparently convert `:unprocessable_entity` -> `:unprocessable_content`](https://github.com/rails/rails/pull/53383), and Devise will use that in the failure app to avoid Rack deprecation warnings for apps that are configured with `:unprocessable_entity`. They can also simply change their `error_status` to `:unprocessable_content` in latest Rack versions to avoid the warning.
* Add Ruby 3.4 and 4.0 support.
* Reenable Mongoid test suite across all Rails 7+ versions, to ensure we continue supporting it. Changes to dirty tracking to support Mongoid 8.0+. [#5568](https://github.com/heartcombo/devise/pull/5568)
* Password length validator is changed from
```
validates_length_of :password, within: password_length, allow_blank: true`
```
to
```
validates_length_of :password, minimum: proc { password_length.min }, maximum: proc { password_length.max }, allow_blank: true
```
so it's possible to override `password_length` at runtime. [#5734](https://github.com/heartcombo/devise/pull/5734)
* bug fixes
* Make `Devise` work without `ActionMailer` when `Zeitwerk` autoloader is used. [#5731](https://github.com/heartcombo/devise/pull/5731)
* Handle defaults `:from` and `:reply_to` as procs correctly by delegating to Rails [#5595](https://github.com/heartcombo/devise/pull/5595)
* Use `OmniAuth.config.allowed_request_methods` as routing verbs for the auth path [#5508](https://github.com/heartcombo/devise/pull/5508)
* Handle `on` and `ON` as true values to check params [#5514](https://github.com/heartcombo/devise/pull/5514)
* Fix passing `format` option to `devise_for` [#5732](https://github.com/heartcombo/devise/pull/5732)
* Use `ActiveRecord::SecurityUtils.secure_compare` in `Devise.secure_compare` to match two empty strings correctly. [#4829](https://github.com/heartcombo/devise/pull/4829)
* Respond with `401 Unauthorized` for non-navigational requests to destroy the session when there is no authenticated resource. [#4878](https://github.com/heartcombo/devise/pull/4878)
* Fix incorrect grammar of invalid authentication message with capitalized attributes, e.g.: "Invalid Email or password" => "Invalid email or password". (originally introduced by [#4014](https://github.com/heartcombo/devise/pull/4014), released on v4.1.0) [#4834](https://github.com/heartcombo/devise/pull/4834)
Please check [4-stable](https://github.com/heartcombo/devise/blob/4-stable/CHANGELOG.md)
for previous changes.
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
* Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by sending an email to [heartcombo.oss@gmail.com](heartcombo.oss@gmail.com) or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
================================================
FILE: CONTRIBUTING.md
================================================
# How to contribute to Devise
Thanks for your interest on contributing to Devise! Here are a few general
guidelines on contributing and reporting bugs to Devise that we ask you to
take a look first. Notice that all of your interactions in the project are
expected to follow our [Code of Conduct](CODE_OF_CONDUCT.md).
## Reporting Issues
Before reporting a new issue, please be sure that the issue wasn't already
reported or fixed by searching on GitHub through our [issues](https://github.com/heartcombo/devise/issues).
When creating a new issue, be sure to include a **title and clear description**,
as much relevant information as possible, and either a test case example or
even better a **sample Rails app that replicates the issue** - Devise has a lot
of moving parts and it's functionality can be affected by third party gems, so
we need as much context and details as possible to identify what might be broken
for you. We have a [test case template](guides/bug_report_templates/integration_test.rb)
that can be used to replicate issues with minimal setup.
Please do not attempt to translate Devise built in views. The views are meant
to be a starting point for fresh apps and not production material - eventually
all applications will require custom views where you can write your own copy and
translate it if the application requires it . For historical references, please look into closed
[Issues/Pull Requests](https://github.com/heartcombo/devise/issues?q=i18n) regarding
internationalization.
Avoid opening new issues to ask questions in our issues tracker. Please go through
the project wiki, documentation and source code first, or try to ask your question
on [Stack Overflow](http://stackoverflow.com/questions/tagged/devise).
**If you find a security bug, do not report it through GitHub. Please send an
e-mail to [heartcombo.oss@gmail.com](mailto:heartcombo.oss@gmail.com)
instead.**
## Sending Pull Requests
Before sending a new Pull Request, take a look on existing Pull Requests and Issues
to see if the proposed change or fix has been discussed in the past, or if the
change was already implemented but not yet released.
We expect new Pull Requests to include enough tests for new or changed behavior,
and we aim to maintain everything as most backwards compatible as possible,
reserving breaking changes to be ship in major releases when necessary - you
can wrap the new code path with a setting toggle from the `Devise` module defined
as `false` by default to require developers to opt-in for the new behavior.
If your Pull Request includes new or changed behavior, be sure that the changes
are beneficial to a wide range of use cases or it's an application specific change
that might not be so valuable to other applications. Some changes can be introduced
as a new `devise-something` gem instead of belonging to the main codebase.
When adding new settings, you can take advantage of the [`Devise::Models.config`](https://github.com/heartcombo/devise/blob/245b1f9de0b3386b7913e14b60ea24f43b77feb0/lib/devise/models.rb#L13-L50) method to add class and instance level fallbacks
to the new setting.
We also welcome Pull Requests that improve our existing documentation (both our
`README.md` and the RDoc sections in the source code) or improve existing rough
edges in our API that might be blocking existing integrations or 3rd party gems.
## Other ways to contribute
We welcome anyone that wants to contribute to Devise to triage and reply to
open issues to help troubleshoot and fix existing bugs on Devise. Here is what
you can do:
* Help ensure that existing issues follows the recommendations from the
_[Reporting Issues](#reporting-issues)_ section, providing feedback to the issue's
author on what might be missing.
* Review and update the existing content of our [Wiki](https://github.com/heartcombo/devise/wiki)
with up to date instructions and code samples - the wiki was grown with several
different tutorials and references that we can't keep track of everything, so if
there is a page that showcases an integration or customization that you are
familiar with feel free to update it as necessary.
* Review existing Pull Requests, and testing patches against real existing
applications that use Devise.
Thanks again for your interest on contributing to the project!
:heart:
================================================
FILE: Gemfile
================================================
# frozen_string_literal: true
source "https://rubygems.org"
gemspec
gem "omniauth"
gem "omniauth-oauth2"
gem "rails", "~> 8.1.0"
gem "rdoc"
gem "rails-controller-testing"
gem "responders", "~> 3.1"
group :test do
gem "minitest", "< 6"
gem "mocha", "~> 2.1", require: false
gem "omniauth-facebook"
gem "omniauth-openid"
gem "rexml"
gem "timecop"
gem "webrat"
gem "ostruct"
end
platforms :ruby do
gem "sqlite3"
end
group :mongoid do
gem "mongoid", "~> 9.0", github: "mongodb/mongoid", branch: "9.0-stable"
end
================================================
FILE: ISSUE_TEMPLATE.md
================================================
## Pre-check
- Do not use the issues tracker for help or support, try Stack Overflow.
- For bugs, do a quick search and make sure the bug has not yet been reported
- If you found a security bug, do not report it through GitHub. Please send an e-mail to heartcombo.oss@gmail.com instead.
- Finally, be nice and have fun!
## Environment
- Ruby **[version]**
- Rails **[version]**
- Devise **[version]**
## Current behavior
Include code samples, errors, steps to reproduce the error and stack traces if appropriate.
Will be even more helpful if you provide a sample application or a test case that reproduces the error.
## Expected behavior
================================================
FILE: MIT-LICENSE
================================================
Copyright (c) 2020-CURRENT Rafael França, Carlos Antonio da Silva
Copyright (c) 2009-2019 Plataformatec
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================

Devise is a flexible authentication solution for Rails based on Warden. It:
* Is Rack based;
* Is a complete MVC solution based on Rails engines;
* Allows you to have multiple models signed in at the same time;
* Is based on a modularity concept: use only what you really need.
It's composed of 10 modules:
* [Database Authenticatable](https://www.rubydoc.info/gems/devise/Devise/Models/DatabaseAuthenticatable): hashes and stores a password in the database to validate the authenticity of a user while signing in. The authentication can be done both through POST requests or HTTP Basic Authentication.
* [Omniauthable](https://www.rubydoc.info/gems/devise/Devise/Models/Omniauthable): adds OmniAuth (https://github.com/omniauth/omniauth) support.
* [Confirmable](https://www.rubydoc.info/gems/devise/Devise/Models/Confirmable): sends emails with confirmation instructions and verifies whether an account is already confirmed during sign in.
* [Recoverable](https://www.rubydoc.info/gems/devise/Devise/Models/Recoverable): resets the user password and sends reset instructions.
* [Registerable](https://www.rubydoc.info/gems/devise/Devise/Models/Registerable): handles signing up users through a registration process, also allowing them to edit and destroy their account.
* [Rememberable](https://www.rubydoc.info/gems/devise/Devise/Models/Rememberable): manages generating and clearing a token for remembering the user from a saved cookie.
* [Trackable](https://www.rubydoc.info/gems/devise/Devise/Models/Trackable): tracks sign in count, timestamps and IP address.
* [Timeoutable](https://www.rubydoc.info/gems/devise/Devise/Models/Timeoutable): expires sessions that have not been active in a specified period of time.
* [Validatable](https://www.rubydoc.info/gems/devise/Devise/Models/Validatable): provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
* [Lockable](https://www.rubydoc.info/gems/devise/Devise/Models/Lockable): locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
## Table of Contents
<!-- TOC depthFrom:1 depthTo:6 withLinks:1 orderedList:0 -->
- [Information](#information)
- [The Devise wiki](#the-devise-wiki)
- [Bug reports](#bug-reports)
- [StackOverflow and Mailing List](#stackoverflow-and-mailing-list)
- [RDocs](#rdocs)
- [Example applications](#example-applications)
- [Extensions](#extensions)
- [Supported Ruby / Rails versions](#supported-ruby--rails-versions)
- [Contributing](#contributing)
- [Starting with Rails?](#starting-with-rails)
- [Getting started](#getting-started)
- [Controller filters and helpers](#controller-filters-and-helpers)
- [Configuring Models](#configuring-models)
- [Strong Parameters](#strong-parameters)
- [Configuring views](#configuring-views)
- [Configuring controllers](#configuring-controllers)
- [Configuring routes](#configuring-routes)
- [I18n](#i18n)
- [Test helpers](#test-helpers)
- [Controller tests](#controller-tests)
- [Integration tests](#integration-tests)
- [OmniAuth](#omniauth)
- [Configuring multiple models](#configuring-multiple-models)
- [Active Job Integration](#active-job-integration)
- [Password reset tokens and Rails logs](#password-reset-tokens-and-rails-logs)
- [Other ORMs](#other-orms)
- [Rails API mode](#rails-api-mode)
- [Additional information](#additional-information)
- [Warden](#warden)
- [License](#license)
<!-- /TOC -->
## Information
### The Devise wiki
The Devise Wiki has lots of additional information about Devise including many "how-to" articles and answers to the most frequently asked questions. Please browse the Wiki after finishing this README:
https://github.com/heartcombo/devise/wiki
### Bug reports
If you discover a problem with Devise, we would like to know about it. However, we ask that you please review these guidelines before submitting a bug report:
https://github.com/heartcombo/devise/wiki/Bug-reports
If you have discovered a security related bug, please do *NOT* use the GitHub issue tracker. Send an email to heartcombo.oss@gmail.com.
### StackOverflow and Mailing List
If you have any questions, comments, or concerns, please use StackOverflow instead of the GitHub issue tracker:
http://stackoverflow.com/questions/tagged/devise
The deprecated mailing lists can still be read on:
https://groups.google.com/group/plataformatec-devise
https://groups.google.com/group/heartcombo
### RDocs
You can view the Devise documentation in RDoc format here:
http://rubydoc.info/github/heartcombo/devise/main/frames
If you need to use Devise with previous versions of Rails, you can always run "gem server" from the command line after you install the gem to access the old documentation.
### Example applications
There are a few example applications available on GitHub that demonstrate various features of Devise with different versions of Rails. You can view them here:
https://github.com/heartcombo/devise/wiki/Example-Applications
### Extensions
Our community has created a number of extensions that add functionality above and beyond what is included with Devise. You can view a list of available extensions and add your own here:
https://github.com/heartcombo/devise/wiki/Extensions
### Supported Ruby / Rails versions
We intend to maintain support for all Ruby / Rails versions that haven't reached end-of-life.
For more information about specific versions please check [Ruby](https://www.ruby-lang.org/en/downloads/branches/)
and [Rails](https://guides.rubyonrails.org/maintenance_policy.html) maintenance policies, and our test matrix.
### Contributing
We hope that you will consider contributing to Devise. Please read this short overview for some information about how to get started:
https://github.com/heartcombo/devise/wiki/Contributing
You will usually want to write tests for your changes. To run the test suite, go into Devise's top-level directory and run `bundle install` and `bin/test`.
Devise works with multiple Ruby and Rails versions, and ActiveRecord and Mongoid ORMs, which means you can run the test suite with some modifiers: `DEVISE_ORM` and `BUNDLE_GEMFILE`.
#### DEVISE_ORM
Since Devise supports both Mongoid and ActiveRecord, we rely on this variable to run specific code for each ORM.
The default value of `DEVISE_ORM` is `active_record`. To run the tests for Mongoid, you can pass `mongoid`:
```
DEVISE_ORM=mongoid bin/test
==> Devise.orm = :mongoid
```
When running the tests for Mongoid, you will need to have a MongoDB server (version 2.0 or newer) running on your system.
Please note that the command output will show the variable value being used.
#### BUNDLE_GEMFILE
We can use this variable to tell bundler what Gemfile it should use (instead of the one in the current directory).
Inside the [gemfiles](https://github.com/heartcombo/devise/tree/main/gemfiles) directory, we have one for each version of Rails we support. When you send us a pull request, it may happen that the test suite breaks using some of them. If that's the case, you can simulate the same environment using the `BUNDLE_GEMFILE` variable.
For example, if the tests broke using Ruby 3.4 and Rails 8.0, you can do the following:
```bash
chruby 3.4.0 # or rbenv shell 3.4.0, or rvm use 3.4.0, etc.
BUNDLE_GEMFILE=gemfiles/Gemfile-rails-8-0 bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile-rails-8-0 bin/test
```
You can also combine both of them if the tests broke for Mongoid:
```bash
BUNDLE_GEMFILE=gemfiles/Gemfile-rails-8-0 bundle install
BUNDLE_GEMFILE=gemfiles/Gemfile-rails-8-0 DEVISE_ORM=mongoid bin/test
```
### Running tests
Devise uses [minitest](https://github.com/seattlerb/minitest) as test framework.
* Running all tests:
```bash
bin/test
```
* Running tests for an specific file:
```bash
bin/test test/models/trackable_test.rb
```
* Running a specific test given a line number or a regex:
```bash
bin/test test/models/trackable_test.rb:16
bin/test test/models/trackable_test.rb -n '/update.*record/'
```
## Starting with Rails?
If you are building your first Rails application, we recommend you *do not* use Devise. Devise requires a good understanding of the Rails Framework. In such cases, we advise you to start a simple authentication system from scratch. Here's a few resources that should help you get started:
* Michael Hartl's online book: https://www.railstutorial.org/book/modeling_users
* Ryan Bates' Railscasts: http://railscasts.com/episodes/250-authentication-from-scratch and http://railscasts.com/episodes/250-authentication-from-scratch-revised
* Codecademy's Ruby on Rails: Authentication and Authorization: https://www.codecademy.com/learn/rails-auth
Once you have solidified your understanding of Rails and authentication mechanisms, we assure you Devise will be very pleasant to work with. :smiley:
## Getting started
Devise 5 works with Rails 7 onwards. Run:
```sh
bundle add devise
```
Next, you need to run the generator:
```console
rails generate devise:install
```
At this point, a number of instructions will appear in the console. Among these instructions, you'll need to set up the default URL options for the Devise mailer in each environment. Here is a possible configuration for `config/environments/development.rb`:
```ruby
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```
The generator will install an initializer which describes ALL of Devise's configuration options. It is *imperative* that you take a look at it. When you are done, you are ready to add Devise to any of your models using the generator.
In the following command you will replace `MODEL` with the class name used for the application’s users (it’s frequently `User` but could also be `Admin`). This will create a model (if one does not exist) and configure it with the default Devise modules. The generator also configures your `config/routes.rb` file to point to the Devise controller.
```console
rails generate devise MODEL
```
Next, check the MODEL for any additional configuration options you might want to add, such as confirmable or lockable. If you add an option, be sure to inspect the migration file (created by the generator if your ORM supports them) and uncomment the appropriate section. For example, if you add the confirmable option in the model, you'll need to uncomment the Confirmable section in the migration.
Then run `rails db:migrate`
You should restart your application after changing Devise's configuration options (this includes stopping spring). Otherwise, you will run into strange errors, for example, users being unable to login and route helpers being undefined.
### Controller filters and helpers
Devise will create some helpers to use inside your controllers and views. To set up a controller with user authentication, just add this before_action (assuming your devise model is 'User'):
```ruby
before_action :authenticate_user!
```
For Rails 5, note that `protect_from_forgery` is no longer prepended to the `before_action` chain, so if you have set `authenticate_user` before `protect_from_forgery`, your request will result in "Can't verify CSRF token authenticity." To resolve this, either change the order in which you call them, or use `protect_from_forgery prepend: true`.
If your devise model is something other than User, replace "_user" with "_yourmodel". The same logic applies to the instructions below.
To verify if a user is signed in, use the following helper:
```ruby
user_signed_in?
```
For the current signed-in user, this helper is available:
```ruby
current_user
```
You can access the session for this scope:
```ruby
user_session
```
After signing in a user, confirming the account or updating the password, Devise will look for a scoped root path to redirect to. For instance, when using a `:user` resource, the `user_root_path` will be used if it exists; otherwise, the default `root_path` will be used. This means that you need to set the root inside your routes:
```ruby
root to: 'home#index'
```
You can also override `after_sign_in_path_for` and `after_sign_out_path_for` to customize your redirect hooks.
Notice that if your Devise model is called `Member` instead of `User`, for example, then the helpers available are:
```ruby
before_action :authenticate_member!
member_signed_in?
current_member
member_session
```
### Configuring Models
The Devise method in your models also accepts some options to configure its modules. For example, you can choose the cost of the hashing algorithm with:
```ruby
devise :database_authenticatable, :registerable, :confirmable, :recoverable, stretches: 13
```
Besides `:stretches`, you can define `:pepper`, `:encryptor`, `:confirm_within`, `:remember_for`, `:timeout_in`, `:unlock_in` among other options. For more details, see the initializer file that was created when you invoked the "devise:install" generator described above. This file is usually located at `/config/initializers/devise.rb`.
### Strong Parameters
The Parameter Sanitizer API has changed for Devise 4 :warning:
*For previous Devise versions see https://github.com/heartcombo/devise/tree/3-stable#strong-parameters*
When you customize your own views, you may end up adding new attributes to forms. Rails 4 moved the parameter sanitization from the model to the controller, causing Devise to handle this concern at the controller as well.
There are just three actions in Devise that allow any set of parameters to be passed down to the model, therefore requiring sanitization. Their names and default permitted parameters are:
* `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`
In case you want to permit additional parameters (the lazy way™), you can do so using a simple before action in your `ApplicationController`:
```ruby
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
end
end
```
The above works for any additional fields where the parameters are simple scalar types. If you have nested attributes (say you're using `accepts_nested_attributes_for`), then you will need to tell devise about those nestings and types:
```ruby
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, address_attributes: [:country, :state, :city, :area, :postal_code]])
end
end
```
Devise allows you to completely change Devise defaults or invoke custom behavior by passing a block:
To permit simple scalar values for username and email, use this
```ruby
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_in) do |user_params|
user_params.permit(:username, :email)
end
end
```
If you have some checkboxes that express the roles a user may take on registration, the browser will send those selected checkboxes as an array. An array is not one of Strong Parameters' permitted scalars, so we need to configure Devise in the following way:
```ruby
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) do |user_params|
user_params.permit({ roles: [] }, :email, :password, :password_confirmation)
end
end
```
For the list of permitted scalars, and how to declare permitted keys in nested hashes and arrays, see
https://github.com/rails/strong_parameters#nested-parameters
If you have multiple Devise models, you may want to set up a different parameter sanitizer per model. In this case, we recommend inheriting from `Devise::ParameterSanitizer` and adding your own logic:
```ruby
class User::ParameterSanitizer < Devise::ParameterSanitizer
def initialize(*)
super
permit(:sign_up, keys: [:username, :email])
end
end
```
And then configure your controllers to use it:
```ruby
class ApplicationController < ActionController::Base
protected
def devise_parameter_sanitizer
if resource_class == User
User::ParameterSanitizer.new(User, :user, params)
else
super # Use the default one
end
end
end
```
The example above overrides the permitted parameters for the user to be both `:username` and `:email`. The non-lazy way to configure parameters would be by defining the before filter above in a custom controller. We detail how to configure and customize controllers in some sections below.
### Configuring views
We built Devise to help you quickly develop an application that uses authentication. However, we don't want to be in your way when you need to customize it.
Since Devise is an engine, all its views are packaged inside the gem. These views will help you get started, but after some time you may want to change them. If this is the case, you just need to invoke the following generator, and it will copy all views to your application:
```console
rails generate devise:views
```
If you have more than one Devise model in your application (such as `User` and `Admin`), you will notice that Devise uses the same views for all models. Fortunately, Devise offers an easy way to customize views. All you need to do is set `config.scoped_views = true` inside the `config/initializers/devise.rb` file.
After doing so, you will be able to have views based on the role like `users/sessions/new` and `admins/sessions/new`. If no view is found within the scope, Devise will use the default view at `devise/sessions/new`. You can also use the generator to generate scoped views:
```console
rails generate devise:views users
```
If you would like to generate only a few sets of views, like the ones for the `registerable` and `confirmable` module,
you can pass a list of views to the generator with the `-v` flag.
```console
rails generate devise:views -v registrations confirmations
```
### Configuring controllers
If the customization at the views level is not enough, you can customize each controller by following these steps:
1. Create your custom controllers using the generator which requires a scope:
```console
rails generate devise:controllers [scope]
```
If you specify `users` as the scope, controllers will be created in `app/controllers/users/`.
And the sessions controller will look like this:
```ruby
class Users::SessionsController < Devise::SessionsController
# GET /resource/sign_in
# def new
# super
# end
...
end
```
Use the `-c` flag to specify one or more controllers, for example: `rails generate devise:controllers users -c sessions`
2. Tell the router to use this controller:
```ruby
devise_for :users, controllers: { sessions: 'users/sessions' }
```
3. Recommended but not required: copy (or move) the views from `devise/sessions` to `users/sessions`. Rails will continue using the views from `devise/sessions` due to inheritance if you skip this step, but having the views matching the controller(s) keeps things consistent.
4. Finally, change or extend the desired controller actions.
You can completely override a controller action:
```ruby
class Users::SessionsController < Devise::SessionsController
def create
# custom sign-in code
end
end
```
Or you can simply add new behavior to it:
```ruby
class Users::SessionsController < Devise::SessionsController
def create
super do |resource|
BackgroundWorker.trigger(resource)
end
end
end
```
This is useful for triggering background jobs or logging events during certain actions.
Remember that Devise uses flash messages to let users know if sign in was successful or unsuccessful. Devise expects your application to call `flash[:notice]` and `flash[:alert]` as appropriate. Do not print the entire flash hash, print only specific keys. In some circumstances, Devise adds a `:timedout` key to the flash hash, which is not meant for display. Remove this key from the hash if you intend to print the entire hash.
### Configuring routes
Devise also ships with default routes. If you need to customize them, you should probably be able to do it through the devise_for method. It accepts several options like :class_name, :path_prefix and so on, including the possibility to change path names for I18n:
```ruby
devise_for :users, path: 'auth', path_names: { sign_in: 'login', sign_out: 'logout', password: 'secret', confirmation: 'verification', unlock: 'unblock', registration: 'register', sign_up: 'cmon_let_me_in' }
```
Be sure to check `devise_for` [documentation](https://www.rubydoc.info/gems/devise/ActionDispatch/Routing/Mapper#devise_for-instance_method) for details.
If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is create your routes normally and wrap them in a `devise_scope` block in the router:
```ruby
devise_scope :user do
get 'sign_in', to: 'devise/sessions#new'
end
```
This way, you tell Devise to use the scope `:user` when "/sign_in" is accessed. Notice `devise_scope` is also aliased as `as` in your router.
Please note: You will still need to add `devise_for` in your routes in order to use helper methods such as `current_user`.
```ruby
devise_for :users, skip: :all
```
### Hotwire/Turbo
Devise integrates with Hotwire/Turbo by treating such requests as navigational, and configuring certain responses for errors and redirects to match the expected behavior. New apps are generated with the following response configuration by default, and existing apps may opt-in by adding the config to their Devise initializers:
```ruby
Devise.setup do |config|
# ...
# When using Devise with Hotwire/Turbo, the http status for error responses
# and some redirects must match the following. The default in Devise for existing
# apps is `200 OK` and `302 Found` respectively, but new apps are generated with
# these new defaults that match Hotwire/Turbo behavior.
# Note: These might become the new default in future versions of Devise.
config.responder.error_status = :unprocessable_content # for Rack 3.1 or higher
# config.responder.error_status = :unprocessable_entity # for Rack 3.0 or lower
config.responder.redirect_status = :see_other
end
```
**Important**: these custom responses require the `responders` gem version to be `3.1.0` or higher, please make sure you update it if you're going to use this configuration. Check [this upgrade guide](https://github.com/heartcombo/devise/wiki/How-To:-Upgrade-to-Devise-4.9.0-[Hotwire-Turbo-integration]) for more info.
_Note_: the above statuses configuration may become the default for Devise in a future release.
There are a couple other changes you might need to make in your app to work with Hotwire/Turbo, if you're migrating from rails-ujs:
* The `data-confirm` option that adds a confirmation modal to buttons/forms before submission needs to change to `data-turbo-confirm`, so that Turbo handles those appropriately.
* The `data-method` option that sets the request method for link submissions needs to change to `data-turbo-method`. This is not necessary for `button_to` or `form`s since Turbo can handle those.
If you're setting up Devise to sign out via `:delete`, and you're using links (instead of buttons wrapped in a form) to sign out with the `method: :delete` option, they will need to be updated as described above. (Devise does not provide sign out links/buttons in its shared views.)
Make sure to inspect your views looking for those, and change appropriately.
### I18n
Devise uses flash messages with I18n, in conjunction with the flash keys :notice and :alert. To customize your app, you can set up your locale file:
```yaml
en:
devise:
sessions:
signed_in: 'Signed in successfully.'
```
You can also create distinct messages based on the resource you've configured using the singular name given in routes:
```yaml
en:
devise:
sessions:
user:
signed_in: 'Welcome user, you are signed in.'
admin:
signed_in: 'Hello admin!'
```
The Devise mailer uses a similar pattern to create subject messages:
```yaml
en:
devise:
mailer:
confirmation_instructions:
subject: 'Hello everybody!'
user_subject: 'Hello User! Please confirm your email'
reset_password_instructions:
subject: 'Reset instructions'
```
Take a look at our locale file to check all available messages. You may also be interested in one of the many translations that are available on our wiki:
https://github.com/heartcombo/devise/wiki/I18n
Caution: Devise Controllers inherit from ApplicationController. If your app uses multiple locales, you should be sure to set I18n.locale in ApplicationController.
### Test helpers
Devise includes some test helpers for controller and integration tests.
In order to use them, you need to include the respective module in your test
cases/specs.
### Controller tests
Controller tests require that you include `Devise::Test::IntegrationHelpers` on
your test case or its parent `ActionController::TestCase` superclass.
For Rails versions prior to 5, include `Devise::Test::ControllerHelpers` instead, since the superclass
for controller tests was changed to ActionDispatch::IntegrationTest
(for more details, see the [Integration tests](#integration-tests) section).
```ruby
class PostsControllerTest < ActionController::TestCase
include Devise::Test::IntegrationHelpers # Rails >= 5
end
```
```ruby
class PostsControllerTest < ActionController::TestCase
include Devise::Test::ControllerHelpers # Rails < 5
end
```
If you're using RSpec, you can put the following inside a file named
`spec/support/devise.rb` or in your `spec/spec_helper.rb` (or
`spec/rails_helper.rb` if you are using `rspec-rails`):
```ruby
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
end
```
Just be sure that this inclusion is made *after* the `require 'rspec/rails'` directive.
Now you are ready to use the `sign_in` and `sign_out` methods on your controller
tests:
```ruby
sign_in @user
sign_in @user, scope: :admin
```
If you are testing Devise internal controllers or a controller that inherits
from Devise's, you need to tell Devise which mapping should be used before a
request. This is necessary because Devise gets this information from the router,
but since controller tests do not pass through the router, it needs to be stated
explicitly. For example, if you are testing the user scope, simply use:
```ruby
test 'GET new' do
# Mimic the router behavior of setting the Devise scope through the env.
@request.env['devise.mapping'] = Devise.mappings[:user]
# Use the sign_in helper to sign in a fixture `User` record.
sign_in users(:alice)
get :new
# assert something
end
```
### Integration tests
Integration test helpers are available by including the
`Devise::Test::IntegrationHelpers` module.
```ruby
class PostsTests < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
end
```
Now you can use the following `sign_in` and `sign_out` methods in your integration
tests:
```ruby
sign_in users(:bob)
sign_in users(:bob), scope: :admin
sign_out :user
```
RSpec users can include the `IntegrationHelpers` module on their `:feature` specs.
```ruby
RSpec.configure do |config|
config.include Devise::Test::IntegrationHelpers, type: :feature
end
```
Unlike controller tests, integration tests do not need to supply the
`devise.mapping` `env` value, as the mapping can be inferred by the routes that
are executed in your tests.
You can read more about testing your Rails controllers with RSpec in the wiki:
* https://github.com/heartcombo/devise/wiki/How-To:-Test-controllers-with-Rails-(and-RSpec)
### OmniAuth
Devise comes with OmniAuth support out of the box to authenticate with other providers. To use it, simply specify your OmniAuth configuration in `config/initializers/devise.rb`:
```ruby
config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
```
You can read more about OmniAuth support in the wiki:
* https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview
### Configuring multiple models
Devise allows you to set up as many Devise models as you want. If you want to have an Admin model with just authentication and timeout features, in addition to the User model above, just run:
```ruby
# Create a migration with the required fields
create_table :admins do |t|
t.string :email
t.string :encrypted_password
t.timestamps null: false
end
# Inside your Admin model
devise :database_authenticatable, :timeoutable
# Inside your routes
devise_for :admins
# Inside your protected controller
before_action :authenticate_admin!
# Inside your controllers and views
admin_signed_in?
current_admin
admin_session
```
Alternatively, you can simply run the Devise generator.
Keep in mind that those models will have completely different routes. They **do not** and **cannot** share the same controller for sign in, sign out and so on. In case you want to have different roles sharing the same actions, we recommend that you use a role-based approach, by either providing a role column or using a dedicated gem for authorization.
### Active Job Integration
If you are using Active Job to deliver Action Mailer messages in the
background through a queuing back-end, you can send Devise emails through your
existing queue by overriding the `send_devise_notification` method in your model.
```ruby
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver_later
end
```
### Password reset tokens and Rails logs
If you enable the [Recoverable](https://www.rubydoc.info/gems/devise/Devise/Models/Recoverable) module, note that a stolen password reset token could give an attacker access to your application. Devise takes effort to generate random, secure tokens, and stores only token digests in the database, never plaintext. However the default logging behavior in Rails can cause plaintext tokens to leak into log files:
1. Action Mailer logs the entire contents of all outgoing emails to the DEBUG level. Password reset tokens delivered to users in email will be leaked.
2. Active Job logs all arguments to every enqueued job at the INFO level. If you configure Devise to use `deliver_later` to send password reset emails, password reset tokens will be leaked.
Rails sets the production logger level to INFO by default. Consider changing your production logger level to WARN if you wish to prevent tokens from being leaked into your logs. In `config/environments/production.rb`:
```ruby
config.log_level = :warn
```
### Other ORMs
Devise supports ActiveRecord (default) and Mongoid. To select another ORM, simply require it in the initializer file.
### Rails API Mode
Rails 5+ has a built-in [API Mode](https://edgeguides.rubyonrails.org/api_app.html) which optimizes Rails for use as an API (only). Devise is _somewhat_ able to handle applications that are built in this mode without additional modifications in the sense that it should not raise exceptions and the like. But some issues may still arise during `development`/`testing`, as we still don't know the full extent of this compatibility. (For more information, see [issue #4947](https://github.com/heartcombo/devise/issues/4947/))
#### Supported Authentication Strategies
API-only applications don't support browser-based authentication via cookies, which is devise's default. Yet, devise can still provide authentication out of the box in those cases with the `http_authenticatable` strategy, which uses HTTP Basic Auth and authenticates the user on each request. (For more info, see this wiki article for [How To: Use HTTP Basic Authentication](https://github.com/heartcombo/devise/wiki/How-To:-Use-HTTP-Basic-Authentication))
The devise default for HTTP Auth is disabled, so it will need to be enabled in the devise initializer for the database strategy:
```ruby
config.http_authenticatable = [:database]
```
This restriction does not limit you from implementing custom warden strategies, either in your application or via gem-based extensions for devise.
A common authentication strategy for APIs is token-based authentication. For more information on extending devise to support this type of authentication and others, see the wiki article for [Simple Token Authentication Examples and alternatives](https://github.com/heartcombo/devise/wiki/How-To:-Simple-Token-Authentication-Example#alternatives) or this blog post on [Custom authentication methods with Devise](http://blog.plataformatec.com.br/2019/01/custom-authentication-methods-with-devise/).
#### Testing
API Mode changes the order of the middleware stack, and this can cause problems for `Devise::Test::IntegrationHelpers`. This problem usually surfaces as an ```undefined method `[]=' for nil:NilClass``` error when using integration test helpers, such as `#sign_in`. The solution is simply to reorder the middlewares by adding the following to test.rb:
```ruby
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Cookies
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Session::CookieStore
```
For a deeper understanding of this, review [this issue](https://github.com/heartcombo/devise/issues/4696).
Additionally be mindful that without views supported, some email-based flows from Confirmable, Recoverable and Lockable are not supported directly at this time.
## Additional information
### Warden
Devise is based on Warden, which is a general Rack authentication framework created by Daniel Neighman. We encourage you to read more about Warden here:
https://github.com/wardencommunity/warden
## License
MIT License.
Copyright 2020-CURRENT Rafael França, Carlos Antonio da Silva.
Copyright 2009-2019 Plataformatec.
The Devise logo is licensed under [Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License](https://creativecommons.org/licenses/by-nc-nd/4.0/).
================================================
FILE: Rakefile
================================================
# encoding: UTF-8
# frozen_string_literal: true
require 'bundler/gem_tasks'
require 'rake/testtask'
require 'rdoc/task'
desc 'Default: run tests for all ORMs.'
task default: :test
desc 'Run Devise tests for all ORMs.'
task :pre_commit do
Dir[File.join(File.dirname(__FILE__), 'test', 'orm', '*.rb')].each do |file|
orm = File.basename(file).split(".").first
# "Some day, my son, rake's inner wisdom will reveal itself. Until then,
# take this `system` -- may its brute force protect you well."
exit 1 unless system "rake test DEVISE_ORM=#{orm}"
end
end
desc 'Run Devise unit tests.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
t.warning = false
end
desc 'Generate documentation for Devise.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Devise'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README.md')
rdoc.rdoc_files.include('lib/**/*.rb')
end
================================================
FILE: app/controllers/devise/confirmations_controller.rb
================================================
# frozen_string_literal: true
class Devise::ConfirmationsController < DeviseController
# GET /resource/confirmation/new
def new
self.resource = resource_class.new
end
# POST /resource/confirmation
def create
self.resource = resource_class.send_confirmation_instructions(resource_params)
yield resource if block_given?
if successfully_sent?(resource)
respond_with({}, location: after_resending_confirmation_instructions_path_for(resource_name))
else
respond_with(resource)
end
end
# GET /resource/confirmation?confirmation_token=abcdef
def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
yield resource if block_given?
if resource.errors.empty?
set_flash_message!(:notice, :confirmed)
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
else
# TODO: use `error_status` when the default changes to `:unprocessable_entity` / `:unprocessable_content`.
respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
end
end
protected
# The path used after resending confirmation instructions.
def after_resending_confirmation_instructions_path_for(resource_name)
is_navigational_format? ? new_session_path(resource_name) : '/'
end
# The path used after confirmation.
def after_confirmation_path_for(resource_name, resource)
if signed_in?(resource_name)
signed_in_root_path(resource)
else
new_session_path(resource_name)
end
end
def translation_scope
'devise.confirmations'
end
end
================================================
FILE: app/controllers/devise/omniauth_callbacks_controller.rb
================================================
# frozen_string_literal: true
class Devise::OmniauthCallbacksController < DeviseController
prepend_before_action { request.env["devise.skip_timeout"] = true }
def passthru
render status: 404, plain: "Not found. Authentication passthru."
end
def failure
set_flash_message! :alert, :failure, kind: OmniAuth::Utils.camelize(failed_strategy.name), reason: failure_message
redirect_to after_omniauth_failure_path_for(resource_name)
end
protected
def failed_strategy
request.respond_to?(:get_header) ? request.get_header("omniauth.error.strategy") : request.env["omniauth.error.strategy"]
end
def failure_message
exception = request.respond_to?(:get_header) ? request.get_header("omniauth.error") : request.env["omniauth.error"]
error = exception.error_reason if exception.respond_to?(:error_reason)
error ||= exception.error if exception.respond_to?(:error)
error ||= (request.respond_to?(:get_header) ? request.get_header("omniauth.error.type") : request.env["omniauth.error.type"]).to_s
error.to_s.humanize if error
end
def after_omniauth_failure_path_for(scope)
new_session_path(scope)
end
def translation_scope
'devise.omniauth_callbacks'
end
end
================================================
FILE: app/controllers/devise/passwords_controller.rb
================================================
# frozen_string_literal: true
class Devise::PasswordsController < DeviseController
prepend_before_action :require_no_authentication
# Render the #edit only if coming from a reset password email link
append_before_action :assert_reset_token_passed, only: :edit
# GET /resource/password/new
def new
self.resource = resource_class.new
end
# POST /resource/password
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
yield resource if block_given?
if successfully_sent?(resource)
respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name))
else
respond_with(resource)
end
end
# GET /resource/password/edit?reset_password_token=abcdef
def edit
self.resource = resource_class.new
set_minimum_password_length
resource.reset_password_token = params[:reset_password_token]
end
# PUT /resource/password
def update
self.resource = resource_class.reset_password_by_token(resource_params)
yield resource if block_given?
if resource.errors.empty?
resource.unlock_access! if unlockable?(resource)
if sign_in_after_reset_password?
flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
set_flash_message!(:notice, flash_message)
resource.after_database_authentication
sign_in(resource_name, resource)
else
set_flash_message!(:notice, :updated_not_active)
end
respond_with resource, location: after_resetting_password_path_for(resource)
else
set_minimum_password_length
respond_with resource
end
end
protected
def after_resetting_password_path_for(resource)
sign_in_after_reset_password? ? after_sign_in_path_for(resource) : new_session_path(resource_name)
end
# The path used after sending reset password instructions
def after_sending_reset_password_instructions_path_for(resource_name)
new_session_path(resource_name) if is_navigational_format?
end
# Check if a reset_password_token is provided in the request
def assert_reset_token_passed
if params[:reset_password_token].blank?
set_flash_message(:alert, :no_token)
redirect_to new_session_path(resource_name)
end
end
# Check if the user should be signed in automatically after resetting the password.
def sign_in_after_reset_password?
resource_class.sign_in_after_reset_password
end
# Check if proper Lockable module methods are present & unlock strategy
# allows to unlock resource on password reset
def unlockable?(resource)
resource.respond_to?(:unlock_access!) &&
resource.respond_to?(:unlock_strategy_enabled?) &&
resource.unlock_strategy_enabled?(:email)
end
def translation_scope
'devise.passwords'
end
end
================================================
FILE: app/controllers/devise/registrations_controller.rb
================================================
# frozen_string_literal: true
class Devise::RegistrationsController < DeviseController
prepend_before_action :require_no_authentication, only: [:new, :create, :cancel]
prepend_before_action :authenticate_scope!, only: [:edit, :update, :destroy]
prepend_before_action :set_minimum_password_length, only: [:new, :edit]
# GET /resource/sign_up
def new
build_resource
yield resource if block_given?
respond_with resource
end
# POST /resource
def create
build_resource(sign_up_params)
resource.save
yield resource if block_given?
if resource.persisted?
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
end
# GET /resource/edit
def edit
render :edit
end
# PUT /resource
# We need to use a copy of the resource because we don't want to change
# the current user in place.
def update
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)
resource_updated = update_resource(resource, account_update_params)
yield resource if block_given?
if resource_updated
set_flash_message_for_update(resource, prev_unconfirmed_email)
bypass_sign_in resource, scope: resource_name if sign_in_after_change_password?
respond_with resource, location: after_update_path_for(resource)
else
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
end
# DELETE /resource
def destroy
resource.destroy
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
set_flash_message! :notice, :destroyed
yield resource if block_given?
respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name), status: Devise.responder.redirect_status }
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
expire_data_after_sign_in!
redirect_to new_registration_path(resource_name)
end
protected
# By default we want to require a password checks on update.
# You can overwrite this method in your own RegistrationsController.
def update_resource(resource, params)
resource.update_with_password(params)
end
# Build a devise resource passing in the session. Useful to move
# temporary session data to the newly created user.
def build_resource(hash = {})
self.resource = resource_class.new_with_session(hash, session)
end
# Signs in a user on sign up. You can overwrite this method in your own
# RegistrationsController.
def sign_up(resource_name, resource)
sign_in(resource_name, resource)
end
# The path used after sign up. You need to overwrite this method
# in your own RegistrationsController.
def after_sign_up_path_for(resource)
after_sign_in_path_for(resource) if is_navigational_format?
end
# The path used after sign up for inactive accounts. You need to overwrite
# this method in your own RegistrationsController.
def after_inactive_sign_up_path_for(resource)
scope = Devise::Mapping.find_scope!(resource)
router_name = Devise.mappings[scope].router_name
context = router_name ? send(router_name) : self
context.respond_to?(:root_path) ? context.root_path : "/"
end
# The default url to be used after updating a resource. You need to overwrite
# this method in your own RegistrationsController.
def after_update_path_for(resource)
sign_in_after_change_password? ? signed_in_root_path(resource) : new_session_path(resource_name)
end
# Authenticates the current scope and gets the current resource from the session.
def authenticate_scope!
send(:"authenticate_#{resource_name}!", force: true)
self.resource = send(:"current_#{resource_name}")
end
# Check if the user should be signed in automatically after updating the password.
def sign_in_after_change_password?
return true if account_update_params[:password].blank?
resource_class.sign_in_after_change_password
end
def sign_up_params
devise_parameter_sanitizer.sanitize(:sign_up)
end
def account_update_params
devise_parameter_sanitizer.sanitize(:account_update)
end
def translation_scope
'devise.registrations'
end
private
def set_flash_message_for_update(resource, prev_unconfirmed_email)
return unless is_flashing_format?
flash_key = if update_needs_confirmation?(resource, prev_unconfirmed_email)
:update_needs_confirmation
elsif sign_in_after_change_password?
:updated
else
:updated_but_not_signed_in
end
set_flash_message :notice, flash_key
end
def update_needs_confirmation?(resource, previous)
resource.respond_to?(:pending_reconfirmation?) &&
resource.pending_reconfirmation? &&
previous != resource.unconfirmed_email
end
end
================================================
FILE: app/controllers/devise/sessions_controller.rb
================================================
# frozen_string_literal: true
class Devise::SessionsController < DeviseController
prepend_before_action :require_no_authentication, only: [:new, :create]
prepend_before_action :allow_params_authentication!, only: :create
prepend_before_action :verify_signed_out_user, only: :destroy
prepend_before_action(only: [:create, :destroy]) { request.env["devise.skip_timeout"] = true }
# GET /resource/sign_in
def new
self.resource = resource_class.new(sign_in_params)
clean_up_passwords(resource)
yield resource if block_given?
respond_with(resource, serialize_options(resource))
end
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message!(:notice, :signed_in)
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
# DELETE /resource/sign_out
def destroy
signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
set_flash_message! :notice, :signed_out if signed_out
yield if block_given?
respond_to_on_destroy(non_navigational_status: :no_content)
end
protected
def sign_in_params
devise_parameter_sanitizer.sanitize(:sign_in)
end
def serialize_options(resource)
methods = resource_class.authentication_keys.dup
methods = methods.keys if methods.is_a?(Hash)
methods << :password if resource.respond_to?(:password)
{ methods: methods, only: [:password] }
end
def auth_options
{ scope: resource_name, recall: "#{controller_path}#new", locale: I18n.locale }
end
def translation_scope
'devise.sessions'
end
private
# Check if there is no signed in user before doing the sign out.
#
# If there is no signed in user, it will set the flash message and redirect
# to the after_sign_out path.
def verify_signed_out_user
if all_signed_out?
set_flash_message! :notice, :already_signed_out
respond_to_on_destroy(non_navigational_status: :unauthorized)
end
end
def all_signed_out?
users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) }
users.all?(&:blank?)
end
def respond_to_on_destroy(non_navigational_status: :no_content)
# We actually need to hardcode this as Rails default responder doesn't
# support returning empty response on GET request
respond_to do |format|
format.all { head non_navigational_status }
format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name), status: Devise.responder.redirect_status }
end
end
end
================================================
FILE: app/controllers/devise/unlocks_controller.rb
================================================
# frozen_string_literal: true
class Devise::UnlocksController < DeviseController
prepend_before_action :require_no_authentication
# GET /resource/unlock/new
def new
self.resource = resource_class.new
end
# POST /resource/unlock
def create
self.resource = resource_class.send_unlock_instructions(resource_params)
yield resource if block_given?
if successfully_sent?(resource)
respond_with({}, location: after_sending_unlock_instructions_path_for(resource))
else
respond_with(resource)
end
end
# GET /resource/unlock?unlock_token=abcdef
def show
self.resource = resource_class.unlock_access_by_token(params[:unlock_token])
yield resource if block_given?
if resource.errors.empty?
set_flash_message! :notice, :unlocked
respond_with_navigational(resource){ redirect_to after_unlock_path_for(resource) }
else
# TODO: use `error_status` when the default changes to `:unprocessable_entity` / `:unprocessable_content`.
respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
end
end
protected
# The path used after sending unlock password instructions
def after_sending_unlock_instructions_path_for(resource)
new_session_path(resource) if is_navigational_format?
end
# The path used after unlocking the resource
def after_unlock_path_for(resource)
new_session_path(resource) if is_navigational_format?
end
def translation_scope
'devise.unlocks'
end
end
================================================
FILE: app/controllers/devise_controller.rb
================================================
# frozen_string_literal: true
# All Devise controllers are inherited from here.
class DeviseController < Devise.parent_controller.constantize
include Devise::Controllers::ScopedViews
if respond_to?(:helper)
helper DeviseHelper
end
if respond_to?(:helper_method)
helpers = %w(resource scope_name resource_name signed_in_resource
resource_class resource_params devise_mapping)
helper_method(*helpers)
end
prepend_before_action :assert_is_devise_resource!
self.responder = Devise.responder
respond_to :html if mimes_for_respond_to.empty?
# Override prefixes to consider the scoped view.
# Notice we need to check for the request due to a bug in
# Action Controller tests that forces _prefixes to be
# loaded before even having a request object.
#
# This method should be public as it is in ActionPack
# itself. Changing its visibility may break other gems.
def _prefixes #:nodoc:
@_prefixes ||= if self.class.scoped_views? && request && devise_mapping
["#{devise_mapping.scoped_path}/#{controller_name}"] + super
else
super
end
end
# Override internal methods to exclude `_prefixes` from action methods since
# we override it above.
#
# There was an intentional change in Rails 7.1 that will allow it to become
# an action method because it's a public method of a non-abstract controller,
# but we also can't make this abstract because it can affect potential actions
# defined in the parent controller, so instead we ensure `_prefixes` is going
# to be considered internal. (and thus, won't become an action method.)
# Ref: https://github.com/rails/rails/pull/48699
def self.internal_methods #:nodoc:
super << :_prefixes
end
protected
# 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
# 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}.
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
get "/some/route" => "some_devise_controller"
end
2) You are testing a Devise controller bypassing the router.
If so, you can explicitly tell Devise which mapping to use:
@request.env["devise.mapping"] = Devise.mappings[:user]
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 AbstractController::ActionNotFound, msg
end
# Sets the resource creating an instance variable
def resource=(new_resource)
instance_variable_set(:"@#{resource_name}", new_resource)
end
# Helper for use in before_actions where no authentication is required.
#
# Example:
# before_action :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)
set_flash_message(:alert, 'already_authenticated', scope: 'devise.failure')
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
true
end
end
# Sets the flash message with :key, using I18n. By default you are able
# to set up your messages using specific resource scope, and if no message is
# found we look to the default scope. Set the "now" options key to a true
# value to populate the flash.now hash in lieu of the default flash hash (so
# the flash message will be available to the current action instead of the
# next action).
# 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 = {})
message = find_message(kind, options)
if options[:now]
flash.now[key] = message if message.present?
else
flash[key] = message if message.present?
end
end
# Sets flash message if is_flashing_format? equals true
def set_flash_message!(key, kind, options = {})
if is_flashing_format?
set_flash_message(key, kind, options)
end
end
# Sets minimum password length to show to user
def set_minimum_password_length
if devise_mapping.validatable?
@minimum_password_length = resource_class.password_length.min
end
end
def devise_i18n_options(options)
options
end
# Get message for given
def find_message(kind, options = {})
options[:scope] ||= translation_scope
options[:default] = Array(options[:default]).unshift(kind.to_sym)
options[:resource_name] = resource_name
options = devise_i18n_options(options)
I18n.t("#{options[:resource_name]}.#{kind}", **options)
end
# Controllers inheriting DeviseController are advised to override this
# method so that other controllers inheriting from them would use
# existing translations.
def translation_scope
"devise.#{controller_name}"
end
def clean_up_passwords(object)
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 resource_params
params.fetch(resource_name, {})
end
ActiveSupport.run_load_hooks(:devise_controller, self)
end
================================================
FILE: app/helpers/devise_helper.rb
================================================
# frozen_string_literal: true
# Keeping the helper around for backward compatibility.
module DeviseHelper
end
================================================
FILE: app/mailers/devise/mailer.rb
================================================
# frozen_string_literal: true
if defined?(ActionMailer)
class Devise::Mailer < Devise.parent_mailer.constantize
include Devise::Mailers::Helpers
def confirmation_instructions(record, token, opts = {})
@token = token
devise_mail(record, :confirmation_instructions, opts)
end
def reset_password_instructions(record, token, opts = {})
@token = token
devise_mail(record, :reset_password_instructions, opts)
end
def unlock_instructions(record, token, opts = {})
@token = token
devise_mail(record, :unlock_instructions, opts)
end
def email_changed(record, opts = {})
devise_mail(record, :email_changed, opts)
end
def password_change(record, opts = {})
devise_mail(record, :password_change, opts)
end
end
end
================================================
FILE: app/views/devise/confirmations/new.html.erb
================================================
<h2>Resend confirmation instructions</h2>
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<p><%= f.label :email %></p>
<p><%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %></p>
</div>
<div class="actions">
<%= f.submit "Resend confirmation instructions" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
================================================
FILE: app/views/devise/mailer/confirmation_instructions.html.erb
================================================
<p>Welcome <%= @email %>!</p>
<p>You can confirm your account email through the link below:</p>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
================================================
FILE: app/views/devise/mailer/email_changed.html.erb
================================================
<p>Hello <%= @email %>!</p>
<% if @resource.try(:unconfirmed_email?) %>
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
<% else %>
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
<% end %>
================================================
FILE: app/views/devise/mailer/password_change.html.erb
================================================
<p>Hello <%= @resource.email %>!</p>
<p>We're contacting you to notify you that your password has been changed.</p>
================================================
FILE: app/views/devise/mailer/reset_password_instructions.html.erb
================================================
<p>Hello <%= @resource.email %>!</p>
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
================================================
FILE: app/views/devise/mailer/unlock_instructions.html.erb
================================================
<p>Hello <%= @resource.email %>!</p>
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
<p>Click the link below to unlock your account:</p>
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
================================================
FILE: app/views/devise/passwords/edit.html.erb
================================================
<h2>Change your password</h2>
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<%= f.hidden_field :reset_password_token %>
<div class="field">
<p><%= f.label :password, "New password" %></p>
<% if @minimum_password_length %>
<p><em>(<%= @minimum_password_length %> characters minimum)</em></p>
<% end %>
<p><%= f.password_field :password, autofocus: true, autocomplete: "new-password" %></p>
</div>
<div class="field">
<p><%= f.label :password_confirmation, "Confirm new password" %></p>
<p><%= f.password_field :password_confirmation, autocomplete: "new-password" %></p>
</div>
<div class="actions">
<%= f.submit "Change my password" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
================================================
FILE: app/views/devise/passwords/new.html.erb
================================================
<h2>Forgot your password?</h2>
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<p><%= f.label :email %></p>
<p><%= f.email_field :email, autofocus: true, autocomplete: "email" %></p>
</div>
<div class="actions">
<%= f.submit "Send me password reset instructions" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
================================================
FILE: app/views/devise/registrations/edit.html.erb
================================================
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<p><%= f.label :email %></p>
<p><%= f.email_field :email, autofocus: true, autocomplete: "email" %></p>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="field">
<p><%= f.label :password %> <i>(leave blank if you don't want to change it)</i></p>
<p><%= f.password_field :password, autocomplete: "new-password" %></p>
<% if @minimum_password_length %>
<p><em><%= @minimum_password_length %> characters minimum</em></p>
<% end %>
</div>
<div class="field">
<p><%= f.label :password_confirmation %></p>
<p><%= f.password_field :password_confirmation, autocomplete: "new-password" %></p>
</div>
<div class="field">
<p><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i></p>
<p><%= f.password_field :current_password, autocomplete: "current-password" %></p>
</div>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
<h3>Cancel my account</h3>
<div>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %></div>
<%= link_to "Back", :back %>
================================================
FILE: app/views/devise/registrations/new.html.erb
================================================
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<p><%= f.label :email %></p>
<p><%= f.email_field :email, autofocus: true, autocomplete: "email" %></p>
</div>
<div class="field">
<p><%= f.label :password %></p>
<% if @minimum_password_length %>
<p><em>(<%= @minimum_password_length %> characters minimum)</em></p>
<% end %>
<p><%= f.password_field :password, autocomplete: "new-password" %></p>
</div>
<div class="field">
<p><%= f.label :password_confirmation %></p>
<p><%= f.password_field :password_confirmation, autocomplete: "new-password" %></p>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
================================================
FILE: app/views/devise/sessions/new.html.erb
================================================
<h2>Log in</h2>
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="field">
<p><%= f.label :email %></p>
<p><%= f.email_field :email, autofocus: true, autocomplete: "email" %></p>
</div>
<div class="field">
<p><%= f.label :password %></p>
<p><%= f.password_field :password, autocomplete: "current-password" %></p>
</div>
<% if devise_mapping.rememberable? %>
<div class="field">
<p><%= f.check_box :remember_me %></p>
<p><%= f.label :remember_me %></p>
</div>
<% end %>
<div class="actions">
<%= f.submit "Log in" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
================================================
FILE: app/views/devise/shared/_error_messages.html.erb
================================================
<% if resource.errors.any? %>
<div id="error_explanation" data-turbo-temporary>
<h2>
<%= I18n.t("errors.messages.not_saved",
count: resource.errors.count,
resource: resource.class.model_name.human.downcase)
%>
</h2>
<ul>
<% resource.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
================================================
FILE: app/views/devise/shared/_links.html.erb
================================================
<%- if controller_name != 'sessions' %>
<p><%= link_to "Log in", new_session_path(resource_name) %></p>
<% end %>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<p><%= link_to "Sign up", new_registration_path(resource_name) %></p>
<% end %>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
<p><%= link_to "Forgot your password?", new_password_path(resource_name) %></p>
<% end %>
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
<p><%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %></p>
<% end %>
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
<p><%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %></p>
<% end %>
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<p><%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %></p>
<% end %>
<% end %>
================================================
FILE: app/views/devise/unlocks/new.html.erb
================================================
<h2>Resend unlock instructions</h2>
<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<p><%= f.label :email %></p>
<p><%= f.email_field :email, autofocus: true, autocomplete: "email" %></p>
</div>
<div class="actions">
<%= f.submit "Resend unlock instructions" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
================================================
FILE: bin/test
================================================
#!/usr/bin/env ruby
$: << File.expand_path(File.expand_path('../../test', __FILE__))
require 'bundler/setup'
require 'rails/test_unit/runner'
require 'rails/test_unit/reporter'
require 'rails/test_unit/line_filtering'
Rails::TestUnitReporter.executable = 'bin/test'
Rails::TestUnit::Runner.parse_options(ARGV)
Rails::TestUnit::Runner.run(ARGV)
================================================
FILE: config/locales/en.yml
================================================
# Additional translations at https://github.com/heartcombo/devise/wiki/I18n
en:
devise:
confirmations:
confirmed: "Your email address has been successfully confirmed."
send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes."
send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes."
failure:
already_authenticated: "You are already signed in."
inactive: "Your account is not activated yet."
invalid: "Invalid %{authentication_keys} or password."
locked: "Your account is locked."
last_attempt: "You have one more attempt before your account is locked."
not_found_in_database: "Invalid %{authentication_keys} 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."
mailer:
confirmation_instructions:
subject: "Confirmation instructions"
reset_password_instructions:
subject: "Reset password instructions"
unlock_instructions:
subject: "Unlock instructions"
email_changed:
subject: "Email Changed"
password_change:
subject: "Password Changed"
omniauth_callbacks:
failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
success: "Successfully authenticated from %{kind} account."
passwords:
no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."
send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
updated: "Your password has been changed successfully. You are now signed in."
updated_not_active: "Your password has been changed successfully."
registrations:
destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon."
signed_up: "Welcome! You have signed up successfully."
signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address."
updated: "Your account has been updated successfully."
updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again."
sessions:
signed_in: "Signed in successfully."
signed_out: "Signed out successfully."
already_signed_out: "Signed out successfully."
unlocks:
send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes."
send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes."
unlocked: "Your account has been unlocked successfully. Please sign in to continue."
errors:
messages:
already_confirmed: "was already confirmed, please try signing in"
confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
expired: "has expired, please request a new one"
not_found: "not found"
not_locked: "was not locked"
not_saved:
one: "1 error prohibited this %{resource} from being saved:"
other: "%{count} errors prohibited this %{resource} from being saved:"
================================================
FILE: devise.gemspec
================================================
# -*- encoding: utf-8 -*-
# frozen_string_literal: true
$:.push File.expand_path("../lib", __FILE__)
require "devise/version"
Gem::Specification.new do |s|
s.name = "devise"
s.version = Devise::VERSION.dup
s.platform = Gem::Platform::RUBY
s.licenses = ["MIT"]
s.summary = "Flexible authentication solution for Rails with Warden"
s.email = "heartcombo.oss@gmail.com"
s.homepage = "https://github.com/heartcombo/devise"
s.description = "Flexible authentication solution for Rails with Warden"
s.authors = ['José Valim', 'Carlos Antônio']
s.metadata = {
"homepage_uri" => "https://github.com/heartcombo/devise",
"documentation_uri" => "https://rubydoc.info/github/heartcombo/devise",
"changelog_uri" => "https://github.com/heartcombo/devise/blob/main/CHANGELOG.md",
"source_code_uri" => "https://github.com/heartcombo/devise",
"bug_tracker_uri" => "https://github.com/heartcombo/devise/issues",
"wiki_uri" => "https://github.com/heartcombo/devise/wiki"
}
s.files = Dir["{app,config,lib}/**/*", "CHANGELOG.md", "MIT-LICENSE", "README.md"]
s.require_paths = ["lib"]
s.required_ruby_version = '>= 2.7.0'
s.add_dependency("warden", "~> 1.2.3")
s.add_dependency("orm_adapter", "~> 0.1")
s.add_dependency("bcrypt", "~> 3.0")
s.add_dependency("railties", ">= 7.0")
s.add_dependency("responders")
end
================================================
FILE: gemfiles/Gemfile-rails-7-0
================================================
source "https://rubygems.org"
gemspec path: ".."
gem "rails", "~> 7.0.0"
gem "omniauth"
gem "omniauth-oauth2"
gem "rdoc"
gem "rails-controller-testing"
gem "responders", "~> 3.1"
group :test do
gem "omniauth-facebook"
gem "omniauth-openid"
gem "rexml"
gem "timecop"
gem "webrat", "0.7.3", require: false
gem "mocha", "~> 2.1", require: false
gem "minitest", "< 6"
gem "ostruct"
end
platforms :ruby do
gem "sqlite3", "~> 1.4"
end
group :mongoid do
gem "mongoid", "~> 7.5"
end
================================================
FILE: gemfiles/Gemfile-rails-7-1
================================================
source "https://rubygems.org"
gemspec path: ".."
gem "rails", "~> 7.1.0"
gem "omniauth"
gem "omniauth-oauth2"
gem "rdoc"
gem "rails-controller-testing"
gem "responders", "~> 3.1"
group :test do
gem "omniauth-facebook"
gem "omniauth-openid"
gem "rexml"
gem "timecop"
gem "webrat"
gem "mocha", "~> 2.1", require: false
gem "minitest", "< 6"
gem "ostruct"
end
platforms :ruby do
gem "sqlite3", "~> 1.4"
end
group :mongoid do
gem "mongoid", "~> 8.1"
end
================================================
FILE: gemfiles/Gemfile-rails-7-2
================================================
source "https://rubygems.org"
gemspec path: ".."
gem "rails", "~> 7.2.0"
gem "omniauth"
gem "omniauth-oauth2"
gem "rdoc"
gem "rails-controller-testing"
gem "responders", "~> 3.1"
group :test do
gem "omniauth-facebook"
gem "omniauth-openid"
gem "rexml"
gem "timecop"
gem "webrat", require: false
gem "mocha", "~> 2.1", require: false
gem "minitest", "< 6"
gem "ostruct"
end
platforms :ruby do
gem "sqlite3"
end
group :mongoid do
gem "mongoid", "~> 8.1"
end
================================================
FILE: gemfiles/Gemfile-rails-8-0
================================================
source "https://rubygems.org"
gemspec path: ".."
gem "rails", "~> 8.0.0"
gem "omniauth"
gem "omniauth-oauth2"
gem "rdoc"
gem "rails-controller-testing"
gem "responders", "~> 3.1"
group :test do
gem "omniauth-facebook"
gem "omniauth-openid"
gem "rexml"
gem "timecop"
gem 'webrat'
gem "mocha", "~> 2.1", require: false
gem "minitest", "< 6"
gem "ostruct"
end
platforms :ruby do
gem "sqlite3"
end
group :mongoid do
gem "mongoid", "~> 8.1"
end
================================================
FILE: gemfiles/Gemfile-rails-main
================================================
source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "main"
gem "omniauth"
gem "omniauth-oauth2"
gem "rdoc"
gem "rails-controller-testing"
gem "responders", "~> 3.1"
group :test do
gem "omniauth-facebook"
gem "omniauth-openid"
gem "rexml"
gem "timecop"
gem "webrat", "0.7.3", require: false
gem "mocha", "~> 2.1", require: false
gem "minitest", "< 6"
gem "ostruct"
end
platforms :ruby do
gem "sqlite3"
end
group :mongoid do
gem "mongoid", github: "mongodb/mongoid", branch: "master"
end
================================================
FILE: guides/bug_report_templates/integration_test.rb
================================================
# frozen_string_literal: true
begin
require 'bundler/inline'
rescue LoadError => e
$stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler'
raise e
end
gemfile(true) do
source 'https://rubygems.org'
# Activate the gem you are reporting the issue against.
gem 'rails', '~> 4.2.0'
gem 'devise', '~> 4.0'
gem 'sqlite3'
gem 'byebug'
end
require 'rack/test'
require 'action_controller/railtie'
require 'active_record'
require 'devise/rails/routes'
require 'devise/rails/warden_compat'
ActiveRecord::Base.establish_connection( adapter: :sqlite3, database: ':memory:')
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
t.string :email, null: false
t.string :encrypted_password, null: true
t.timestamps null: false
end
end
end
Devise.setup do |config|
require 'devise/orm/active_record'
config.secret_key = 'secret_key_base'
end
class TestApp < Rails::Application
config.root = File.dirname(__FILE__)
config.session_store :cookie_store, key: 'cookie_store_key'
secrets.secret_token = 'secret_token'
secrets.secret_key_base = 'secret_key_base'
config.eager_load = false
config.middleware.use Warden::Manager do |config|
Devise.warden_config = config
end
config.logger = Logger.new($stdout)
Rails.logger = config.logger
end
Rails.application.initialize!
DeviseCreateUsers.migrate(:up)
class User < ActiveRecord::Base
devise :database_authenticatable
end
Rails.application.routes.draw do
devise_for :users
get '/' => 'test#index'
end
class ApplicationController < ActionController::Base
end
class TestController < ApplicationController
include Rails.application.routes.url_helpers
before_action :authenticate_user!
def index
render plain: 'Home'
end
end
require 'minitest/autorun'
class BugTest < ActionDispatch::IntegrationTest
include Rack::Test::Methods
include Warden::Test::Helpers
def test_returns_success
Warden.test_mode!
login_as User.create!(email: 'test@test.com', password: 'test123456', password_confirmation: 'test123456')
get '/'
assert last_response.ok?
end
private
def app
Rails.application
end
end
================================================
FILE: lib/devise/controllers/helpers.rb
================================================
# frozen_string_literal: true
module Devise
module Controllers
# Those helpers are convenience methods added to ApplicationController.
module Helpers
extend ActiveSupport::Concern
include Devise::Controllers::SignInOut
include Devise::Controllers::StoreLocation
included do
if respond_to?(:helper_method)
helper_method :warden, :signed_in?, :devise_controller?
end
end
module ClassMethods
# Define authentication filters and accessor helpers for a group of mappings.
# These methods are useful when you are working with multiple mappings that
# share some functionality. They are pretty much the same as the ones
# defined for normal mappings.
#
# Example:
#
# inside BlogsController (or any other controller, it doesn't matter which):
# devise_group :blogger, contains: [:user, :admin]
#
# Generated methods:
# authenticate_blogger! # Redirects unless user or admin are signed in
# blogger_signed_in? # Checks whether there is either a user or an admin signed in
# current_blogger # Currently signed in user or admin
# current_bloggers # Currently signed in user and admin
#
# Use:
# before_action :authenticate_blogger! # Redirects unless either a user or an admin are authenticated
# before_action ->{ authenticate_blogger! :admin } # Redirects to the admin login page
# current_blogger :user # Preferably returns a User if one is signed in
#
def devise_group(group_name, opts = {})
mappings = "[#{ opts[:contains].map { |m| ":#{m}" }.join(',') }]"
class_eval <<-METHODS, __FILE__, __LINE__ + 1
def authenticate_#{group_name}!(favorite = nil, opts = {})
unless #{group_name}_signed_in?
mappings = #{mappings}
mappings.unshift mappings.delete(favorite.to_sym) if favorite
mappings.each do |mapping|
opts[:scope] = mapping
opts[:locale] = I18n.locale
warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
end
end
end
def #{group_name}_signed_in?
#{mappings}.any? do |mapping|
warden.authenticate?(scope: mapping)
end
end
def current_#{group_name}(favorite = nil)
mappings = #{mappings}
mappings.unshift mappings.delete(favorite.to_sym) if favorite
mappings.each do |mapping|
current = warden.authenticate(scope: mapping)
return current if current
end
nil
end
def current_#{group_name.to_s.pluralize}
#{mappings}.map do |mapping|
warden.authenticate(scope: mapping)
end.compact
end
if respond_to?(:helper_method)
helper_method "current_#{group_name}", "current_#{group_name.to_s.pluralize}", "#{group_name}_signed_in?"
end
METHODS
end
def log_process_action(payload)
payload[:status] ||= 401 unless payload[:exception]
super
end
end
# Define authentication filters and accessor helpers based on mappings.
# These filters should be used inside the controllers as before_actions,
# so you can control the scope of the user who should be signed in to
# access that specific controller/action.
# Example:
#
# Roles:
# User
# Admin
#
# Generated methods:
# authenticate_user! # Signs user in or redirect
# authenticate_admin! # Signs admin in or redirect
# user_signed_in? # Checks whether there is a user signed in or not
# admin_signed_in? # Checks whether there is an admin signed in or not
# current_user # Current signed in user
# current_admin # Current signed in admin
# user_session # Session data available only to the user scope
# admin_session # Session data available only to the admin scope
#
# Use:
# before_action :authenticate_user! # Tell devise to use :user map
# before_action :authenticate_admin! # Tell devise to use :admin map
#
def self.define_helpers(mapping) #:nodoc:
mapping = mapping.name
class_eval <<-METHODS, __FILE__, __LINE__ + 1
def authenticate_#{mapping}!(opts = {})
opts[:scope] = :#{mapping}
opts[:locale] = I18n.locale
warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
end
def #{mapping}_signed_in?
!!current_#{mapping}
end
def current_#{mapping}
@current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end
def #{mapping}_session
current_#{mapping} && warden.session(:#{mapping})
end
METHODS
ActiveSupport.on_load(:action_controller) do
if respond_to?(:helper_method)
helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session"
end
end
end
# The main accessor for the warden proxy instance
def warden
request.env['warden'] or raise MissingWarden
end
# Return true if it's a devise_controller. false to all controllers unless
# the controllers defined inside devise. Useful if you want to apply a before
# filter to all controllers, except the ones in devise:
#
# before_action :my_filter, unless: :devise_controller?
def devise_controller?
is_a?(::DeviseController)
end
# Set up a param sanitizer to filter parameters using strong_parameters. See
# lib/devise/parameter_sanitizer.rb for more info. Override this
# method in your application controller to use your own parameter sanitizer.
def devise_parameter_sanitizer
@devise_parameter_sanitizer ||= Devise::ParameterSanitizer.new(resource_class, resource_name, params)
end
# Tell warden that params authentication is allowed for that specific page.
def allow_params_authentication!
request.env["devise.allow_params_authentication"] = true
end
# The scope root url to be used when they're signed in. By default, it first
# tries to find a resource_root_path, otherwise it uses the root_path.
def signed_in_root_path(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
router_name = Devise.mappings[scope].router_name
home_path = "#{scope}_root_path"
context = router_name ? send(router_name) : self
if context.respond_to?(home_path, true)
context.send(home_path)
elsif context.respond_to?(:root_path)
context.root_path
elsif respond_to?(:root_path)
root_path
else
"/"
end
end
# The default url to be used after signing in. This is used by all Devise
# controllers and you can overwrite it in your ApplicationController to
# provide a custom hook for a custom resource.
#
# By default, it first tries to find a valid resource_return_to key in the
# session, then it fallbacks to resource_root_path, otherwise it uses the
# root path. For a user scope, you can define the default url in
# the following way:
#
# get '/users' => 'users#index', as: :user_root # creates user_root_path
#
# namespace :user do
# root 'users#index' # creates user_root_path
# end
#
# If the resource root path is not defined, root_path is used. However,
# if this default is not enough, you can customize it, for example:
#
# def after_sign_in_path_for(resource)
# stored_location_for(resource) ||
# if resource.is_a?(User) && resource.can_publish?
# publisher_url
# else
# super
# end
# end
#
def after_sign_in_path_for(resource_or_scope)
stored_location_for(resource_or_scope) || signed_in_root_path(resource_or_scope)
end
# Method used by sessions controller to sign out a user. You can overwrite
# it in your ApplicationController to provide a custom hook for a custom
# scope. Notice that differently from +after_sign_in_path_for+ this method
# receives a symbol with the scope, and not the resource.
#
# By default it is the root_path.
def after_sign_out_path_for(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
router_name = Devise.mappings[scope].router_name
context = router_name ? send(router_name) : self
context.respond_to?(:root_path) ? context.root_path : "/"
end
# Sign in a user and tries to redirect first to the stored location and
# then to the url specified by after_sign_in_path_for. It accepts the same
# parameters as the sign_in method.
def sign_in_and_redirect(resource_or_scope, *args)
options = args.extract_options!
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource = args.last || resource_or_scope
sign_in(scope, resource, options)
redirect_to after_sign_in_path_for(resource)
end
# Sign out a user and tries to redirect to the url specified by
# after_sign_out_path_for.
def sign_out_and_redirect(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
redirect_path = after_sign_out_path_for(scope)
Devise.sign_out_all_scopes ? sign_out : sign_out(scope)
redirect_to redirect_path
end
# Overwrite Rails' handle unverified request to sign out all scopes,
# clear run strategies and remove cached variables.
def handle_unverified_request
super # call the default behavior which resets/nullifies/raises
request.env["devise.skip_storage"] = true
sign_out_all_scopes(false)
end
def request_format
@request_format ||= request.format.try(:ref)
end
def is_navigational_format?
Devise.navigational_formats.include?(request_format)
end
# Check if flash messages should be emitted. Default is to do it on
# navigational formats
def is_flashing_format?
request.respond_to?(:flash) && is_navigational_format?
end
private
def expire_data_after_sign_out!
Devise.mappings.each { |_,m| instance_variable_set("@current_#{m.name}", nil) }
super
end
end
end
class MissingWarden < StandardError
def initialize
super "Devise could not find the `Warden::Proxy` instance on your request environment.\n" + \
"Make sure that your application is loading Devise and Warden as expected and that " + \
"the `Warden::Manager` middleware is present in your middleware stack.\n" + \
"If you are seeing this on one of your tests, ensure that your tests are either " + \
"executing the Rails middleware stack or that your tests are using the `Devise::Test::ControllerHelpers` " + \
"module to inject the `request.env['warden']` object for you."
end
end
end
================================================
FILE: lib/devise/controllers/rememberable.rb
================================================
# frozen_string_literal: true
module Devise
module Controllers
# A module that may be optionally included in a controller in order
# to provide remember me behavior. Useful when signing in is done
# through a callback, like in OmniAuth.
module Rememberable
# Return default cookie values retrieved from session options.
def self.cookie_values
Rails.configuration.session_options.slice(:path, :domain, :secure)
end
def remember_me_is_active?(resource)
return false unless resource.respond_to?(:remember_me)
scope = Devise::Mapping.find_scope!(resource)
_, token, generated_at = cookies.signed[remember_key(resource, scope)]
resource.remember_me?(token, generated_at)
end
# Remembers the given resource by setting up a cookie
def remember_me(resource)
return if request.env["devise.skip_storage"]
scope = Devise::Mapping.find_scope!(resource)
resource.remember_me!
cookies.signed[remember_key(resource, scope)] = remember_cookie_values(resource)
end
# Forgets the given resource by deleting a cookie
def forget_me(resource)
scope = Devise::Mapping.find_scope!(resource)
resource.forget_me!
cookies.delete(remember_key(resource, scope), forget_cookie_values(resource))
end
protected
def forget_cookie_values(resource)
Devise::Controllers::Rememberable.cookie_values.merge!(resource.rememberable_options)
end
def remember_cookie_values(resource)
options = { httponly: true }
options.merge!(forget_cookie_values(resource))
options.merge!(
value: resource.class.serialize_into_cookie(resource),
expires: resource.remember_expires_at
)
end
def remember_key(resource, scope)
resource.rememberable_options.fetch(:key, "remember_#{scope}_token")
end
end
end
end
================================================
FILE: lib/devise/controllers/responder.rb
================================================
# frozen_string_literal: true
module Devise
module Controllers
# Custom Responder to configure default statuses that only apply to Devise,
# and allow to integrate more easily with Hotwire/Turbo.
class Responder < ActionController::Responder
if respond_to?(:error_status=) && respond_to?(:redirect_status=)
self.error_status = :ok
self.redirect_status = :found
else
# TODO: remove this support for older Rails versions, which aren't supported by Turbo
# and/or responders. It won't allow configuring a custom response, but it allows Devise
# to use these methods and defaults across the implementation more easily.
def self.error_status
:ok
end
def self.redirect_status
:found
end
def self.error_status=(*)
warn "[DEVISE] Setting the error status on the Devise responder has no effect with this " \
"version of `responders`, please make sure you're using a newer version. Check the changelog for more info."
end
def self.redirect_status=(*)
warn "[DEVISE] Setting the redirect status on the Devise responder has no effect with this " \
"version of `responders`, please make sure you're using a newer version. Check the changelog for more info."
end
end
end
end
end
================================================
FILE: lib/devise/controllers/scoped_views.rb
================================================
# frozen_string_literal: true
module Devise
module Controllers
module ScopedViews
extend ActiveSupport::Concern
module ClassMethods
def scoped_views?
defined?(@scoped_views) ? @scoped_views : Devise.scoped_views
end
def scoped_views=(value)
@scoped_views = value
end
end
end
end
end
================================================
FILE: lib/devise/controllers/sign_in_out.rb
================================================
# frozen_string_literal: true
module Devise
module Controllers
# Provide sign in and sign out functionality.
# Included by default in all controllers.
module SignInOut
# Return true if the given scope is signed in session. If no scope given, return
# true if any scope is signed in. This will run authentication hooks, which may
# cause exceptions to be thrown from this method; if you simply want to check
# if a scope has already previously been authenticated without running
# authentication hooks, you can directly call `warden.authenticated?(scope: scope)`
def signed_in?(scope = nil)
[scope || Devise.mappings.keys].flatten.any? do |_scope|
warden.authenticate?(scope: _scope)
end
end
# Sign in a user that already was authenticated. This helper is useful for logging
# users in after sign up. All options given to sign_in is passed forward
# to the set_user method in warden.
# If you are using a custom warden strategy and the timeoutable module, you have to
# set `env["devise.skip_timeout"] = true` in the request to use this method, like we do
# in the sessions controller: https://github.com/heartcombo/devise/blob/main/app/controllers/devise/sessions_controller.rb#L7
#
# Examples:
#
# sign_in :user, @user # sign_in(scope, resource)
# sign_in @user # sign_in(resource)
# sign_in @user, event: :authentication # sign_in(resource, options)
# sign_in @user, store: false # sign_in(resource, options)
#
def sign_in(resource_or_scope, *args)
options = args.extract_options!
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource = args.last || resource_or_scope
expire_data_after_sign_in!
if warden.user(scope) == resource && !options.delete(:force)
# Do nothing. User already signed in and we are not forcing it.
true
else
warden.set_user(resource, options.merge!(scope: scope))
end
end
# Sign in a user bypassing the warden callbacks and stores the user
# straight in session. This option is useful in cases the user is already
# signed in, but we want to refresh the credentials in session.
#
# Examples:
#
# bypass_sign_in @user, scope: :user
# bypass_sign_in @user
def bypass_sign_in(resource, scope: nil)
scope ||= Devise::Mapping.find_scope!(resource)
expire_data_after_sign_in!
warden.session_serializer.store(resource, scope)
end
# Sign out a given user or scope. This helper is useful for signing out a user
# after deleting accounts. Returns true if there was a logout and false if there
# is no user logged in on the referred scope
#
# Examples:
#
# sign_out :user # sign_out(scope)
# sign_out @user # sign_out(resource)
#
def sign_out(resource_or_scope = nil)
return sign_out_all_scopes unless resource_or_scope
scope = Devise::Mapping.find_scope!(resource_or_scope)
user = warden.user(scope: scope, run_callbacks: false) # If there is no user
warden.logout(scope)
warden.clear_strategies_cache!(scope: scope)
instance_variable_set(:"@current_#{scope}", nil)
!!user
end
# Sign out all active users or scopes. This helper is useful for signing out all roles
# in one click. This signs out ALL scopes in warden. Returns true if there was at least one logout
# and false if there was no user logged in on all scopes.
def sign_out_all_scopes(lock = true)
users = Devise.mappings.keys.map { |s| warden.user(scope: s, run_callbacks: false) }
warden.logout
expire_data_after_sign_out!
warden.clear_strategies_cache!
warden.lock! if lock
users.any?
end
private
def expire_data_after_sign_in!
session.keys.grep(/^devise\./).each { |k| session.delete(k) }
end
alias :expire_data_after_sign_out! :expire_data_after_sign_in!
end
end
end
================================================
FILE: lib/devise/controllers/store_location.rb
================================================
# frozen_string_literal: true
require "uri"
module Devise
module Controllers
# Provide the ability to store a location.
# Used to redirect back to a desired path after sign in.
# Included by default in all controllers.
module StoreLocation
# Returns and delete (if it's navigational format) the url stored in the session for
# the given scope. Useful for giving redirect backs after sign up:
#
# Example:
#
# redirect_to stored_location_for(:user) || root_path
#
def stored_location_for(resource_or_scope)
session_key = stored_location_key_for(resource_or_scope)
if is_navigational_format?
session.delete(session_key)
else
session[session_key]
end
end
# Stores the provided location to redirect the user after signing in.
# Useful in combination with the `stored_location_for` helper.
#
# Example:
#
# store_location_for(:user, dashboard_path)
# redirect_to user_facebook_omniauth_authorize_path
#
def store_location_for(resource_or_scope, location)
session_key = stored_location_key_for(resource_or_scope)
path = extract_path_from_location(location)
session[session_key] = path if path
end
private
def parse_uri(location)
location && URI.parse(location)
rescue URI::InvalidURIError
nil
end
def stored_location_key_for(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
"#{scope}_return_to"
end
def extract_path_from_location(location)
uri = parse_uri(location)
if uri
path = remove_domain_from_uri(uri)
path = add_fragment_back_to_path(uri, path)
path
end
end
def remove_domain_from_uri(uri)
[uri.path.sub(/\A\/+/, '/'), uri.query].compact.join('?')
end
def add_fragment_back_to_path(uri, path)
[path, uri.fragment].compact.join('#')
end
end
end
end
================================================
FILE: lib/devise/controllers/url_helpers.rb
================================================
# frozen_string_literal: true
module Devise
module Controllers
# Create url helpers to be used with resource/scope configuration. Acts as
# proxies to the generated routes created by devise.
# Resource param can be a string or symbol, a class, or an instance object.
# Example using a :user resource:
#
# new_session_path(:user) => new_user_session_path
# session_path(:user) => user_session_path
# destroy_session_path(:user) => destroy_user_session_path
#
# new_password_path(:user) => new_user_password_path
# password_path(:user) => user_password_path
# edit_password_path(:user) => edit_user_password_path
#
# new_confirmation_path(:user) => new_user_confirmation_path
# confirmation_path(:user) => user_confirmation_path
#
# Those helpers are included by default to ActionController::Base.
#
# In case you want to add such helpers to another class, you can do
# that as long as this new class includes both url_helpers and
# mounted_helpers. Example:
#
# include Rails.application.routes.url_helpers
# include Rails.application.routes.mounted_helpers
#
module UrlHelpers
def self.remove_helpers!
self.instance_methods.map(&:to_s).grep(/_(url|path)$/).each do |method|
remove_method method
end
end
def self.generate_helpers!(routes = nil)
routes ||= begin
mappings = Devise.mappings.values.map(&:used_helpers).flatten.uniq
Devise::URL_HELPERS.slice(*mappings)
end
routes.each do |module_name, actions|
[:path, :url].each do |path_or_url|
actions.each do |action|
action = action ? "#{action}_" : ""
method = :"#{action}#{module_name}_#{path_or_url}"
define_method method do |resource_or_scope, *args|
scope = Devise::Mapping.find_scope!(resource_or_scope)
router_name = Devise.mappings[scope].router_name
context = router_name ? send(router_name) : _devise_route_context
context.send("#{action}#{scope}_#{module_name}_#{path_or_url}", *args)
end
end
end
end
end
generate_helpers!(Devise::URL_HELPERS)
private
def _devise_route_context
@_devise_route_context ||= send(Devise.available_router_name)
end
end
end
end
================================================
FILE: lib/devise/delegator.rb
================================================
# frozen_string_literal: true
module Devise
# Checks the scope in the given environment and returns the associated failure app.
class Delegator
def call(env)
failure_app(env).call(env)
end
def failure_app(env)
app = env["warden.options"] &&
(scope = env["warden.options"][:scope]) &&
Devise.mappings[scope.to_sym].failure_app
app || Devise::FailureApp
end
end
end
================================================
FILE: lib/devise/encryptor.rb
================================================
# frozen_string_literal: true
require 'bcrypt'
module Devise
module Encryptor
def self.digest(klass, password)
if klass.pepper.present?
password = "#{password}#{klass.pepper}"
end
::BCrypt::Password.create(password, cost: klass.stretches).to_s
end
def self.compare(klass, hashed_password, password)
return false if hashed_password.blank?
bcrypt = ::BCrypt::Password.new(hashed_password)
if klass.pepper.present?
password = "#{password}#{klass.pepper}"
end
password = ::BCrypt::Engine.hash_secret(password, bcrypt.salt)
Devise.secure_compare(password, hashed_password)
end
end
end
================================================
FILE: lib/devise/failure_app.rb
================================================
# frozen_string_literal: true
require "action_controller/metal"
module Devise
# Failure application that will be called every time :warden is thrown from
# any strategy or hook. It is responsible for redirecting the user to the sign
# in page based on current scope and mapping. If no scope is given, it
# redirects to the default_url.
class FailureApp < ActionController::Metal
include ActionController::UrlFor
include ActionController::Redirecting
include Rails.application.routes.url_helpers
include Rails.application.routes.mounted_helpers
include Devise::Controllers::StoreLocation
delegate :flash, to: :request
include AbstractController::Callbacks
around_action do |failure_app, action|
I18n.with_locale(failure_app.i18n_locale, &action)
end
def self.call(env)
@respond ||= action(:respond)
@respond.call(env)
end
# Try retrieving the URL options from the parent controller (usually
# ApplicationController). Instance methods are not supported at the moment,
# so only the class-level attribute is used.
def self.default_url_options(*args)
if defined?(Devise.parent_controller.constantize)
Devise.parent_controller.constantize.try(:default_url_options) || {}
else
{}
end
end
def respond
if http_auth?
http_auth
elsif warden_options[:recall]
recall
else
redirect
end
end
def http_auth
self.status = 401
self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect}) if http_auth_header?
self.content_type = request.format.to_s
self.response_body = http_auth_body
end
def recall
header_info = if relative_url_root?
base_path = Pathname.new(relative_url_root)
full_path = Pathname.new(attempted_path)
{ "SCRIPT_NAME" => relative_url_root,
"PATH_INFO" => '/' + full_path.relative_path_from(base_path).to_s }
else
{ "PATH_INFO" => attempted_path }
end
header_info.each do | var, value|
if request.respond_to?(:set_header)
request.set_header(var, value)
else
request.env[var] = value
end
end
flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
self.response = recall_app(warden_options[:recall]).call(request.env).tap { |response|
status = response[0].in?(300..399) ? Devise.responder.redirect_status : Devise.responder.error_status
# Avoid warnings translating status to code using Rails if available (e.g. `unprocessable_entity` => `unprocessable_content`)
response[0] = ActionDispatch::Response.try(:rack_status_code, status) || Rack::Utils.status_code(status)
}
end
def redirect
store_location!
if is_flashing_format?
if flash[:timedout] && flash[:alert]
flash.keep(:timedout)
flash.keep(:alert)
else
flash[:alert] = i18n_message
end
end
redirect_to redirect_url
end
protected
def i18n_options(options)
options
end
def i18n_message(default = nil)
message = warden_message || default || :unauthenticated
if message.is_a?(Symbol)
options = {}
options[:resource_name] = scope
options[:scope] = "devise.failure"
options[:default] = [message]
auth_keys = scope_class.authentication_keys
human_keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key|
# TODO: Remove the fallback and just use `downcase_first` once we drop support for Rails 7.0.
human_key = scope_class.human_attribute_name(key)
human_key.respond_to?(:downcase_first) ? human_key.downcase_first : human_key[0].downcase + human_key[1..]
}
options[:authentication_keys] = human_keys.join(I18n.t(:"support.array.words_connector"))
options = i18n_options(options)
I18n.t(:"#{scope}.#{message}", **options).then { |msg|
# Ensure that auth keys at the start of the translated string are properly cased.
msg.start_with?(human_keys.first) ? msg.upcase_first : msg
}
else
message.to_s
end
end
def i18n_locale
warden_options[:locale]
end
def redirect_url
if warden_message == :timeout
flash[:timedout] = true if is_flashing_format?
path = if request.get?
attempted_path
else
request.referrer
end
path || scope_url
else
scope_url
end
end
def route(scope)
:"new_#{scope}_session_url"
end
def scope_url
opts = {}
# Initialize script_name with nil to prevent infinite loops in
# authenticated mounted engines
opts[:script_name] = nil
route = route(scope)
opts[:format] = request_format unless skip_format?
router_name = Devise.mappings[scope].router_name || Devise.available_router_name
context = send(router_name)
if relative_url_root?
opts[:script_name] = relative_url_root
end
if context.respond_to?(route)
context.send(route, opts)
elsif respond_to?(:root_url)
root_url(opts)
else
"/"
end
end
def skip_format?
%w(html */* turbo_stream).include? request_format.to_s
end
# Choose whether we should respond in an HTTP authentication fashion,
# including 401 and optional headers.
#
# This method allows the user to explicitly disable HTTP authentication
# on AJAX requests in case they want to redirect on failures instead of
# handling the errors on their own. This is useful in case your AJAX API
# is the same as your public API and uses a format like JSON (so you
# cannot mark JSON as a navigational format).
def http_auth?
if request.xhr?
Devise.http_authenticatable_on_xhr
else
!(request_format && is_navigational_format?)
end
end
# It doesn't make sense to send authenticate headers in AJAX requests
# or if the user disabled them.
def http_auth_header?
scope_class.http_authenticatable && !request.xhr?
end
def http_auth_body
return i18n_message unless request_format
method = "to_#{request_format}"
if method == "to_xml"
{ error: i18n_message }.to_xml(root: "errors")
elsif {}.respond_to?(method)
{ error: i18n_message }.send(method)
else
i18n_message
end
end
def recall_app(app)
controller, action = app.split("#")
controller_name = ActiveSupport::Inflector.camelize(controller)
controller_klass = ActiveSupport::Inflector.constantize("#{controller_name}Controller")
controller_klass.action(action)
end
def warden
request.respond_to?(:get_header) ? request.get_header("warden") : request.env["warden"]
end
def warden_options
request.respond_to?(:get_header) ? request.get_header("warden.options") : request.env["warden.options"]
end
def warden_message
@message ||= warden.message || warden_options[:message]
end
def scope
@scope ||= warden_options[:scope] || Devise.default_scope
end
def scope_class
@scope_class ||= Devise.mappings[scope].to
end
def attempted_path
warden_options[:attempted_path]
end
# Stores requested URI to redirect the user after signing in. We can't use
# the scoped session provided by warden here, since the user is not
# authenticated yet, but we still need to store the URI based on scope, so
# different scopes would never use the same URI to redirect.
def store_location!
store_location_for(scope, attempted_path) if request.get? && !http_auth?
end
def is_navigational_format?
Devise.navigational_formats.include?(request_format)
end
# Check if flash messages should be emitted. Default is to do it on
# navigational formats
def is_flashing_format?
request.respond_to?(:flash) && is_navigational_format?
end
def request_format
@request_format ||= request.format.try(:ref)
end
def relative_url_root
@relative_url_root ||= begin
config = Rails.application.config
config.try(:relative_url_root) || config.action_controller.try(:relative_url_root)
end
end
def relative_url_root?
relative_url_root.present?
end
ActiveSupport.run_load_hooks(:devise_failure_app, self)
end
end
================================================
FILE: lib/devise/hooks/activatable.rb
================================================
# frozen_string_literal: true
# Deny user access whenever their account is not active yet.
# We need this as hook to validate the user activity on each request
# and in case the user is using other strategies beside Devise ones.
Warden::Manager.after_set_user do |record, warden, options|
if record && record.respond_to?(:active_for_authentication?) && !record.active_for_authentication?
scope = options[:scope]
warden.logout(scope)
throw :warden, scope: scope, message: record.inactive_message, locale: options.fetch(:locale, I18n.locale)
end
end
================================================
FILE: lib/devise/hooks/csrf_cleaner.rb
================================================
# frozen_string_literal: true
Warden::Manager.after_authentication do |record, warden, options|
clean_up_for_winning_strategy = !warden.winning_strategy.respond_to?(:clean_up_csrf?) ||
warden.winning_strategy.clean_up_csrf?
if Devise.clean_up_csrf_token_on_authentication && clean_up_for_winning_strategy
if warden.request.respond_to?(:reset_csrf_token)
# Rails 7.1+
warden.request.reset_csrf_token
else
warden.request.session.try(:delete, :_csrf_token)
end
end
end
================================================
FILE: lib/devise/hooks/forgetable.rb
================================================
# frozen_string_literal: true
# Before logout hook to forget the user in the given scope, if it responds
# to forget_me! Also clear remember token to ensure the user won't be
# remembered again. Notice that we forget the user unless the record is not persisted.
# This avoids forgetting deleted users.
Warden::Manager.before_logout do |record, warden, options|
if record.respond_to?(:forget_me!)
Devise::Hooks::Proxy.new(warden).forget_me(record)
end
end
================================================
FILE: lib/devise/hooks/lockable.rb
================================================
# frozen_string_literal: true
# After each sign in, if resource responds to failed_attempts, sets it to 0
# This is only triggered when the user is explicitly set (with set_user)
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
record.reset_failed_attempts!
end
end
================================================
FILE: lib/devise/hooks/proxy.rb
================================================
# frozen_string_literal: true
module Devise
module Hooks
# A small warden proxy so we can remember, forget and
# sign out users from hooks.
class Proxy #:nodoc:
include Devise::Controllers::Rememberable
include Devise::Controllers::SignInOut
attr_reader :warden
delegate :cookies, :request, to: :warden
def initialize(warden)
@warden = warden
end
def session
warden.request.session
end
end
end
end
================================================
FILE: lib/devise/hooks/rememberable.rb
================================================
# frozen_string_literal: true
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
scope = options[:scope]
if record.respond_to?(:remember_me) && options[:store] != false &&
record.remember_me && warden.authenticated?(scope)
Devise::Hooks::Proxy.new(warden).remember_me(record)
end
end
================================================
FILE: lib/devise/hooks/timeoutable.rb
================================================
# frozen_string_literal: true
# Each time a record is set we check whether its session has already timed out
# or not, based on last request time. If so, the record is logged out and
# redirected to the sign in page. Also, each time the request comes and the
# record is set, we set the last request time inside its scoped session to
# verify timeout in the following request.
Warden::Manager.after_set_user do |record, warden, options|
scope = options[:scope]
env = warden.request.env
if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) &&
options[:store] != false && !env['devise.skip_timeoutable']
last_request_at = warden.session(scope)['last_request_at']
if last_request_at.is_a? Integer
last_request_at = Time.at(last_request_at).utc
elsif last_request_at.is_a? String
last_request_at = Time.parse(last_request_at)
end
proxy = Devise::Hooks::Proxy.new(warden)
if !env['devise.skip_timeout'] &&
record.timedout?(last_request_at) &&
!proxy.remember_me_is_active?(record)
Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
throw :warden, scope: scope, message: :timeout, locale: options.fetch(:locale, I18n.locale)
end
unless env['devise.skip_trackable']
warden.session(scope)['last_request_at'] = Time.now.utc.to_i
end
end
end
================================================
FILE: lib/devise/hooks/trackable.rb
================================================
# frozen_string_literal: true
# After each sign in, update sign in time, sign in count and sign in IP.
# This is only triggered when the user is explicitly set (with set_user)
# and on authentication. Retrieving the user from session (:fetch) does
# not trigger it.
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && !warden.request.env['devise.skip_trackable']
record.update_tracked_fields!(warden.request)
end
end
================================================
FILE: lib/devise/mailers/helpers.rb
================================================
# frozen_string_literal: true
module Devise
module Mailers
module Helpers
extend ActiveSupport::Concern
included do
include Devise::Controllers::ScopedViews
end
protected
attr_reader :scope_name, :resource
# Configure default email options
def devise_mail(record, action, opts = {}, &block)
initialize_from_record(record)
mail headers_for(action, opts), &block
end
def initialize_from_record(record)
@scope_name = Devise::Mapping.find_scope!(record)
@resource = instance_variable_set("@#{devise_mapping.name}", record)
end
def devise_mapping
@devise_mapping ||= Devise.mappings[scope_name]
end
def headers_for(action, opts)
headers = {
subject: subject_for(action),
to: resource.email,
from: mailer_sender(devise_mapping),
reply_to: mailer_sender(devise_mapping),
template_path: template_paths,
template_name: action
}
# Give priority to the mailer's default if they exists.
headers.delete(:from) if default_params[:from]
headers.delete(:reply_to) if default_params[:reply_to]
headers.merge!(opts)
@email = headers[:to]
headers
end
def mailer_sender(mapping)
if Devise.mailer_sender.is_a?(Proc)
Devise.mailer_sender.call(mapping.name)
else
Devise.mailer_sender
end
end
def template_paths
template_path = _prefixes.dup
template_path.unshift "#{@devise_mapping.scoped_path}/mailer" if self.class.scoped_views?
template_path
end
# Set up a subject doing an I18n lookup. At first, it attempts to set a subject
# based on the current mapping:
#
# en:
# devise:
# mailer:
# confirmation_instructions:
# user_subject: '...'
#
# If one does not exist, it fallbacks to ActionMailer default:
#
# en:
# devise:
# mailer:
# confirmation_instructions:
# subject: '...'
#
def subject_for(key)
I18n.t(:"#{devise_mapping.name}_subject", scope: [:devise, :mailer, key],
default: [:subject, key.to_s.humanize])
end
end
end
end
================================================
FILE: lib/devise/mapping.rb
================================================
# frozen_string_literal: true
module Devise
# 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.
#
# The required value in devise_for is actually not used internally, but it's
# inflected to find all other values.
#
# map.devise_for :users
# mapping = Devise.mappings[:user]
#
# mapping.name #=> :user
# # is the scope used in controllers and warden, given in the route as :singular.
#
# mapping.as #=> "users"
# # how the mapping should be search in the path, given in the route as :as.
#
# mapping.to #=> User
# # is the class to be loaded from routes, given in the route as :class_name.
#
# mapping.modules #=> [:authenticatable]
# # is the modules included in the class
#
class Mapping #:nodoc:
attr_reader :singular, :scoped_path, :path, :controllers, :path_names,
:class_name, :sign_out_via, :format, :used_routes, :used_helpers,
:failure_app, :router_name
alias :name :singular
# Receives an object and finds a scope for it. If a scope cannot be found,
# raises an error. If a symbol is given, it's considered to be the scope.
def self.find_scope!(obj)
obj = obj.devise_scope if obj.respond_to?(:devise_scope)
case obj
when String, Symbol
return obj.to_sym
when Class
Devise.mappings.each_value { |m| return m.name if obj <= m.to }
else
Devise.mappings.each_value { |m| return m.name if obj.is_a?(m.to) }
end
raise "Could not find a valid mapping for #{obj.inspect}"
end
def self.find_by_path!(path, path_type = :fullpath)
Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
raise "Could not find a valid mapping for path #{path.inspect}"
end
def initialize(name, options) #:nodoc:
@scoped_path = options[:as] ? "#{options[:as]}/#{name}" : name.to_s
@singular = (options[:singular] || @scoped_path.tr('/', '_').singularize).to_sym
@class_name = (options[:class_name] || name.to_s.classify).to_s
@klass = Devise.ref(@class_name)
@path = (options[:path] || name).to_s
@path_prefix = options[:path_prefix]
@sign_out_via = options[:sign_out_via] || Devise.sign_out_via
@format = options[:format]
@router_name = options[:router_name]
default_failure_app(options)
default_controllers(options)
default_path_names(options)
default_used_route(options)
default_used_helpers(options)
end
# Return modules for the mapping.
def modules
@modules ||= to.respond_to?(:devise_modules) ? to.devise_modules : []
end
# Gives the class the mapping points to.
def to
@klass.get
end
def strategies
@strategies ||= STRATEGIES.values_at(*self.modules).compact.uniq.reverse
end
def no_input_strategies
self.strategies & Devise::NO_INPUT
end
def routes
@routes ||= ROUTES.values_at(*self.modules).compact.uniq
end
def authenticatable?
@authenticatable ||= self.modules.any? { |m| m.to_s =~ /authenticatable/ }
end
def fullpath
"/#{@path_prefix}/#{@path}".squeeze("/")
end
# Create magic predicates for verifying what module is activated by this map.
# Example:
#
# def confirmable?
# self.modules.include?(:confirmable)
# end
#
def self.add_module(m)
class_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{m}?
self.modules.include?(:#{m})
end
METHOD
end
private
def default_failure_app(options)
@failure_app = options[:failure_app] || Devise::FailureApp
if @failure_app.is_a?(String)
ref = Devise.ref(@failure_app)
@failure_app = lambda { |env| ref.get.call(env) }
end
end
def default_controllers(options)
mod = options[:module] || "devise"
@controllers = Hash.new { |h,k| h[k] = "#{mod}/#{k}" }
@controllers.merge!(options[:controllers]) if options[:controllers]
@controllers.each { |k,v| @controllers[k] = v.to_s }
end
def default_path_names(options)
@path_names = Hash.new { |h,k| h[k] = k.to_s }
@path_names[:registration] = ""
@path_names.merge!(options[:path_names]) if options[:path_names]
end
def default_constraints(options)
@constraints = Hash.new
@constraints.merge!(options[:constraints]) if options[:constraints]
end
def default_defaults(options)
@defaults = Hash.new
@defaults.merge!(options[:defaults]) if options[:defaults]
end
def default_used_route(options)
singularizer = lambda { |s| s.to_s.singularize.to_sym }
if options.has_key?(:only)
@used_routes = self.routes & Array(options[:only]).map(&singularizer)
elsif options[:skip] == :all
@used_routes = []
else
@used_routes = self.routes - Array(options[:skip]).map(&singularizer)
end
end
def default_used_helpers(options)
singularizer = lambda { |s| s.to_s.singularize.to_sym }
if options[:skip_helpers] == true
@used_helpers = @used_routes
elsif skip = options[:skip_helpers]
@used_helpers = self.routes - Array(skip).map(&singularizer)
else
@used_helpers = self.routes
end
end
end
end
================================================
FILE: lib/devise/models/authenticatable.rb
================================================
# frozen_string_literal: true
require 'devise/hooks/activatable'
require 'devise/hooks/csrf_cleaner'
module Devise
module Models
# Authenticatable module. Holds common settings for authentication.
#
# == Options
#
# Authenticatable adds the following options to +devise+:
#
# * +authentication_keys+: parameters used for authentication. By default [:email].
#
# * +http_authentication_key+: map the username passed via HTTP Auth to this parameter. Defaults to
# the first element in +authentication_keys+.
#
# * +request_keys+: parameters from the request object used for authentication.
# By specifying a symbol (which should be a request method), it will automatically be
# passed to find_for_authentication method and considered in your model lookup.
#
# For instance, if you set :request_keys to [:subdomain], :subdomain will be considered
# as key on authentication. This can also be a hash where the value is a boolean specifying
# if the value is required or not.
#
# * +http_authenticatable+: if this model allows http authentication. By default false.
# It also accepts an array specifying the strategies that should allow http.
#
# * +params_authenticatable+: if this model allows authentication through request params. By default true.
# It also accepts an array specifying the strategies that should allow params authentication.
#
# * +skip_session_storage+: By default Devise will store the user in session.
# By default is set to skip_session_storage: [:http_auth].
#
# == active_for_authentication?
#
# After authenticating a user and in each request, Devise checks if your model is active by
# calling model.active_for_authentication?. This method is overwritten by other devise modules. For instance,
# :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
#
# You can overwrite this method yourself, but if you do, don't forget to call super:
#
# def active_for_authentication?
# super && special_condition_is_valid?
# end
#
# Whenever active_for_authentication? returns false, Devise asks the reason why your model is inactive using
# the inactive_message method. You can overwrite it as well:
#
# def inactive_message
# special_condition_is_valid? ? super : :special_condition_is_not_valid
# end
#
module Authenticatable
extend ActiveSupport::Concern
UNSAFE_ATTRIBUTES_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
:remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
:last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
:remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
included do
class_attribute :devise_modules, instance_writer: false
self.devise_modules ||= []
before_validation :downcase_keys
before_validation :strip_whitespace
end
def self.required_fields(klass)
[]
end
# Check if the current object is valid for authentication. This method and
# find_for_authentication are the methods used in a Warden::Strategy to check
# if a model should be signed in or not.
#
# However, you should not overwrite this method, you should overwrite active_for_authentication?
# and inactive_message instead.
def valid_for_authentication?
block_given? ? yield : true
end
def unauthenticated_message
:invalid
end
def active_for_authentication?
true
end
def inactive_message
:inactive
end
def authenticatable_salt
end
# Redefine serializable_hash in models for more secure defaults.
# By default, it removes from the serializable model all attributes that
# are *not* accessible. You can remove this default by using :force_except
# and passing a new list of attributes you want to exempt. All attributes
# given to :except will simply add names to exempt to Devise internal list.
def serializable_hash(options = nil)
options = options.try(:dup) || {}
options[:except] = Array(options[:except]).dup
if options[:force_except]
options[:except].concat Array(options[:force_except])
else
options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
end
super(options)
end
# Redefine inspect using serializable_hash, to ensure we don't accidentally
# leak passwords into exceptions.
def inspect
inspection = serializable_hash.collect do |k,v|
"#{k}: #{respond_to?(:attribute_for_inspect) ? attribute_for_inspect(k) : v.inspect}"
end
"#<#{self.class} #{inspection.join(", ")}>"
end
protected
def devise_mailer
Devise.mailer
end
# This is an internal method called every time Devise needs
# to send a notification/mail. This can be overridden if you
# need to customize the e-mail delivery logic. For instance,
# if you are using a queue to deliver e-mails (active job, delayed
# job, sidekiq, resque, etc), you must add the delivery to the queue
# just after the transaction was committed. To achieve this,
# you can override send_devise_notification to store the
# deliveries until the after_commit callback is triggered.
#
# The following example uses Active Job's `deliver_later` :
#
# class User
# devise :database_authenticatable, :confirmable
#
# after_commit :send_pending_devise_notifications
#
# protected
#
# def send_devise_notification(notification, *args)
# # If the record is new or changed then delay the
# # delivery until the after_commit callback otherwise
# # send now because after_commit will not be called.
# # For Rails < 6 use `changed?` instead of `saved_changes?`.
# if new_record? || saved_changes?
# pending_devise_notifications << [notification, args]
# else
# render_and_send_devise_message(notification, *args)
# end
# end
#
# private
#
# def send_pending_devise_notifications
# pending_devise_notifications.each do |notification, args|
# render_and_send_devise_message(notification, *args)
# end
#
# # Empty the pending notifications array because the
# # after_commit hook can be called multiple times which
# # could cause multiple emails to be sent.
# pending_devise_notifications.clear
# end
#
# def pending_devise_notifications
# @pending_devise_notifications ||= []
# end
#
# def render_and_send_devise_message(notification, *args)
# message = devise_mailer.send(notification, self, *args)
#
# # Deliver later with Active Job's `deliver_later`
# if message.respond_to?(:deliver_later)
# message.deliver_later
# else
# message.deliver_now
# end
# end
#
# end
#
def send_devise_notification(notification, *args)
message = devise_mailer.send(notification, self, *args)
message.deliver_now
end
def downcase_keys
self.class.case_insensitive_keys.each { |k| apply_to_attribute_or_variable(k, :downcase) }
end
def strip_whitespace
self.class.strip_whitespace_keys.each { |k| apply_to_attribute_or_variable(k, :strip) }
end
def apply_to_attribute_or_variable(attr, method)
if self[attr]
self[attr] = self[attr].try(method)
# Use respond_to? here to avoid a regression where globally
# configured strip_whitespace_keys or case_insensitive_keys were
# attempting to strip or downcase when a model didn't have the
# globally configured key.
elsif respond_to?(attr) && respond_to?("#{attr}=")
new_value = send(attr).try(method)
send("#{attr}=", new_value)
end
end
module ClassMethods
Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys,
:case_insensitive_keys, :http_authenticatable, :params_authenticatable, :skip_session_storage,
:http_authentication_key)
def serialize_into_session(record)
[record.to_key, record.authenticatable_salt]
end
def serialize_from_session(key, salt)
record = to_adapter.get(key)
record if record && record.authenticatable_salt == salt
end
def params_authenticatable?(strategy)
params_authenticatable.is_a?(Array) ?
params_authenticatable.include?(strategy) : params_authenticatable
end
def http_authenticatable?(strategy)
http_authenticatable.is_a?(Array) ?
http_authenticatable.include?(strategy) : http_authenticatable
end
# Find first record based on conditions given (ie by the sign in form).
# This method is always called during an authentication process but
# it may be wrapped as well. For instance, database authenticatable
# provides a `find_for_database_authentication` that wraps a call to
# this method. This allows you to customize both database authenticatable
# or the whole authenticate stack by customize `find_for_authentication.`
#
# Overwrite to add customized conditions, create a join, or maybe use a
# namedscope to filter records while authenticating.
# Example:
#
# def self.find_for_authentication(tainted_conditions)
# find_first_by_auth_conditions(tainted_conditions, active: true)
# end
#
# Finally, notice that Devise also queries for users in other scenarios
# besides authentication, for example when retrieving a user to send
# an e-mail for password reset. In such cases, find_for_authentication
# is not called.
def find_for_authentication(tainted_conditions)
find_first_by_auth_conditions(tainted_conditions)
end
def find_first_by_auth_conditions(tainted_conditions, opts = {})
to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
end
# Find or initialize a record setting an error if it can't be found.
def find_or_initialize_with_error_by(attribute, value, error = :invalid) #:nodoc:
find_or_initialize_with_errors([attribute], { attribute => value }, error)
end
# Find or initialize a record with group of attributes based on a list of required attributes.
def find_or_initialize_with_errors(required_attributes, attributes, error = :invalid) #:nodoc:
attributes.try(:permit!)
attributes = attributes.to_h.with_indifferent_access
.slice(*required_attributes)
.delete_if { |key, value| value.blank? }
if attributes.size == required_attributes.size
record = find_first_by_auth_conditions(attributes) and return record
end
new(devise_parameter_filter.filter(attributes)).tap do |record|
required_attributes.each do |key|
record.errors.add(key, attributes[key].blank? ? :blank : error)
end
end
end
protected
def devise_parameter_filter
@devise_parameter_filter ||= Devise::ParameterFilter.new(case_insensitive_keys, strip_whitespace_keys)
end
end
end
end
end
================================================
FILE: lib/devise/models/confirmable.rb
================================================
# frozen_string_literal: true
module Devise
module Models
# Confirmable is responsible to verify if an account is already confirmed to
# sign in, and to send emails with confirmation instructions.
# Confirmation instructions are sent to the user email after creating a
# record and when manually requested by a new confirmation instruction request.
#
# Confirmable tracks the following columns:
#
# * confirmation_token - A unique random token
# * confirmed_at - A timestamp when the user clicked the confirmation link
# * confirmation_sent_at - A timestamp when the confirmation_token was generated (not sent)
# * unconfirmed_email - An email address copied from the email attr. After confirmation
# this value is copied to the email attr then cleared
#
# == Options
#
# Confirmable adds the following options to +devise+:
#
# * +allow_unconfirmed_access_for+: the time you want to allow the user to access their account
# before confirming it. After this period, the user access is denied. You can
# use this to let your user access some features of your application without
# confirming the account, but blocking it after a certain period (ie 7 days).
# By default allow_unconfirmed_access_for is zero, it means users always have to confirm to sign in.
# * +reconfirmable+: requires any email changes to be confirmed (exactly the same way as
# initial account confirmation) to be applied. Requires additional unconfirmed_email
# db field to be set up (t.reconfirmable in migrations). Until confirmed, new email is
# stored in unconfirmed email column, and copied to email column on successful
# confirmation. Also, when used in conjunction with `send_email_changed_notification`,
# the notification is sent to the original email when the change is requested,
# not when the unconfirmed email is confirmed.
# * +confirm_within+: the time before a sent confirmation token becomes invalid.
# You can use this to force the user to confirm within a set period of time.
# Confirmable will not generate a new token if a repeat confirmation is requested
# during this time frame, unless the user's email changed too.
#
# == Examples
#
# User.find(1).confirm # returns true unless it's already confirmed
# User.find(1).confirmed? # true/false
# User.find(1).send_confirmation_instructions # manually send instructions
#
module Confirmable
extend ActiveSupport::Concern
included do
before_create :generate_confirmation_token, if: :confirmation_required?
after_create :skip_reconfirmation_in_callback!, if: :send_confirmation_notification?
if Devise::Orm.active_record?(self) # ActiveRecord
after_commit :send_on_create_confirmation_instructions, on: :create, if: :send_confirmation_notification?
after_commit :send_reconfirmation_instructions, on: :update, if: :reconfirmation_required?
else # Mongoid
after_create :send_on_create_confirmation_instructions, if: :send_confirmation_notification?
after_update :send_reconfirmation_instructions, if: :reconfirmation_required?
end
before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, if: :postpone_email_change?
end
def initialize(*args, &block)
@bypass_confirmation_postpone = false
@skip_reconfirmation_in_callback = false
@reconfirmation_required = false
@skip_confirmation_notification = false
@raw_confirmation_token = nil
super
end
def self.required_fields(klass)
required_methods = [:confirmation_token, :confirmed_at, :confirmation_sent_at]
required_methods << :unconfirmed_email if klass.reconfirmable
required_methods
end
# Confirm a user by setting it's confirmed_at to actual time. If the user
# is already confirmed, add an error to email field. If the user is invalid
# add errors
def confirm(args = {})
pending_any_confirmation do
if confirmation_period_expired?
self.errors.add(:email, :confirmation_period_expired,
period: Devise::TimeInflector.time_ago_in_words(self.class.confirm_within.ago))
return false
end
self.confirmed_at = Time.now.utc
saved = if pending_reconfirmation?
skip_reconfirmation!
self.email = unconfirmed_email
self.unconfirmed_email = nil
# We need to validate in such cases to enforce e-mail uniqueness
save(validate: true)
else
save(validate: args[:ensure_valid] == true)
end
after_confirmation if saved
saved
end
end
# Verifies whether a user is confirmed or not
def confirmed?
!!confirmed_at
end
def pending_reconfirmation?
self.class.reconfirmable && unconfirmed_email.present?
end
# Send confirmation instructions by email
def send_confirmation_instructions
unless @raw_confirmation_token
generate_confirmation_token!
end
opts = pending_reconfirmation? ? { to: unconfirmed_email } : { }
send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
end
def send_reconfirmation_instructions
@reconfirmation_required = false
unless @skip_confirmation_notification
send_confirmation_instructions
end
end
# Resend confirmation token.
# Regenerates the token if the period is expired.
def resend_confirmation_instructions
pending_any_confirmation do
send_confirmation_instructions
end
end
# Overwrites active_for_authentication? for confirmation
# by verifying whether a user is active to sign in or not. If the user
# is already confirmed, it should never be blocked. Otherwise we need to
# calculate if the confirm time has not expired for this user.
def active_for_authentication?
super && (!confirmation_required? || confirmed? || confirmation_period_valid?)
end
# The message to be shown if the account is inactive.
def inactive_message
!confirmed? ? :unconfirmed : super
end
# If you don't want confirmation to be sent on create, neither a code
# to be generated, call skip_confirmation!
def skip_confirmation!
self.confirmed_at = Time.now.utc
end
# Skips sending the confirmation/reconfirmation notification email after_create/after_update. Unlike
# #skip_confirmation!, record still requires confirmation.
def skip_confirmation_notification!
@skip_confirmation_notification = true
end
# If you don't want reconfirmation to be sent, neither a code
# to be generated, call skip_reconfirmation!
def skip_reconfirmation!
@bypass_confirmation_postpone = true
end
protected
# To not require reconfirmation after creating with #save called in a
# callback call skip_create_confirmation!
def skip_reconfirmation_in_callback!
@skip_reconfirmation_in_callback = true
end
# A callback method used to deliver confirmation
# instructions on creation. This can be overridden
# in models to map to a nice sign up e-mail.
def send_on_create_confirmation_instructions
send_confirmation_instructions
end
# Callback to overwrite if confirmation is required or not.
def confirmation_required?
!confirmed?
end
# Checks if the confirmation for the user is within the limit time.
# We do this by calculating if the difference between today and the
# confirmation sent date does not exceed the confirm in time configured.
# allow_unconfirmed_access_for is a model configuration, must always be an integer value.
#
# Example:
#
# # allow_unconfirmed_access_for = 1.day and confirmation_sent_at = today
# confirmation_period_valid? # returns true
#
# # allow_unconfirmed_access_for = 5.days and confirmation_sent_at = 4.days.ago
# confirmation_period_valid? # returns true
#
# # allow_unconfirmed_access_for = 5.days and confirmation_sent_at = 5.days.ago
# confirmation_period_valid? # returns false
#
# # allow_unconfirmed_access_for = 0.days
# confirmation_period_valid? # will always return false
#
# # allow_unconfirmed_access_for = nil
# confirmation_period_valid? # will always return true
#
def confirmation_period_valid?
return true if self.class.allow_unconfirmed_access_for.nil?
return false if self.class.allow_unconfirmed_access_for == 0.days
confirmation_sent_at && confirmation_sent_at.utc >= self.class.allow_unconfirmed_access_for.ago
end
# Checks if the user confirmation happens before the token becomes invalid
# Examples:
#
# # confirm_within = 3.days and confirmation_sent_at = 2.days.ago
# confirmation_period_expired? # returns false
#
# # confirm_within = 3.days and confirmation_sent_at = 4.days.ago
# confirmation_period_expired? # returns true
#
# # confirm_within = nil
# confirmation_period_expired? # will always return false
#
def confirmation_period_expired?
self.class.confirm_within && self.confirmation_sent_at && (Time.now.utc > self.confirmation_sent_at.utc + self.class.confirm_within)
end
# Checks whether the record requires any confirmation.
def pending_any_confirmation
if (!confirmed? || pending_reconfirmation?)
yield
else
self.errors.add(:email, :already_confirmed)
false
end
end
# Generates a new random token for confirmation, and stores
# the time this token is being generated in confirmation_sent_at
def generate_confirmation_token
if self.confirmation_token && !confirmation_period_expired?
@raw_confirmation_token = self.confirmation_token
else
self.confirmation_token = @raw_confirmation_token = Devise.friendly_token
self.confirmation_sent_at = Time.now.utc
end
end
def generate_confirmation_token!
generate_confirmation_token && save(validate: false)
end
def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
@reconfirmation_required = true
# Force unconfirmed_email to be updated, even if the value hasn't changed, to prevent a
# race condition which could allow an attacker to confirm an email they don't own. See #5783.
devise_unconfirmed_email_will_change!
self.unconfirmed_email = self.email
self.email = self.devise_email_in_database
self.confirmation_token = nil
generate_confirmation_token
end
def postpone_email_change?
postpone = self.class.reconfirmable &&
devise_will_save_change_to_email? &&
!@bypass_confirmation_postpone &&
self.email.present? &&
(!@skip_reconfirmation_in_callback || !self.devise_email_in_database.nil?)
@bypass_confirmation_postpone = false
postpone
end
def reconfirmation_required?
self.class.reconfirmable && @reconfirmation_required && (self.email.present? || self.unconfirmed_email.present?)
end
def send_confirmation_notification?
confirmation_required? && !@skip_confirmation_notification && self.email.present?
end
# With reconfirmable, notify the original email when the user first
# requests the email change, instead of when the change is confirmed.
def send_email_changed_notification?
if self.class.reconfirmable
self.class.send_email_changed_notification && reconfirmation_required?
else
super
end
end
# A callback initiated after successfully confirming. This can be
# used to insert your own logic that is only run after the user successfully
# confirms.
#
# Example:
#
# def after_confirmation
# self.update_attribute(:invite_code, nil)
# end
#
def after_confirmation
end
module ClassMethods
# Attempt to find a user by its email. If a record is found, send new
# confirmation instructions to it. If not, try searching for a user by unconfirmed_email
# field. If no user is found, returns a new user with an email not found error.
# Options must contain the user email
def send_confirmation_instructions(attributes = {})
confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable
unless confirmable.try(:persisted?)
confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
end
confirmable.resend_confirmation_instructions if confirmable.persisted?
confirmable
end
# Find a user by its confirmation token and try to confirm it.
# If no user is found, returns a new user with an error.
# If the user is already confirmed, create an error for the user
# Options must have the confirmation_token
def confirm_by_token(confirmation_token)
# When the `confirmation_token` parameter is blank, if there are any users with a blank
# `confirmation_token` in the database, the first one would be confirmed here.
# The error is being manually added here to ensure no users are confirmed by mistake.
# This was done in the model for convenience, since validation errors are automatically
# displayed in the view.
if confirmation_token.blank?
confirmable = new
confirmable.errors.add(:confirmation_token, :blank)
return confirmable
end
confirmable = find_first_by_auth_conditions(confirmation_token: confirmation_token)
unless confirmable
confirmation_digest = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_digest)
end
# TODO: replace above lines with
# confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
# after enough time has passed that Devise clients do not use digested tokens
confirmable.confirm if confirmable.persisted?
confirmable
end
# Find a record for confirmation by unconfirmed email field
def find_by_unconfirmed_email_with_errors(attributes = {})
attributes = attributes.slice(*confirmation_keys).permit!.to_h if attributes.respond_to? :permit
unconfirmed_required_attributes = confirmation_keys.map { |k| k == :email ? :unconfirmed_email : k }
unconfirmed_attributes = attributes.symbolize_keys
unconfirmed_attributes[:unconfirmed_email] = unconfirmed_attributes.delete(:email)
find_or_initialize_with_errors(unconfirmed_required_attributes, unconfirmed_attributes, :not_found)
end
Devise::Models.config(self, :allow_unconfirmed_access_for, :confirmation_keys, :reconfirmable, :confirm_within)
end
end
end
end
================================================
FILE: lib/devise/models/database_authenticatable.rb
================================================
# frozen_string_literal: true
require 'devise/strategies/database_authenticatable'
module Devise
module Models
# Authenticatable Module, responsible for hashing the password and
# validating the authenticity of a user while signing in.
#
# This module defines a `password=` method. This method will hash the argument
# and store it in the `encrypted_password` column, bypassing any pre-existing
# `password` column if it exists.
#
# == Options
#
# DatabaseAuthenticatable adds the following options to +devise+:
#
# * +pepper+: a random string used to provide a more secure hash. Use
# `rails secret` to generate new keys.
#
# * +stretches+: the cost given to bcrypt.
#
# * +send_email_changed_notification+: notify original email when it changes.
#
# * +send_password_change_notification+: notify email when password changes.
#
# == Examples
#
# User.find(1).valid_password?('password123') # returns true/false
#
module DatabaseAuthenticatable
extend ActiveSupport::Concern
included do
after_update :send_email_changed_notification, if: :send_email_changed_notification?
after_update :send_password_change_notification, if: :send_password_change_notification?
attr_reader :password, :current_password
attr_accessor :password_confirmation
end
def initialize(*args, &block)
@skip_email_changed_notification = false
@skip_password_change_notification = false
super
end
# Skips sending the email changed notification after_update
def skip_email_changed_notification!
@skip_email_changed_notification = true
end
# Skips sending the password change notification after_update
def skip_password_change_notification!
@skip_password_change_notification = true
end
def self.required_fields(klass)
[:encrypted_password] + klass.authentication_keys
end
# Generates a hashed password based on the given value.
# For legacy reasons, we use `encrypted_password` to store
# the hashed password.
def password=(new_password)
@password = new_password
self.encrypted_password = password_digest(@password) if @password.present?
end
# Verifies whether a password (ie from sign in) is the user password.
def valid_password?(password)
Devise::Encryptor.compare(self.class, encrypted_password, password)
end
# Set password and password confirmation to nil
def clean_up_passwords
self.password = self.password_confirmation = nil
end
# Update record attributes when :current_password matches, otherwise
# returns error on :current_password.
#
# This method also rejects the password field if it is blank (allowing
# users to change relevant information like the e-mail without changing
# their password). In case the password field is rejected, the confirmation
# is also rejected as long as it is also blank.
def update_with_password(params)
current_password = params.delete(:current_password)
if params[:password].blank?
params.delete(:password)
params.delete(:password_confirmation) if params[:password_confirmation].blank?
end
result = if valid_password?(current_password)
update(params)
else
assign_attributes(params)
valid?
errors.add(:current_password, current_password.blank? ? :blank : :invalid)
false
end
clean_up_passwords
result
end
# Updates record attributes without asking for the current password.
# Never allows a change to the current password. If you are using this
# method, you should probably override this method to protect other
# attributes you would not like to be updated without a password.
#
# Example:
#
# def update_without_password(params)
# params.delete(:email)
# super(params)
# end
#
def update_without_password(params)
params.delete(:password)
params.delete(:password_confirmation)
result = update(params)
clean_up_passwords
result
end
# Destroy record when :current_password matches, otherwise returns
# error on :current_password. It also automatically rejects
# :current_password if it is blank.
def destroy_with_password(current_password)
result = if valid_password?(current_password)
destroy
else
valid?
errors.add(:current_password, current_password.blank? ? :blank : :invalid)
false
end
result
end
# A callback initiated after successfully authenticating. This can be
# used to insert your own logic that is only run after the user successfully
# authenticates.
#
# Example:
#
# def after_database_authentication
# self.update_attribute(:invite_code, nil)
# end
#
def after_database_authentication
end
# A reliable way to expose the salt regardless of the implementation.
def authenticatable_salt
encrypted_password[0,29] if encrypted_password
end
# Send notification to user when email changes.
def send_email_changed_notification
send_devise_notification(:email_changed, to: devise_email_before_last_save)
end
# Send notification to user when password changes.
def send_password_change_notification
send_devise_notification(:password_change)
end
protected
# Hashes the password using bcrypt. Custom hash functions should override
# this method to apply their own algorithm.
#
# See https://github.com/heartcombo/devise-encryptable for examples
# of other hashing engines.
def password_digest(password)
Devise::Encryptor.digest(self.class, password)
end
def send_email_changed_notification?
self.class.send_email_changed_notification && devise_saved_change_to_email? && !@skip_email_changed_notification
end
def send_password_change_notification?
self.class.send_password_change_notification && devise_saved_change_to_encrypted_password? && !@skip_password_change_notification
end
module ClassMethods
Devise::Models.config(self, :pepper, :stretches, :send_email_changed_notification, :send_password_change_notification)
# We assume this method already gets the sanitized values from the
# DatabaseAuthenticatable strategy. If you are using this method on
# your own, be sure to sanitize the conditions hash to only include
# the proper fields.
def find_for_database_authentication(conditions)
find_for_authentication(conditions)
end
end
end
end
end
================================================
FILE: lib/devise/models/lockable.rb
================================================
# frozen_string_literal: true
require "devise/hooks/lockable"
module Devise
module Models
# Handles blocking a user access after a certain number of attempts.
# Lockable accepts two different strategies to unlock a user after it's
# blocked: email and time. The former will send an email to the user when
# the lock happens, containing a link to unlock its account. The second
# will unlock the user automatically after some configured time (ie 2.hours).
# It's also possible to set up lockable to use both email and time strategies.
#
# == Options
#
# Lockable adds the following options to +devise+:
#
# * +maximum_attempts+: how many attempts should be accepted before blocking the user.
# * +lock_strategy+: lock the user account by :failed_attempts or :none.
# * +unlock_strategy+: unlock the user account by :time, :email, :both or :none.
# * +unlock_in+: the time you want to unlock the user after lock happens. Only available when unlock_strategy is :time or :both.
# * +unlock_keys+: the keys you want to use when locking and unlocking an account
#
module Lockable
extend ActiveSupport::Concern
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, to: "self.class"
def self.required_fields(klass)
attributes = []
attributes << :failed_attempts if klass.lock_strategy_enabled?(:failed_attempts)
attributes << :locked_at if klass.unlock_strategy_enabled?(:time)
attributes << :unlock_token if klass.unlock_strategy_enabled?(:email)
attributes
end
# Lock a user setting its locked_at to actual time.
# * +opts+: Hash options if you don't want to send email
# when you lock access, you could pass the next hash
# `{ send_instructions: false } as option`.
def lock_access!(opts = { })
self.locked_at = Time.now.utc
if unlock_strategy_enabled?(:email) && opts.fetch(:send_instructions, true)
send_unlock_instructions
else
save(validate: false)
end
end
# Unlock a user by cleaning locked_at and failed_attempts.
def unlock_access!
self.locked_at = nil
self.failed_attempts = 0 if respond_to?(:failed_attempts=)
self.unlock_token = nil if respond_to?(:unlock_token=)
save(validate: false)
end
# Resets failed attempts counter to 0.
def reset_failed_attempts!
if respond_to?(:failed_attempts) && !failed_attempts.to_i.zero?
self.failed_attempts = 0
save(validate: false)
end
end
# Verifies whether a user is locked or not.
def access_locked?
!!locked_at && !lock_expired?
end
# Send unlock instructions by email
def send_unlock_instructions
raw, enc = Devise.token_generator.generate(self.class, :unlock_token)
self.unlock_token = enc
save(validate: false)
send_devise_notification(:unlock_instructions, raw, {})
raw
end
# Resend the unlock instructions if the user is locked.
def resend_unlock_instructions
if_access_locked { send_unlock_instructions }
end
# Overwrites active_for_authentication? from Devise::Models::Authenticatable for locking purposes
# by verifying whether a user is active to sign in or not based on locked?
def active_for_authentication?
super && !access_locked?
end
# Overwrites invalid_message from Devise::Models::Authenticatable to define
# the correct reason for blocking the sign in.
def inactive_message
access_locked? ? :locked : super
end
# Overwrites valid_for_authentication? from Devise::Models::Authenticatable
# for verifying whether a user is allowed to sign in or not. If the user
# is locked, it should never be allowed.
def valid_for_authentication?
return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
# Unlock the user if the lock is expired, no matter
# if the user can login or not (wrong password, etc)
unlock_access! if lock_expired?
if super && !access_locked?
true
else
increment_failed_attempts
if attempts_exceeded?
lock_access! unless access_locked?
else
save(validate: false)
end
false
end
end
def increment_failed_attempts
self.class.increment_counter(:failed_attempts, id)
reload
end
def unauthenticated_message
# If set to paranoid mode, do not show the locked message because it
# leaks the existence of an account.
if Devise.paranoid
super
elsif access_locked? || (lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?)
:locked
elsif lock_strategy_enabled?(:failed_attempts) && last_attempt? && self.class.last_attempt_warning
:last_attempt
else
super
end
end
protected
def attempts_exceeded?
self.failed_attempts >= self.class.maximum_attempts
end
def last_attempt?
self.failed_attempts == self.class.maximum_attempts - 1
end
# Tells if the lock is expired if :time unlock strategy is active
def lock_expired?
if unlock_strategy_enabled?(:time)
locked_at && locked_at < self.class.unlock_in.ago
else
false
end
end
# Checks whether the record is locked or not, yielding to the block
# if it's locked, otherwise adds an error to email.
def if_access_locked
if access_locked?
yield
else
self.errors.add(Devise.unlock_keys.first, :not_locked)
false
end
end
module ClassMethods
# List of strategies that are enabled/supported if :both is used.
BOTH_STRATEGIES = [:time, :email]
# Attempt to find a user by its unlock keys. If a record is found, send new
# unlock instructions to it. If not user is found, returns a new user
# with an email not found error.
# Options must contain the user's unlock keys
def send_unlock_instructions(attributes = {})
lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
lockable.resend_unlock_instructions if lockable.persisted?
lockable
end
# Find a user by its unlock token and try to unlock it.
# If no user is found, returns a new user with an error.
# If the user is not locked, creates an error for the user
# Options must have the unlock_token
def unlock_access_by_token(unlock_token)
original_token = unlock_token
unlock_token = Devise.token_generator.digest(self, :unlock_token, unlock_token)
lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
lockable.unlock_access! if lockable.persisted?
lockable.unlock_token = original_token
lockable
end
# Is the unlock enabled for the given unlock strategy?
def unlock_strategy_enabled?(strategy)
self.unlock_strategy == strategy ||
(self.unlock_strategy == :both && BOTH_STRATEGIES.include?(strategy))
end
# Is the lock enabled for the given lock strategy?
def lock_strategy_enabled?(strategy)
self.lock_strategy == strategy
end
Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in, :unlock_keys, :last_attempt_warning)
end
end
end
end
================================================
FILE: lib/devise/models/omniauthable.rb
================================================
# frozen_string_literal: true
require 'devise/omniauth'
module Devise
module Models
# Adds OmniAuth support to your model.
#
# == Options
#
# Oauthable adds the following options to +devise+:
#
# * +omniauth_providers+: Which providers are available to this model. It expects an array:
#
# devise :database_authenticatable, :omniauthable, omniauth_providers: [:twitter]
#
module Omniauthable
extend ActiveSupport::Concern
def self.required_fields(klass)
[]
end
module ClassMethods
Devise::Models.config(self, :omniauth_providers)
end
end
end
end
================================================
FILE: lib/devise/models/recoverable.rb
================================================
# frozen_string_literal: true
module Devise
module Models
# Recoverable takes care of resetting the user password and send reset instructions.
#
# ==Options
#
# Recoverable adds the following options to +devise+:
#
# * +reset_password_keys+: the keys you want to use when recovering the password for an account
# * +reset_password_within+: the time period within which the password must be reset or the token expires.
# * +sign_in_after_reset_password+: whether or not to sign in the user automatically after a password reset.
#
# == Examples
#
# # resets the user password and save the record, true if valid passwords are given, otherwise false
# User.find(1).reset_password('password123', 'password123')
#
# # creates a new token and send it with instructions about how to reset the password
# User.find(1).send_reset_password_instructions
#
module Recoverable
extend ActiveSupport::Concern
def self.required_fields(klass)
[:reset_password_sent_at, :reset_password_token]
end
included do
before_update :clear_reset_password_token, if: :clear_reset_password_token?
end
# Update password saving the record and clearing token. Returns true if
# the passwords are valid and the record was saved, false otherwise.
def reset_password(new_password, new_password_confirmation)
if new_password.present?
self.password = new_password
self.password_confirmation = new_password_confirmation
save
else
errors.add(:password, :blank)
false
end
end
# Resets reset password token and send reset password instructions by email.
# Returns the token sent in the e-mail.
def send_reset_password_instructions
token = set_reset_password_token
send_reset_password_instructions_notification(token)
token
end
# Checks if the reset password token sent is within the limit time.
# We do this by calculating if the difference between today and the
# sending date does not exceed the conf
gitextract_4bqfrk55/
├── .devcontainer/
│ └── devcontainer.json
├── .github/
│ ├── code-scanning.yml
│ ├── dependabot.yml
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .yardopts
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Gemfile
├── ISSUE_TEMPLATE.md
├── MIT-LICENSE
├── README.md
├── Rakefile
├── app/
│ ├── controllers/
│ │ ├── devise/
│ │ │ ├── confirmations_controller.rb
│ │ │ ├── omniauth_callbacks_controller.rb
│ │ │ ├── passwords_controller.rb
│ │ │ ├── registrations_controller.rb
│ │ │ ├── sessions_controller.rb
│ │ │ └── unlocks_controller.rb
│ │ └── devise_controller.rb
│ ├── helpers/
│ │ └── devise_helper.rb
│ ├── mailers/
│ │ └── devise/
│ │ └── mailer.rb
│ └── views/
│ └── devise/
│ ├── confirmations/
│ │ └── new.html.erb
│ ├── mailer/
│ │ ├── confirmation_instructions.html.erb
│ │ ├── email_changed.html.erb
│ │ ├── password_change.html.erb
│ │ ├── reset_password_instructions.html.erb
│ │ └── unlock_instructions.html.erb
│ ├── passwords/
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ ├── registrations/
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ ├── sessions/
│ │ └── new.html.erb
│ ├── shared/
│ │ ├── _error_messages.html.erb
│ │ └── _links.html.erb
│ └── unlocks/
│ └── new.html.erb
├── bin/
│ └── test
├── config/
│ └── locales/
│ └── en.yml
├── devise.gemspec
├── gemfiles/
│ ├── Gemfile-rails-7-0
│ ├── Gemfile-rails-7-1
│ ├── Gemfile-rails-7-2
│ ├── Gemfile-rails-8-0
│ └── Gemfile-rails-main
├── guides/
│ └── bug_report_templates/
│ └── integration_test.rb
├── lib/
│ ├── devise/
│ │ ├── controllers/
│ │ │ ├── helpers.rb
│ │ │ ├── rememberable.rb
│ │ │ ├── responder.rb
│ │ │ ├── scoped_views.rb
│ │ │ ├── sign_in_out.rb
│ │ │ ├── store_location.rb
│ │ │ └── url_helpers.rb
│ │ ├── delegator.rb
│ │ ├── encryptor.rb
│ │ ├── failure_app.rb
│ │ ├── hooks/
│ │ │ ├── activatable.rb
│ │ │ ├── csrf_cleaner.rb
│ │ │ ├── forgetable.rb
│ │ │ ├── lockable.rb
│ │ │ ├── proxy.rb
│ │ │ ├── rememberable.rb
│ │ │ ├── timeoutable.rb
│ │ │ └── trackable.rb
│ │ ├── mailers/
│ │ │ └── helpers.rb
│ │ ├── mapping.rb
│ │ ├── models/
│ │ │ ├── authenticatable.rb
│ │ │ ├── confirmable.rb
│ │ │ ├── database_authenticatable.rb
│ │ │ ├── lockable.rb
│ │ │ ├── omniauthable.rb
│ │ │ ├── recoverable.rb
│ │ │ ├── registerable.rb
│ │ │ ├── rememberable.rb
│ │ │ ├── timeoutable.rb
│ │ │ ├── trackable.rb
│ │ │ └── validatable.rb
│ │ ├── models.rb
│ │ ├── modules.rb
│ │ ├── omniauth/
│ │ │ ├── config.rb
│ │ │ └── url_helpers.rb
│ │ ├── omniauth.rb
│ │ ├── orm/
│ │ │ ├── active_record.rb
│ │ │ └── mongoid.rb
│ │ ├── orm.rb
│ │ ├── parameter_filter.rb
│ │ ├── parameter_sanitizer.rb
│ │ ├── rails/
│ │ │ ├── routes.rb
│ │ │ └── warden_compat.rb
│ │ ├── rails.rb
│ │ ├── strategies/
│ │ │ ├── authenticatable.rb
│ │ │ ├── base.rb
│ │ │ ├── database_authenticatable.rb
│ │ │ └── rememberable.rb
│ │ ├── test/
│ │ │ ├── controller_helpers.rb
│ │ │ └── integration_helpers.rb
│ │ ├── time_inflector.rb
│ │ ├── token_generator.rb
│ │ └── version.rb
│ ├── devise.rb
│ └── generators/
│ ├── active_record/
│ │ ├── devise_generator.rb
│ │ └── templates/
│ │ ├── migration.rb
│ │ └── migration_existing.rb
│ ├── devise/
│ │ ├── controllers_generator.rb
│ │ ├── devise_generator.rb
│ │ ├── install_generator.rb
│ │ ├── orm_helpers.rb
│ │ └── views_generator.rb
│ ├── mongoid/
│ │ └── devise_generator.rb
│ └── templates/
│ ├── README
│ ├── controllers/
│ │ ├── README
│ │ ├── confirmations_controller.rb
│ │ ├── omniauth_callbacks_controller.rb
│ │ ├── passwords_controller.rb
│ │ ├── registrations_controller.rb
│ │ ├── sessions_controller.rb
│ │ └── unlocks_controller.rb
│ ├── devise.rb
│ ├── markerb/
│ │ ├── confirmation_instructions.markerb
│ │ ├── email_changed.markerb
│ │ ├── password_change.markerb
│ │ ├── reset_password_instructions.markerb
│ │ └── unlock_instructions.markerb
│ └── simple_form_for/
│ ├── confirmations/
│ │ └── new.html.erb
│ ├── passwords/
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ ├── registrations/
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ ├── sessions/
│ │ └── new.html.erb
│ └── unlocks/
│ └── new.html.erb
└── test/
├── controllers/
│ ├── custom_registrations_controller_test.rb
│ ├── custom_strategy_test.rb
│ ├── helper_methods_test.rb
│ ├── helpers_test.rb
│ ├── inherited_controller_i18n_messages_test.rb
│ ├── internal_helpers_test.rb
│ ├── load_hooks_controller_test.rb
│ ├── passwords_controller_test.rb
│ ├── sessions_controller_test.rb
│ └── url_helpers_test.rb
├── delegator_test.rb
├── devise_test.rb
├── failure_app_test.rb
├── generators/
│ ├── active_record_generator_test.rb
│ ├── controllers_generator_test.rb
│ ├── devise_generator_test.rb
│ ├── install_generator_test.rb
│ ├── mongoid_generator_test.rb
│ └── views_generator_test.rb
├── helpers/
│ └── devise_helper_test.rb
├── integration/
│ ├── authenticatable_test.rb
│ ├── confirmable_test.rb
│ ├── database_authenticatable_test.rb
│ ├── http_authenticatable_test.rb
│ ├── lockable_test.rb
│ ├── mounted_engine_test.rb
│ ├── omniauthable_test.rb
│ ├── recoverable_test.rb
│ ├── registerable_test.rb
│ ├── rememberable_test.rb
│ ├── timeoutable_test.rb
│ └── trackable_test.rb
├── mailers/
│ ├── confirmation_instructions_test.rb
│ ├── email_changed_test.rb
│ ├── mailer_test.rb
│ ├── reset_password_instructions_test.rb
│ └── unlock_instructions_test.rb
├── mapping_test.rb
├── models/
│ ├── authenticatable_test.rb
│ ├── confirmable_test.rb
│ ├── database_authenticatable_test.rb
│ ├── lockable_test.rb
│ ├── omniauthable_test.rb
│ ├── recoverable_test.rb
│ ├── registerable_test.rb
│ ├── rememberable_test.rb
│ ├── serializable_test.rb
│ ├── timeoutable_test.rb
│ ├── trackable_test.rb
│ └── validatable_test.rb
├── models_test.rb
├── omniauth/
│ ├── config_test.rb
│ └── url_helpers_test.rb
├── orm/
│ ├── active_record.rb
│ └── mongoid.rb
├── parameter_sanitizer_test.rb
├── rails_app/
│ ├── Rakefile
│ ├── app/
│ │ ├── active_record/
│ │ │ ├── admin.rb
│ │ │ ├── shim.rb
│ │ │ ├── user.rb
│ │ │ ├── user_on_engine.rb
│ │ │ ├── user_on_main_app.rb
│ │ │ ├── user_with_validations.rb
│ │ │ └── user_without_email.rb
│ │ ├── controllers/
│ │ │ ├── admins/
│ │ │ │ └── sessions_controller.rb
│ │ │ ├── admins_controller.rb
│ │ │ ├── application_controller.rb
│ │ │ ├── application_with_fake_engine.rb
│ │ │ ├── custom/
│ │ │ │ └── registrations_controller.rb
│ │ │ ├── home_controller.rb
│ │ │ ├── publisher/
│ │ │ │ ├── registrations_controller.rb
│ │ │ │ └── sessions_controller.rb
│ │ │ ├── streaming_controller.rb
│ │ │ ├── users/
│ │ │ │ └── omniauth_callbacks_controller.rb
│ │ │ └── users_controller.rb
│ │ ├── helpers/
│ │ │ └── application_helper.rb
│ │ ├── mailers/
│ │ │ └── users/
│ │ │ ├── from_proc_mailer.rb
│ │ │ ├── mailer.rb
│ │ │ └── reply_to_mailer.rb
│ │ ├── mongoid/
│ │ │ ├── admin.rb
│ │ │ ├── shim.rb
│ │ │ ├── user.rb
│ │ │ ├── user_on_engine.rb
│ │ │ ├── user_on_main_app.rb
│ │ │ ├── user_with_validations.rb
│ │ │ └── user_without_email.rb
│ │ └── views/
│ │ ├── admins/
│ │ │ ├── index.html.erb
│ │ │ └── sessions/
│ │ │ └── new.html.erb
│ │ ├── home/
│ │ │ ├── admin_dashboard.html.erb
│ │ │ ├── index.html.erb
│ │ │ ├── join.html.erb
│ │ │ ├── private.html.erb
│ │ │ └── user_dashboard.html.erb
│ │ ├── layouts/
│ │ │ └── application.html.erb
│ │ └── users/
│ │ ├── edit_form.html.erb
│ │ ├── index.html.erb
│ │ ├── mailer/
│ │ │ └── confirmation_instructions.erb
│ │ └── sessions/
│ │ └── new.html.erb
│ ├── bin/
│ │ ├── bundle
│ │ ├── rails
│ │ └── rake
│ ├── config/
│ │ ├── application.rb
│ │ ├── boot.rb
│ │ ├── database.yml
│ │ ├── environment.rb
│ │ ├── environments/
│ │ │ ├── development.rb
│ │ │ ├── production.rb
│ │ │ └── test.rb
│ │ ├── initializers/
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── devise.rb
│ │ │ ├── inflections.rb
│ │ │ ├── secret_token.rb
│ │ │ └── session_store.rb
│ │ └── routes.rb
│ ├── config.ru
│ ├── db/
│ │ ├── migrate/
│ │ │ └── 20100401102949_create_tables.rb
│ │ └── schema.rb
│ ├── lib/
│ │ ├── lazy_load_test_module.rb
│ │ ├── shared_admin.rb
│ │ ├── shared_user.rb
│ │ ├── shared_user_without_email.rb
│ │ └── shared_user_without_omniauth.rb
│ └── public/
│ ├── 404.html
│ ├── 422.html
│ └── 500.html
├── rails_test.rb
├── routes_test.rb
├── support/
│ ├── action_controller/
│ │ └── record_identifier.rb
│ ├── assertions.rb
│ ├── helpers.rb
│ ├── http_method_compatibility.rb
│ ├── integration.rb
│ ├── locale/
│ │ ├── de.yml
│ │ ├── en.yml
│ │ └── pt-BR.yml
│ ├── mongoid.yml
│ └── webrat/
│ ├── integrations/
│ │ └── rails.rb
│ └── matchers.rb
├── test/
│ ├── controller_helpers_test.rb
│ └── integration_helpers_test.rb
├── test_helper.rb
└── test_models.rb
SYMBOL INDEX (1041 symbols across 172 files)
FILE: app/controllers/devise/confirmations_controller.rb
class Devise::ConfirmationsController (line 3) | class Devise::ConfirmationsController < DeviseController
method new (line 5) | def new
method create (line 10) | def create
method show (line 22) | def show
method after_resending_confirmation_instructions_path_for (line 38) | def after_resending_confirmation_instructions_path_for(resource_name)
method after_confirmation_path_for (line 43) | def after_confirmation_path_for(resource_name, resource)
method translation_scope (line 51) | def translation_scope
FILE: app/controllers/devise/omniauth_callbacks_controller.rb
class Devise::OmniauthCallbacksController (line 3) | class Devise::OmniauthCallbacksController < DeviseController
method passthru (line 6) | def passthru
method failure (line 10) | def failure
method failed_strategy (line 17) | def failed_strategy
method failure_message (line 21) | def failure_message
method after_omniauth_failure_path_for (line 29) | def after_omniauth_failure_path_for(scope)
method translation_scope (line 33) | def translation_scope
FILE: app/controllers/devise/passwords_controller.rb
class Devise::PasswordsController (line 3) | class Devise::PasswordsController < DeviseController
method new (line 9) | def new
method create (line 14) | def create
method edit (line 26) | def edit
method update (line 33) | def update
method after_resetting_password_path_for (line 55) | def after_resetting_password_path_for(resource)
method after_sending_reset_password_instructions_path_for (line 60) | def after_sending_reset_password_instructions_path_for(resource_name)
method assert_reset_token_passed (line 65) | def assert_reset_token_passed
method sign_in_after_reset_password? (line 73) | def sign_in_after_reset_password?
method unlockable? (line 79) | def unlockable?(resource)
method translation_scope (line 85) | def translation_scope
FILE: app/controllers/devise/registrations_controller.rb
class Devise::RegistrationsController (line 3) | class Devise::RegistrationsController < DeviseController
method new (line 9) | def new
method create (line 16) | def create
method edit (line 39) | def edit
method update (line 46) | def update
method destroy (line 65) | def destroy
method cancel (line 78) | def cancel
method update_resource (line 87) | def update_resource(resource, params)
method build_resource (line 93) | def build_resource(hash = {})
method sign_up (line 99) | def sign_up(resource_name, resource)
method after_sign_up_path_for (line 105) | def after_sign_up_path_for(resource)
method after_inactive_sign_up_path_for (line 111) | def after_inactive_sign_up_path_for(resource)
method after_update_path_for (line 120) | def after_update_path_for(resource)
method authenticate_scope! (line 125) | def authenticate_scope!
method sign_in_after_change_password? (line 131) | def sign_in_after_change_password?
method sign_up_params (line 137) | def sign_up_params
method account_update_params (line 141) | def account_update_params
method translation_scope (line 145) | def translation_scope
method set_flash_message_for_update (line 151) | def set_flash_message_for_update(resource, prev_unconfirmed_email)
method update_needs_confirmation? (line 164) | def update_needs_confirmation?(resource, previous)
FILE: app/controllers/devise/sessions_controller.rb
class Devise::SessionsController (line 3) | class Devise::SessionsController < DeviseController
method new (line 10) | def new
method create (line 18) | def create
method destroy (line 27) | def destroy
method sign_in_params (line 36) | def sign_in_params
method serialize_options (line 40) | def serialize_options(resource)
method auth_options (line 47) | def auth_options
method translation_scope (line 51) | def translation_scope
method verify_signed_out_user (line 61) | def verify_signed_out_user
method all_signed_out? (line 69) | def all_signed_out?
method respond_to_on_destroy (line 75) | def respond_to_on_destroy(non_navigational_status: :no_content)
FILE: app/controllers/devise/unlocks_controller.rb
class Devise::UnlocksController (line 3) | class Devise::UnlocksController < DeviseController
method new (line 7) | def new
method create (line 12) | def create
method show (line 24) | def show
method after_sending_unlock_instructions_path_for (line 40) | def after_sending_unlock_instructions_path_for(resource)
method after_unlock_path_for (line 45) | def after_unlock_path_for(resource)
method translation_scope (line 49) | def translation_scope
FILE: app/controllers/devise_controller.rb
class DeviseController (line 4) | class DeviseController < Devise.parent_controller.constantize
method _prefixes (line 28) | def _prefixes #:nodoc:
method internal_methods (line 45) | def self.internal_methods #:nodoc:
method resource (line 52) | def resource
method resource_name (line 57) | def resource_name
method resource_class (line 63) | def resource_class
method signed_in_resource (line 68) | def signed_in_resource
method devise_mapping (line 73) | def devise_mapping
method assert_is_devise_resource! (line 78) | def assert_is_devise_resource! #:nodoc:
method navigational_formats (line 98) | def navigational_formats
method unknown_action! (line 102) | def unknown_action!(msg)
method resource= (line 108) | def resource=(new_resource)
method require_no_authentication (line 116) | def require_no_authentication
method successfully_sent? (line 137) | def successfully_sent?(resource)
method set_flash_message (line 168) | def set_flash_message(key, kind, options = {})
method set_flash_message! (line 178) | def set_flash_message!(key, kind, options = {})
method set_minimum_password_length (line 185) | def set_minimum_password_length
method devise_i18n_options (line 191) | def devise_i18n_options(options)
method find_message (line 196) | def find_message(kind, options = {})
method translation_scope (line 207) | def translation_scope
method clean_up_passwords (line 211) | def clean_up_passwords(object)
method respond_with_navigational (line 215) | def respond_with_navigational(*args, &block)
method resource_params (line 221) | def resource_params
FILE: app/helpers/devise_helper.rb
type DeviseHelper (line 4) | module DeviseHelper
FILE: app/mailers/devise/mailer.rb
class Devise::Mailer (line 4) | class Devise::Mailer < Devise.parent_mailer.constantize
method confirmation_instructions (line 7) | def confirmation_instructions(record, token, opts = {})
method reset_password_instructions (line 12) | def reset_password_instructions(record, token, opts = {})
method unlock_instructions (line 17) | def unlock_instructions(record, token, opts = {})
method email_changed (line 22) | def email_changed(record, opts = {})
method password_change (line 26) | def password_change(record, opts = {})
FILE: guides/bug_report_templates/integration_test.rb
class DeviseCreateUsers (line 27) | class DeviseCreateUsers < ActiveRecord::Migration
method change (line 28) | def change
class TestApp (line 43) | class TestApp < Rails::Application
class User (line 63) | class User < ActiveRecord::Base
class ApplicationController (line 73) | class ApplicationController < ActionController::Base
class TestController (line 76) | class TestController < ApplicationController
method index (line 81) | def index
class BugTest (line 88) | class BugTest < ActionDispatch::IntegrationTest
method test_returns_success (line 92) | def test_returns_success
method app (line 103) | def app
FILE: lib/devise.rb
type Devise (line 11) | module Devise
type Controllers (line 22) | module Controllers
type Hooks (line 32) | module Hooks
type Mailers (line 36) | module Mailers
type Strategies (line 40) | module Strategies
type Test (line 45) | module Test
function mappings (line 277) | def self.mappings
function setup (line 317) | def self.setup
class Getter (line 321) | class Getter
method initialize (line 322) | def initialize(name)
method get (line 326) | def get
function ref (line 336) | def self.ref(arg)
function available_router_name (line 344) | def self.available_router_name
function omniauth_providers (line 348) | def self.omniauth_providers
function mailer (line 353) | def self.mailer
function mailer= (line 358) | def self.mailer=(class_name)
function add_mapping (line 364) | def self.add_mapping(resource, options)
function add_module (line 397) | def self.add_module(module_name, options = {})
function warden (line 453) | def self.warden(&block)
function omniauth (line 461) | def self.omniauth(provider, *args)
function include_helpers (line 467) | def self.include_helpers(scope)
function regenerate_helpers! (line 479) | def self.regenerate_helpers!
function configure_warden! (line 486) | def self.configure_warden! #:nodoc:
function friendly_token (line 511) | def self.friendly_token(length = 20)
function secure_compare (line 519) | def self.secure_compare(a, b)
function deprecator (line 524) | def self.deprecator
FILE: lib/devise/controllers/helpers.rb
type Devise (line 3) | module Devise
type Controllers (line 4) | module Controllers
type Helpers (line 6) | module Helpers
type ClassMethods (line 17) | module ClassMethods
function devise_group (line 39) | def devise_group(group_name, opts = {})
function log_process_action (line 83) | def log_process_action(payload)
function define_helpers (line 113) | def self.define_helpers(mapping) #:nodoc:
function warden (line 144) | def warden
function devise_controller? (line 153) | def devise_controller?
function devise_parameter_sanitizer (line 160) | def devise_parameter_sanitizer
function allow_params_authentication! (line 165) | def allow_params_authentication!
function signed_in_root_path (line 171) | def signed_in_root_path(resource_or_scope)
function after_sign_in_path_for (line 217) | def after_sign_in_path_for(resource_or_scope)
function after_sign_out_path_for (line 227) | def after_sign_out_path_for(resource_or_scope)
function sign_in_and_redirect (line 237) | def sign_in_and_redirect(resource_or_scope, *args)
function sign_out_and_redirect (line 247) | def sign_out_and_redirect(resource_or_scope)
function handle_unverified_request (line 256) | def handle_unverified_request
function request_format (line 262) | def request_format
function is_navigational_format? (line 266) | def is_navigational_format?
function is_flashing_format? (line 272) | def is_flashing_format?
function expire_data_after_sign_out! (line 278) | def expire_data_after_sign_out!
class MissingWarden (line 285) | class MissingWarden < StandardError
method initialize (line 286) | def initialize
FILE: lib/devise/controllers/rememberable.rb
type Devise (line 3) | module Devise
type Controllers (line 4) | module Controllers
type Rememberable (line 8) | module Rememberable
function cookie_values (line 10) | def self.cookie_values
function remember_me_is_active? (line 14) | def remember_me_is_active?(resource)
function remember_me (line 22) | def remember_me(resource)
function forget_me (line 30) | def forget_me(resource)
function forget_cookie_values (line 38) | def forget_cookie_values(resource)
function remember_cookie_values (line 42) | def remember_cookie_values(resource)
function remember_key (line 51) | def remember_key(resource, scope)
FILE: lib/devise/controllers/responder.rb
type Devise (line 3) | module Devise
type Controllers (line 4) | module Controllers
class Responder (line 7) | class Responder < ActionController::Responder
method error_status (line 15) | def self.error_status
method redirect_status (line 19) | def self.redirect_status
method error_status= (line 23) | def self.error_status=(*)
method redirect_status= (line 28) | def self.redirect_status=(*)
FILE: lib/devise/controllers/scoped_views.rb
type Devise (line 3) | module Devise
type Controllers (line 4) | module Controllers
type ScopedViews (line 5) | module ScopedViews
type ClassMethods (line 8) | module ClassMethods
function scoped_views? (line 9) | def scoped_views?
function scoped_views= (line 13) | def scoped_views=(value)
FILE: lib/devise/controllers/sign_in_out.rb
type Devise (line 3) | module Devise
type Controllers (line 4) | module Controllers
type SignInOut (line 7) | module SignInOut
function signed_in? (line 13) | def signed_in?(scope = nil)
function sign_in (line 33) | def sign_in(resource_or_scope, *args)
function bypass_sign_in (line 56) | def bypass_sign_in(resource, scope: nil)
function sign_out (line 71) | def sign_out(resource_or_scope = nil)
function sign_out_all_scopes (line 86) | def sign_out_all_scopes(lock = true)
function expire_data_after_sign_in! (line 99) | def expire_data_after_sign_in!
FILE: lib/devise/controllers/store_location.rb
type Devise (line 5) | module Devise
type Controllers (line 6) | module Controllers
type StoreLocation (line 10) | module StoreLocation
function stored_location_for (line 18) | def stored_location_for(resource_or_scope)
function store_location_for (line 36) | def store_location_for(resource_or_scope, location)
function parse_uri (line 45) | def parse_uri(location)
function stored_location_key_for (line 51) | def stored_location_key_for(resource_or_scope)
function extract_path_from_location (line 56) | def extract_path_from_location(location)
function remove_domain_from_uri (line 67) | def remove_domain_from_uri(uri)
function add_fragment_back_to_path (line 71) | def add_fragment_back_to_path(uri, path)
FILE: lib/devise/controllers/url_helpers.rb
type Devise (line 3) | module Devise
type Controllers (line 4) | module Controllers
type UrlHelpers (line 30) | module UrlHelpers
function remove_helpers! (line 31) | def self.remove_helpers!
function generate_helpers! (line 37) | def self.generate_helpers!(routes = nil)
function _devise_route_context (line 64) | def _devise_route_context
FILE: lib/devise/delegator.rb
type Devise (line 3) | module Devise
class Delegator (line 5) | class Delegator
method call (line 6) | def call(env)
method failure_app (line 10) | def failure_app(env)
FILE: lib/devise/encryptor.rb
type Devise (line 5) | module Devise
type Encryptor (line 6) | module Encryptor
function digest (line 7) | def self.digest(klass, password)
function compare (line 14) | def self.compare(klass, hashed_password, password)
FILE: lib/devise/failure_app.rb
type Devise (line 5) | module Devise
class FailureApp (line 10) | class FailureApp < ActionController::Metal
method call (line 26) | def self.call(env)
method default_url_options (line 34) | def self.default_url_options(*args)
method respond (line 42) | def respond
method http_auth (line 52) | def http_auth
method recall (line 59) | def recall
method redirect (line 86) | def redirect
method i18n_options (line 101) | def i18n_options(options)
method i18n_message (line 105) | def i18n_message(default = nil)
method i18n_locale (line 131) | def i18n_locale
method redirect_url (line 135) | def redirect_url
method route (line 151) | def route(scope)
method scope_url (line 155) | def scope_url
method skip_format? (line 182) | def skip_format?
method http_auth? (line 194) | def http_auth?
method http_auth_header? (line 204) | def http_auth_header?
method http_auth_body (line 208) | def http_auth_body
method recall_app (line 220) | def recall_app(app)
method warden (line 227) | def warden
method warden_options (line 231) | def warden_options
method warden_message (line 235) | def warden_message
method scope (line 239) | def scope
method scope_class (line 243) | def scope_class
method attempted_path (line 247) | def attempted_path
method store_location! (line 255) | def store_location!
method is_navigational_format? (line 259) | def is_navigational_format?
method is_flashing_format? (line 265) | def is_flashing_format?
method request_format (line 269) | def request_format
method relative_url_root (line 273) | def relative_url_root
method relative_url_root? (line 281) | def relative_url_root?
FILE: lib/devise/hooks/proxy.rb
type Devise (line 3) | module Devise
type Hooks (line 4) | module Hooks
class Proxy (line 7) | class Proxy #:nodoc:
method initialize (line 14) | def initialize(warden)
method session (line 18) | def session
FILE: lib/devise/mailers/helpers.rb
type Devise (line 3) | module Devise
type Mailers (line 4) | module Mailers
type Helpers (line 5) | module Helpers
function devise_mail (line 17) | def devise_mail(record, action, opts = {}, &block)
function initialize_from_record (line 22) | def initialize_from_record(record)
function devise_mapping (line 27) | def devise_mapping
function headers_for (line 31) | def headers_for(action, opts)
function mailer_sender (line 50) | def mailer_sender(mapping)
function template_paths (line 58) | def template_paths
function subject_for (line 81) | def subject_for(key)
FILE: lib/devise/mapping.rb
type Devise (line 3) | module Devise
class Mapping (line 26) | class Mapping #:nodoc:
method find_scope! (line 35) | def self.find_scope!(obj)
method find_by_path! (line 49) | def self.find_by_path!(path, path_type = :fullpath)
method initialize (line 54) | def initialize(name, options) #:nodoc:
method modules (line 77) | def modules
method to (line 82) | def to
method strategies (line 86) | def strategies
method no_input_strategies (line 90) | def no_input_strategies
method routes (line 94) | def routes
method authenticatable? (line 98) | def authenticatable?
method fullpath (line 102) | def fullpath
method add_module (line 113) | def self.add_module(m)
method default_failure_app (line 123) | def default_failure_app(options)
method default_controllers (line 131) | def default_controllers(options)
method default_path_names (line 138) | def default_path_names(options)
method default_constraints (line 144) | def default_constraints(options)
method default_defaults (line 149) | def default_defaults(options)
method default_used_route (line 154) | def default_used_route(options)
method default_used_helpers (line 166) | def default_used_helpers(options)
FILE: lib/devise/models.rb
type Devise (line 3) | module Devise
type Models (line 4) | module Models
class MissingAttribute (line 5) | class MissingAttribute < StandardError
method initialize (line 6) | def initialize(attributes)
method message (line 10) | def message
function config (line 31) | def self.config(mod, *accessors) #:nodoc:
function check_fields! (line 54) | def self.check_fields!(klass)
function devise (line 79) | def devise(*modules)
function devise_modules_hook! (line 116) | def devise_modules_hook!
FILE: lib/devise/models/authenticatable.rb
type Devise (line 6) | module Devise
type Models (line 7) | module Models
type Authenticatable (line 55) | module Authenticatable
function required_fields (line 71) | def self.required_fields(klass)
function valid_for_authentication? (line 81) | def valid_for_authentication?
function unauthenticated_message (line 85) | def unauthenticated_message
function active_for_authentication? (line 89) | def active_for_authentication?
function inactive_message (line 93) | def inactive_message
function authenticatable_salt (line 97) | def authenticatable_salt
function serializable_hash (line 105) | def serializable_hash(options = nil)
function inspect (line 120) | def inspect
function devise_mailer (line 129) | def devise_mailer
function send_devise_notification (line 193) | def send_devise_notification(notification, *args)
function downcase_keys (line 198) | def downcase_keys
function strip_whitespace (line 202) | def strip_whitespace
function apply_to_attribute_or_variable (line 206) | def apply_to_attribute_or_variable(attr, method)
type ClassMethods (line 220) | module ClassMethods
function serialize_into_session (line 225) | def serialize_into_session(record)
function serialize_from_session (line 229) | def serialize_from_session(key, salt)
function params_authenticatable? (line 234) | def params_authenticatable?(strategy)
function http_authenticatable? (line 239) | def http_authenticatable?(strategy)
function find_for_authentication (line 263) | def find_for_authentication(tainted_conditions)
function find_first_by_auth_conditions (line 267) | def find_first_by_auth_conditions(tainted_conditions, opts = {})
function find_or_initialize_with_error_by (line 272) | def find_or_initialize_with_error_by(attribute, value, error = :...
function find_or_initialize_with_errors (line 277) | def find_or_initialize_with_errors(required_attributes, attribut...
function devise_parameter_filter (line 296) | def devise_parameter_filter
FILE: lib/devise/models/confirmable.rb
type Devise (line 3) | module Devise
type Models (line 4) | module Models
type Confirmable (line 45) | module Confirmable
function initialize (line 61) | def initialize(*args, &block)
function required_fields (line 70) | def self.required_fields(klass)
function confirm (line 79) | def confirm(args = {})
function confirmed? (line 106) | def confirmed?
function pending_reconfirmation? (line 110) | def pending_reconfirmation?
function send_confirmation_instructions (line 115) | def send_confirmation_instructions
function send_reconfirmation_instructions (line 124) | def send_reconfirmation_instructions
function resend_confirmation_instructions (line 134) | def resend_confirmation_instructions
function active_for_authentication? (line 144) | def active_for_authentication?
function inactive_message (line 149) | def inactive_message
function skip_confirmation! (line 155) | def skip_confirmation!
function skip_confirmation_notification! (line 161) | def skip_confirmation_notification!
function skip_reconfirmation! (line 167) | def skip_reconfirmation!
function skip_reconfirmation_in_callback! (line 175) | def skip_reconfirmation_in_callback!
function send_on_create_confirmation_instructions (line 182) | def send_on_create_confirmation_instructions
function confirmation_required? (line 187) | def confirmation_required?
function confirmation_period_valid? (line 213) | def confirmation_period_valid?
function confirmation_period_expired? (line 232) | def confirmation_period_expired?
function pending_any_confirmation (line 237) | def pending_any_confirmation
function generate_confirmation_token (line 248) | def generate_confirmation_token
function generate_confirmation_token! (line 257) | def generate_confirmation_token!
function postpone_email_change_until_confirmation_and_regenerate_confirmation_token (line 261) | def postpone_email_change_until_confirmation_and_regenerate_confir...
function postpone_email_change? (line 272) | def postpone_email_change?
function reconfirmation_required? (line 282) | def reconfirmation_required?
function send_confirmation_notification? (line 286) | def send_confirmation_notification?
function send_email_changed_notification? (line 292) | def send_email_changed_notification?
function after_confirmation (line 310) | def after_confirmation
type ClassMethods (line 313) | module ClassMethods
function send_confirmation_instructions (line 318) | def send_confirmation_instructions(attributes = {})
function confirm_by_token (line 331) | def confirm_by_token(confirmation_token)
function find_by_unconfirmed_email_with_errors (line 359) | def find_by_unconfirmed_email_with_errors(attributes = {})
FILE: lib/devise/models/database_authenticatable.rb
type Devise (line 5) | module Devise
type Models (line 6) | module Models
type DatabaseAuthenticatable (line 31) | module DatabaseAuthenticatable
function initialize (line 42) | def initialize(*args, &block)
function skip_email_changed_notification! (line 49) | def skip_email_changed_notification!
function skip_password_change_notification! (line 54) | def skip_password_change_notification!
function required_fields (line 58) | def self.required_fields(klass)
function password= (line 65) | def password=(new_password)
function valid_password? (line 71) | def valid_password?(password)
function clean_up_passwords (line 76) | def clean_up_passwords
function update_with_password (line 87) | def update_with_password(params)
function update_without_password (line 120) | def update_without_password(params)
function destroy_with_password (line 132) | def destroy_with_password(current_password)
function after_database_authentication (line 154) | def after_database_authentication
function authenticatable_salt (line 158) | def authenticatable_salt
function send_email_changed_notification (line 163) | def send_email_changed_notification
function send_password_change_notification (line 168) | def send_password_change_notification
function password_digest (line 179) | def password_digest(password)
function send_email_changed_notification? (line 183) | def send_email_changed_notification?
function send_password_change_notification? (line 187) | def send_password_change_notification?
type ClassMethods (line 191) | module ClassMethods
function find_for_database_authentication (line 198) | def find_for_database_authentication(conditions)
FILE: lib/devise/models/lockable.rb
type Devise (line 5) | module Devise
type Models (line 6) | module Models
type Lockable (line 24) | module Lockable
function required_fields (line 29) | def self.required_fields(klass)
function lock_access! (line 42) | def lock_access!(opts = { })
function unlock_access! (line 53) | def unlock_access!
function reset_failed_attempts! (line 61) | def reset_failed_attempts!
function access_locked? (line 69) | def access_locked?
function send_unlock_instructions (line 74) | def send_unlock_instructions
function resend_unlock_instructions (line 83) | def resend_unlock_instructions
function active_for_authentication? (line 89) | def active_for_authentication?
function inactive_message (line 95) | def inactive_message
function valid_for_authentication? (line 102) | def valid_for_authentication?
function increment_failed_attempts (line 122) | def increment_failed_attempts
function unauthenticated_message (line 127) | def unauthenticated_message
function attempts_exceeded? (line 143) | def attempts_exceeded?
function last_attempt? (line 147) | def last_attempt?
function lock_expired? (line 152) | def lock_expired?
function if_access_locked (line 162) | def if_access_locked
type ClassMethods (line 171) | module ClassMethods
function send_unlock_instructions (line 179) | def send_unlock_instructions(attributes = {})
function unlock_access_by_token (line 189) | def unlock_access_by_token(unlock_token)
function unlock_strategy_enabled? (line 200) | def unlock_strategy_enabled?(strategy)
function lock_strategy_enabled? (line 206) | def lock_strategy_enabled?(strategy)
FILE: lib/devise/models/omniauthable.rb
type Devise (line 5) | module Devise
type Models (line 6) | module Models
type Omniauthable (line 17) | module Omniauthable
function required_fields (line 20) | def self.required_fields(klass)
type ClassMethods (line 24) | module ClassMethods
FILE: lib/devise/models/recoverable.rb
type Devise (line 3) | module Devise
type Models (line 4) | module Models
type Recoverable (line 24) | module Recoverable
function required_fields (line 27) | def self.required_fields(klass)
function reset_password (line 37) | def reset_password(new_password, new_password_confirmation)
function send_reset_password_instructions (line 50) | def send_reset_password_instructions
function reset_password_period_valid? (line 77) | def reset_password_period_valid?
function clear_reset_password_token (line 84) | def clear_reset_password_token
function set_reset_password_token (line 89) | def set_reset_password_token
function send_reset_password_instructions_notification (line 98) | def send_reset_password_instructions_notification(token)
function clear_reset_password_token? (line 102) | def clear_reset_password_token?
type ClassMethods (line 111) | module ClassMethods
function with_reset_password_token (line 114) | def with_reset_password_token(token)
function send_reset_password_instructions (line 123) | def send_reset_password_instructions(attributes = {})
function reset_password_by_token (line 134) | def reset_password_by_token(attributes = {})
FILE: lib/devise/models/registerable.rb
type Devise (line 3) | module Devise
type Models (line 4) | module Models
type Registerable (line 7) | module Registerable
function required_fields (line 10) | def self.required_fields(klass)
type ClassMethods (line 14) | module ClassMethods
function new_with_session (line 21) | def new_with_session(params, session)
FILE: lib/devise/models/rememberable.rb
type Devise (line 7) | module Devise
type Models (line 8) | module Models
type Rememberable (line 41) | module Rememberable
function required_fields (line 46) | def self.required_fields(klass)
function remember_me! (line 50) | def remember_me!
function forget_me! (line 58) | def forget_me!
function remember_expires_at (line 65) | def remember_expires_at
function extend_remember_period (line 69) | def extend_remember_period
function rememberable_value (line 73) | def rememberable_value
function rememberable_options (line 86) | def rememberable_options
function after_remembered (line 100) | def after_remembered
function remember_me? (line 103) | def remember_me?(token, generated_at)
function time_from_json (line 124) | def time_from_json(value)
type ClassMethods (line 132) | module ClassMethods
function serialize_into_cookie (line 134) | def serialize_into_cookie(record)
function serialize_from_cookie (line 139) | def serialize_from_cookie(*args)
function remember_token (line 147) | def remember_token #:nodoc:
FILE: lib/devise/models/timeoutable.rb
type Devise (line 5) | module Devise
type Models (line 6) | module Models
type Timeoutable (line 22) | module Timeoutable
function required_fields (line 25) | def self.required_fields(klass)
function timedout? (line 30) | def timedout?(last_access)
function timeout_in (line 34) | def timeout_in
type ClassMethods (line 40) | module ClassMethods
FILE: lib/devise/models/trackable.rb
type Devise (line 5) | module Devise
type Models (line 6) | module Models
type Trackable (line 15) | module Trackable
function required_fields (line 16) | def self.required_fields(klass)
function update_tracked_fields (line 20) | def update_tracked_fields(request)
function update_tracked_fields! (line 33) | def update_tracked_fields!(request)
function extract_ip_from (line 45) | def extract_ip_from(request)
FILE: lib/devise/models/validatable.rb
type Devise (line 3) | module Devise
type Models (line 4) | module Models
type Validatable (line 19) | module Validatable
function required_fields (line 24) | def self.required_fields(klass)
function included (line 28) | def self.included(base)
function assert_validations_api! (line 43) | def self.assert_validations_api!(base) #:nodoc:
function password_required? (line 57) | def password_required?
function email_required? (line 61) | def email_required?
type ClassMethods (line 65) | module ClassMethods
FILE: lib/devise/omniauth.rb
type Devise (line 22) | module Devise
type OmniAuth (line 23) | module OmniAuth
FILE: lib/devise/omniauth/config.rb
type Devise (line 3) | module Devise
type OmniAuth (line 4) | module OmniAuth
class StrategyNotFound (line 5) | class StrategyNotFound < NameError
method initialize (line 6) | def initialize(strategy)
class Config (line 13) | class Config
method initialize (line 17) | def initialize(provider, args)
method strategy_class (line 26) | def strategy_class
method find_strategy (line 30) | def find_strategy
method autoload_strategy (line 37) | def autoload_strategy
FILE: lib/devise/omniauth/url_helpers.rb
type Devise (line 3) | module Devise
type OmniAuth (line 4) | module OmniAuth
type UrlHelpers (line 5) | module UrlHelpers
function omniauth_authorize_path (line 6) | def omniauth_authorize_path(resource_or_scope, provider, *args)
function omniauth_authorize_url (line 11) | def omniauth_authorize_url(resource_or_scope, provider, *args)
function omniauth_callback_path (line 16) | def omniauth_callback_path(resource_or_scope, provider, *args)
function omniauth_callback_url (line 21) | def omniauth_callback_url(resource_or_scope, provider, *args)
FILE: lib/devise/orm.rb
type Devise (line 3) | module Devise
type Orm (line 4) | module Orm # :nodoc:
function active_record? (line 5) | def self.active_record?(model)
function included (line 9) | def self.included(model)
type DirtyTrackingActiveRecordMethods (line 17) | module DirtyTrackingActiveRecordMethods
function devise_email_before_last_save (line 18) | def devise_email_before_last_save
function devise_email_in_database (line 22) | def devise_email_in_database
function devise_saved_change_to_email? (line 26) | def devise_saved_change_to_email?
function devise_saved_change_to_encrypted_password? (line 30) | def devise_saved_change_to_encrypted_password?
function devise_will_save_change_to_email? (line 34) | def devise_will_save_change_to_email?
function devise_unconfirmed_email_will_change! (line 38) | def devise_unconfirmed_email_will_change!
function devise_respond_to_and_will_save_change_to_attribute? (line 42) | def devise_respond_to_and_will_save_change_to_attribute?(attribute)
type DirtyTrackingMongoidMethods (line 47) | module DirtyTrackingMongoidMethods
function devise_email_before_last_save (line 48) | def devise_email_before_last_save
function devise_email_in_database (line 52) | def devise_email_in_database
function devise_saved_change_to_email? (line 56) | def devise_saved_change_to_email?
function devise_saved_change_to_encrypted_password? (line 60) | def devise_saved_change_to_encrypted_password?
function devise_will_save_change_to_email? (line 64) | def devise_will_save_change_to_email?
function devise_unconfirmed_email_will_change! (line 68) | def devise_unconfirmed_email_will_change!
function devise_respond_to_and_will_save_change_to_attribute? (line 75) | def devise_respond_to_and_will_save_change_to_attribute?(attribute)
FILE: lib/devise/parameter_filter.rb
type Devise (line 3) | module Devise
class ParameterFilter (line 4) | class ParameterFilter
method initialize (line 5) | def initialize(case_insensitive_keys, strip_whitespace_keys)
method filter (line 10) | def filter(conditions)
method filtered_hash_by_method_for_given_keys (line 19) | def filtered_hash_by_method_for_given_keys(conditions, method, condi...
method stringify_params (line 31) | def stringify_params(conditions)
method param_requires_string_conversion? (line 40) | def param_requires_string_conversion?(value)
FILE: lib/devise/parameter_sanitizer.rb
type Devise (line 3) | module Devise
class ParameterSanitizer (line 37) | class ParameterSanitizer
method initialize (line 44) | def initialize(resource_class, resource_name, params)
method sanitize (line 70) | def sanitize(action)
method permit (line 110) | def permit(action, keys: nil, except: nil, &block)
method cast_to_hash (line 132) | def cast_to_hash(params)
method default_params (line 136) | def default_params
method hashable_resource_params? (line 144) | def hashable_resource_params?
method empty_params (line 148) | def empty_params
method permit_keys (line 152) | def permit_keys(parameters, keys)
method extract_auth_keys (line 156) | def extract_auth_keys(klass)
method unknown_action! (line 162) | def unknown_action!(action)
FILE: lib/devise/rails.rb
type Devise (line 6) | module Devise
class Engine (line 7) | class Engine < ::Rails::Engine
FILE: lib/devise/rails/routes.rb
type Devise (line 6) | module Devise
type RouteSet (line 7) | module RouteSet
function finalize! (line 8) | def finalize!
type ActionDispatch::Routing (line 28) | module ActionDispatch::Routing
class RouteSet (line 29) | class RouteSet #:nodoc:
class Mapper (line 35) | class Mapper
method devise_for (line 226) | def devise_for(*resources)
method authenticate (line 289) | def authenticate(scope = nil, block = nil)
method authenticated (line 313) | def authenticated(scope = nil, block = nil)
method unauthenticated (line 330) | def unauthenticated(scope = nil)
method devise_scope (line 362) | def devise_scope(scope)
method devise_session (line 376) | def devise_session(mapping, controllers) #:nodoc:
method devise_password (line 384) | def devise_password(mapping, controllers) #:nodoc:
method devise_confirmation (line 389) | def devise_confirmation(mapping, controllers) #:nodoc:
method devise_unlock (line 394) | def devise_unlock(mapping, controllers) #:nodoc:
method devise_registration (line 401) | def devise_registration(mapping, controllers) #:nodoc:
method devise_omniauth_callback (line 420) | def devise_omniauth_callback(mapping, controllers) #:nodoc:
method with_devise_exclusive_scope (line 460) | def with_devise_exclusive_scope(new_path, new_as, options) #:nodoc:
method constraints_for (line 476) | def constraints_for(method_to_apply, scope = nil, block = nil)
method set_omniauth_path_prefix! (line 487) | def set_omniauth_path_prefix!(path_prefix) #:nodoc:
method raise_no_secret_key (line 498) | def raise_no_secret_key #:nodoc:
method raise_no_devise_method_error! (line 508) | def raise_no_devise_method_error!(klass) #:nodoc:
FILE: lib/devise/rails/warden_compat.rb
type Warden::Mixins::Common (line 3) | module Warden::Mixins::Common
function request (line 4) | def request
function reset_session! (line 8) | def reset_session!
function cookies (line 12) | def cookies
FILE: lib/devise/strategies/authenticatable.rb
type Devise (line 5) | module Devise
type Strategies (line 6) | module Strategies
class Authenticatable (line 10) | class Authenticatable < Base
method store? (line 13) | def store?
method valid? (line 17) | def valid?
method clean_up_csrf? (line 24) | def clean_up_csrf?
method validate (line 37) | def validate(resource, &block)
method remember_me (line 51) | def remember_me(resource)
method remember_me? (line 56) | def remember_me?
method valid_for_http_auth? (line 66) | def valid_for_http_auth?
method valid_for_params_auth? (line 77) | def valid_for_params_auth?
method http_authenticatable? (line 83) | def http_authenticatable?
method params_authenticatable? (line 88) | def params_authenticatable?
method params_auth_hash (line 93) | def params_auth_hash
method http_auth_hash (line 98) | def http_auth_hash
method valid_params_request? (line 104) | def valid_params_request?
method valid_params? (line 109) | def valid_params?
method valid_password? (line 117) | def valid_password?
method decode_credentials (line 122) | def decode_credentials
method with_authentication_hash (line 128) | def with_authentication_hash(auth_type, auth_values)
method authentication_keys (line 136) | def authentication_keys
method http_authentication_key (line 140) | def http_authentication_key
method request_keys (line 147) | def request_keys
method request_values (line 151) | def request_values
method parse_authentication_key_values (line 157) | def parse_authentication_key_values(hash, keys)
method authenticatable_name (line 171) | def authenticatable_name
FILE: lib/devise/strategies/base.rb
type Devise (line 3) | module Devise
type Strategies (line 4) | module Strategies
class Base (line 6) | class Base < ::Warden::Strategies::Base
method store? (line 8) | def store?
method mapping (line 13) | def mapping
FILE: lib/devise/strategies/database_authenticatable.rb
type Devise (line 5) | module Devise
type Strategies (line 6) | module Strategies
class DatabaseAuthenticatable (line 8) | class DatabaseAuthenticatable < Authenticatable
method authenticate! (line 9) | def authenticate!
FILE: lib/devise/strategies/rememberable.rb
type Devise (line 5) | module Devise
type Strategies (line 6) | module Strategies
class Rememberable (line 11) | class Rememberable < Authenticatable
method valid? (line 13) | def valid?
method authenticate! (line 21) | def authenticate!
method clean_up_csrf? (line 41) | def clean_up_csrf?
method extend_remember_me? (line 47) | def extend_remember_me?(resource)
method remember_me? (line 51) | def remember_me?
method remember_key (line 55) | def remember_key
method remember_cookie (line 59) | def remember_cookie
FILE: lib/devise/test/controller_helpers.rb
type Devise (line 3) | module Devise
type Test (line 4) | module Test
type ControllerHelpers (line 26) | module ControllerHelpers
function process (line 34) | def process(*)
function setup_controller_for_warden (line 43) | def setup_controller_for_warden #:nodoc:
function warden (line 48) | def warden #:nodoc:
function sign_in (line 67) | def sign_in(resource, scope: nil)
function sign_out (line 82) | def sign_out(resource_or_scope)
function _catch_warden (line 93) | def _catch_warden(&block)
function _process_unauthenticated (line 116) | def _process_unauthenticated(env, options = {})
FILE: lib/devise/test/integration_helpers.rb
type Devise (line 3) | module Devise
type Test (line 20) | module Test
type IntegrationHelpers (line 21) | module IntegrationHelpers
function included (line 22) | def self.included(base)
function sign_in (line 37) | def sign_in(resource, scope: nil)
function sign_out (line 46) | def sign_out(resource_or_scope)
function setup_integration_for_devise (line 54) | def setup_integration_for_devise
function teardown_integration_for_devise (line 58) | def teardown_integration_for_devise
FILE: lib/devise/time_inflector.rb
type Devise (line 5) | module Devise
class TimeInflector (line 6) | class TimeInflector
FILE: lib/devise/token_generator.rb
type Devise (line 5) | module Devise
class TokenGenerator (line 6) | class TokenGenerator
method initialize (line 7) | def initialize(key_generator, digest = "SHA256")
method digest (line 12) | def digest(klass, column, value)
method generate (line 16) | def generate(klass, column)
method key_for (line 28) | def key_for(column)
FILE: lib/devise/version.rb
type Devise (line 3) | module Devise
FILE: lib/generators/active_record/devise_generator.rb
type ActiveRecord (line 6) | module ActiveRecord
type Generators (line 7) | module Generators
class DeviseGenerator (line 8) | class DeviseGenerator < Base
method copy_devise_migration (line 16) | def copy_devise_migration
method generate_model (line 24) | def generate_model
method inject_devise_content (line 28) | def inject_devise_content
method migration_data (line 43) | def migration_data
method ip_column (line 76) | def ip_column
method inet? (line 81) | def inet?
method rails61_and_up? (line 85) | def rails61_and_up?
method postgresql? (line 89) | def postgresql?
method ar_config (line 93) | def ar_config
method migration_version (line 105) | def migration_version
method primary_key_type (line 109) | def primary_key_type
method primary_key_string (line 113) | def primary_key_string
FILE: lib/generators/devise/controllers_generator.rb
type Devise (line 5) | module Devise
type Generators (line 6) | module Generators
class ControllersGenerator (line 7) | class ControllersGenerator < Rails::Generators::Base
method create_controllers (line 32) | def create_controllers
method show_readme (line 41) | def show_readme
FILE: lib/generators/devise/devise_generator.rb
type Devise (line 5) | module Devise
type Generators (line 6) | module Generators
class DeviseGenerator (line 7) | class DeviseGenerator < Rails::Generators::NamedBase
method add_devise_routes (line 20) | def add_devise_routes
FILE: lib/generators/devise/install_generator.rb
type Devise (line 6) | module Devise
type Generators (line 7) | module Generators
class InstallGenerator (line 10) | class InstallGenerator < Rails::Generators::Base
method copy_initializer (line 16) | def copy_initializer
method copy_locale (line 33) | def copy_locale
method show_readme (line 37) | def show_readme
FILE: lib/generators/devise/orm_helpers.rb
type Devise (line 3) | module Devise
type Generators (line 4) | module Generators
type OrmHelpers (line 5) | module OrmHelpers
function model_contents (line 6) | def model_contents
function model_exists? (line 19) | def model_exists?
function migration_exists? (line 23) | def migration_exists?(table_name)
function migration_path (line 27) | def migration_path
function model_path (line 31) | def model_path
FILE: lib/generators/devise/views_generator.rb
type Devise (line 5) | module Devise
type Generators (line 6) | module Generators
type ViewPathTemplates (line 10) | module ViewPathTemplates #:nodoc:
function copy_views (line 26) | def copy_views
function view_directory (line 42) | def view_directory(name, _target_path = nil)
function target_path (line 52) | def target_path
function plural_scope (line 56) | def plural_scope
class SharedViewsGenerator (line 61) | class SharedViewsGenerator < Rails::Generators::Base #:nodoc:
method copy_views (line 68) | def copy_views
class FormForGenerator (line 73) | class FormForGenerator < Rails::Generators::Base #:nodoc:
class SimpleFormForGenerator (line 80) | class SimpleFormForGenerator < Rails::Generators::Base #:nodoc:
method copy_views (line 86) | def copy_views
class ErbGenerator (line 94) | class ErbGenerator < Rails::Generators::Base #:nodoc:
method copy_views (line 100) | def copy_views
class MarkerbGenerator (line 107) | class MarkerbGenerator < Rails::Generators::Base #:nodoc:
method copy_views (line 113) | def copy_views
method target_path (line 119) | def target_path
class ViewsGenerator (line 124) | class ViewsGenerator < Rails::Generators::Base
FILE: lib/generators/mongoid/devise_generator.rb
type Mongoid (line 6) | module Mongoid
type Generators (line 7) | module Generators
class DeviseGenerator (line 8) | class DeviseGenerator < Rails::Generators::NamedBase
method generate_model (line 11) | def generate_model
method inject_field_types (line 15) | def inject_field_types
method inject_devise_content (line 19) | def inject_devise_content
method migration_data (line 23) | def migration_data
FILE: lib/generators/templates/controllers/confirmations_controller.rb
class ConfirmationsController (line 3) | class <%= @scope_prefix %>ConfirmationsController < Devise::Confirmation...
FILE: lib/generators/templates/controllers/omniauth_callbacks_controller.rb
class OmniauthCallbacksController (line 3) | class <%= @scope_prefix %>OmniauthCallbacksController < Devise::Omniauth...
FILE: lib/generators/templates/controllers/passwords_controller.rb
class PasswordsController (line 3) | class <%= @scope_prefix %>PasswordsController < Devise::PasswordsController
FILE: lib/generators/templates/controllers/registrations_controller.rb
class RegistrationsController (line 3) | class <%= @scope_prefix %>RegistrationsController < Devise::Registration...
FILE: lib/generators/templates/controllers/sessions_controller.rb
class SessionsController (line 3) | class <%= @scope_prefix %>SessionsController < Devise::SessionsController
FILE: lib/generators/templates/controllers/unlocks_controller.rb
class UnlocksController (line 3) | class <%= @scope_prefix %>UnlocksController < Devise::UnlocksController
FILE: test/controllers/custom_registrations_controller_test.rb
class CustomRegistrationsControllerTest (line 5) | class CustomRegistrationsControllerTest < Devise::ControllerTestCase
FILE: test/controllers/custom_strategy_test.rb
class CustomStrategyController (line 8) | class CustomStrategyController < ActionController::Base
method new (line 9) | def new
class CustomStrategy (line 21) | class CustomStrategy < Warden::Strategies::Base
method authenticate! (line 22) | def authenticate!
class CustomStrategyTest (line 29) | class CustomStrategyTest < Devise::ControllerTestCase
FILE: test/controllers/helper_methods_test.rb
class ApiController (line 5) | class ApiController < ActionController::Metal
class HelperMethodsTest (line 9) | class HelperMethodsTest < Devise::ControllerTestCase
FILE: test/controllers/helpers_test.rb
class ControllerAuthenticatableTest (line 6) | class ControllerAuthenticatableTest < Devise::ControllerTestCase
method setup (line 9) | def setup
FILE: test/controllers/inherited_controller_i18n_messages_test.rb
class SessionsInheritedController (line 5) | class SessionsInheritedController < Devise::SessionsController
method test_i18n_scope (line 6) | def test_i18n_scope
class AnotherInheritedController (line 11) | class AnotherInheritedController < SessionsInheritedController
method translation_scope (line 14) | def translation_scope
class InheritedControllerTest (line 19) | class InheritedControllerTest < Devise::ControllerTestCase
method setup (line 22) | def setup
class AnotherInheritedControllerTest (line 37) | class AnotherInheritedControllerTest < Devise::ControllerTestCase
method setup (line 40) | def setup
FILE: test/controllers/internal_helpers_test.rb
class MyController (line 5) | class MyController < DeviseController
class HelpersTest (line 8) | class HelpersTest < Devise::ControllerTestCase
method setup (line 11) | def setup
FILE: test/controllers/load_hooks_controller_test.rb
class LoadHooksControllerTest (line 5) | class LoadHooksControllerTest < Devise::ControllerTestCase
FILE: test/controllers/passwords_controller_test.rb
class PasswordsControllerTest (line 5) | class PasswordsControllerTest < Devise::ControllerTestCase
method put_update_with_params (line 15) | def put_update_with_params
FILE: test/controllers/sessions_controller_test.rb
class SessionsControllerTest (line 5) | class SessionsControllerTest < Devise::ControllerTestCase
FILE: test/controllers/url_helpers_test.rb
class RoutesTest (line 5) | class RoutesTest < Devise::ControllerTestCase
method assert_path_and_url (line 8) | def assert_path_and_url(name, prepend_path = nil)
FILE: test/delegator_test.rb
class DelegatorTest (line 5) | class DelegatorTest < ActiveSupport::TestCase
method delegator (line 6) | def delegator
FILE: test/devise_test.rb
type Devise (line 5) | module Devise
function yield_and_restore (line 6) | def self.yield_and_restore
class DeviseTest (line 15) | class DeviseTest < ActiveSupport::TestCase
FILE: test/failure_app_test.rb
class FailureTest (line 6) | class FailureTest < ActiveSupport::TestCase
class RootFailureApp (line 7) | class RootFailureApp < Devise::FailureApp
method fake_app (line 8) | def fake_app
class FailureWithSubdomain (line 13) | class FailureWithSubdomain < RootFailureApp
class FailureWithI18nOptions (line 25) | class FailureWithI18nOptions < Devise::FailureApp
method i18n_options (line 26) | def i18n_options(options)
class FailureWithoutRootPath (line 31) | class FailureWithoutRootPath < Devise::FailureApp
class FakeURLHelpers (line 32) | class FakeURLHelpers
class FakeRoutesWithoutRoot (line 35) | class FakeRoutesWithoutRoot
method url_helpers (line 36) | def url_helpers
class FakeAppWithoutRootPath (line 41) | class FakeAppWithoutRootPath
method routes (line 42) | def routes
method main_app (line 47) | def main_app
class FakeEngineApp (line 52) | class FakeEngineApp < Devise::FailureApp
class FakeEngine (line 53) | class FakeEngine
method new_user_on_engine_session_url (line 54) | def new_user_on_engine_session_url _
method main_app (line 59) | def main_app
method fake_engine (line 63) | def fake_engine
class RequestWithoutFlashSupport (line 68) | class RequestWithoutFlashSupport < ActionDispatch::Request
method context (line 72) | def self.context(name, &block)
method call_failure (line 76) | def call_failure(env_params = {})
FILE: test/generators/active_record_generator_test.rb
class ActiveRecordGeneratorTest (line 8) | class ActiveRecordGeneratorTest < Rails::Generators::TestCase
type RailsEngine (line 83) | module RailsEngine
class Engine (line 84) | class Engine < Rails::Engine
function simulate_inside_engine (line 89) | def simulate_inside_engine(engine, namespace)
class ActiveRecordEngineGeneratorTest (line 101) | class ActiveRecordEngineGeneratorTest < Rails::Generators::TestCase
FILE: test/generators/controllers_generator_test.rb
class ControllersGeneratorTest (line 5) | class ControllersGeneratorTest < Rails::Generators::TestCase
method assert_class_names (line 40) | def assert_class_names(scope, options = {})
FILE: test/generators/devise_generator_test.rb
class DeviseGeneratorTest (line 7) | class DeviseGeneratorTest < Rails::Generators::TestCase
method copy_routes (line 33) | def copy_routes
FILE: test/generators/install_generator_test.rb
class InstallGeneratorTest (line 5) | class InstallGeneratorTest < Rails::Generators::TestCase
FILE: test/generators/mongoid_generator_test.rb
class MongoidGeneratorTest (line 8) | class MongoidGeneratorTest < Rails::Generators::TestCase
FILE: test/generators/views_generator_test.rb
class ViewsGeneratorTest (line 5) | class ViewsGeneratorTest < Rails::Generators::TestCase
method assert_files (line 80) | def assert_files(scope = nil, options = {})
method assert_shared_links (line 98) | def assert_shared_links(scope = nil)
method assert_error_messages (line 110) | def assert_error_messages(scope = nil)
FILE: test/helpers/devise_helper_test.rb
class DeviseHelperTest (line 5) | class DeviseHelperTest < Devise::IntegrationTest
FILE: test/integration/authenticatable_test.rb
class AuthenticationSanityTest (line 5) | class AuthenticationSanityTest < Devise::IntegrationTest
class AuthenticationRoutesRestrictions (line 145) | class AuthenticationRoutesRestrictions < Devise::IntegrationTest
class AuthenticationRedirectTest (line 265) | class AuthenticationRedirectTest < Devise::IntegrationTest
class AuthenticationSessionTest (line 345) | class AuthenticationSessionTest < Devise::IntegrationTest
class AuthenticationWithScopedViewsTest (line 391) | class AuthenticationWithScopedViewsTest < Devise::IntegrationTest
class AuthenticationOthersTest (line 432) | class AuthenticationOthersTest < Devise::IntegrationTest
class AuthenticationKeysTest (line 562) | class AuthenticationKeysTest < Devise::IntegrationTest
class AuthenticationRequestKeysTest (line 579) | class AuthenticationRequestKeysTest < Devise::IntegrationTest
class AuthenticationSignOutViaTest (line 620) | class AuthenticationSignOutViaTest < Devise::IntegrationTest
method sign_in! (line 621) | def sign_in!(scope)
class DoubleAuthenticationRedirectTest (line 675) | class DoubleAuthenticationRedirectTest < Devise::IntegrationTest
class DoubleSignOutRedirectTest (line 698) | class DoubleSignOutRedirectTest < Devise::IntegrationTest
FILE: test/integration/confirmable_test.rb
class ConfirmationTest (line 5) | class ConfirmationTest < Devise::IntegrationTest
method visit_user_confirmation_with_token (line 7) | def visit_user_confirmation_with_token(confirmation_token)
method resend_confirmation (line 11) | def resend_confirmation
class ConfirmationOnChangeTest (line 285) | class ConfirmationOnChangeTest < Devise::IntegrationTest
method create_second_admin (line 286) | def create_second_admin(options = {})
method visit_admin_confirmation_with_token (line 291) | def visit_admin_confirmation_with_token(confirmation_token)
FILE: test/integration/database_authenticatable_test.rb
class DatabaseAuthenticationTest (line 5) | class DatabaseAuthenticationTest < Devise::IntegrationTest
FILE: test/integration/http_authenticatable_test.rb
class HttpAuthenticationTest (line 5) | class HttpAuthenticationTest < Devise::IntegrationTest
method sign_in_as_new_user_with_http (line 102) | def sign_in_as_new_user_with_http(username = "user@test.com", password...
method add_oauth2_header (line 109) | def add_oauth2_header
FILE: test/integration/lockable_test.rb
class LockTest (line 5) | class LockTest < Devise::IntegrationTest
method visit_user_unlock_with_token (line 7) | def visit_user_unlock_with_token(unlock_token)
method send_unlock_request (line 11) | def send_unlock_request
FILE: test/integration/mounted_engine_test.rb
type MyMountableEngine (line 5) | module MyMountableEngine
class Engine (line 6) | class Engine < ::Rails::Engine
class TestsController (line 9) | class TestsController < ActionController::Base
method index (line 10) | def index
method inner_route (line 13) | def inner_route
class AuthenticatedMountedEngineTest (line 35) | class AuthenticatedMountedEngineTest < Devise::IntegrationTest
FILE: test/integration/omniauthable_test.rb
class OmniauthableIntegrationTest (line 6) | class OmniauthableIntegrationTest < Devise::IntegrationTest
method stub_action! (line 36) | def stub_action!(name)
FILE: test/integration/recoverable_test.rb
class PasswordTest (line 5) | class PasswordTest < Devise::IntegrationTest
method visit_new_password_path (line 7) | def visit_new_password_path
method request_forgot_password (line 12) | def request_forgot_password(&block)
method reset_password (line 24) | def reset_password(options = {}, &block)
FILE: test/integration/registerable_test.rb
class RegistrationTest (line 5) | class RegistrationTest < Devise::IntegrationTest
method user_sign_up (line 46) | def user_sign_up
class ReconfirmableRegistrationTest (line 347) | class ReconfirmableRegistrationTest < Devise::IntegrationTest
FILE: test/integration/rememberable_test.rb
class RememberMeTest (line 5) | class RememberMeTest < Devise::IntegrationTest
method create_user_and_remember (line 6) | def create_user_and_remember(add_to_token = '')
method generate_signed_cookie (line 14) | def generate_signed_cookie(raw_cookie)
method signed_cookie (line 20) | def signed_cookie(key)
method cookie_expires (line 24) | def cookie_expires(key)
FILE: test/integration/timeoutable_test.rb
class SessionTimeoutTest (line 5) | class SessionTimeoutTest < Devise::IntegrationTest
method last_request_at (line 7) | def last_request_at
FILE: test/integration/trackable_test.rb
class TrackableHooksTest (line 5) | class TrackableHooksTest < Devise::IntegrationTest
FILE: test/mailers/confirmation_instructions_test.rb
class ConfirmationInstructionsTest (line 5) | class ConfirmationInstructionsTest < ActionMailer::TestCase
method setup (line 7) | def setup
method teardown (line 13) | def teardown
method user (line 18) | def user
method mail (line 22) | def mail
FILE: test/mailers/email_changed_test.rb
class EmailChangedTest (line 5) | class EmailChangedTest < ActionMailer::TestCase
method setup (line 6) | def setup
method teardown (line 13) | def teardown
method user (line 19) | def user
method mail (line 26) | def mail
class EmailChangedReconfirmationTest (line 94) | class EmailChangedReconfirmationTest < ActionMailer::TestCase
method setup (line 95) | def setup
method teardown (line 102) | def teardown
method admin (line 108) | def admin
method mail (line 115) | def mail
FILE: test/mailers/mailer_test.rb
class MailerTest (line 5) | class MailerTest < ActionMailer::TestCase
class TestMailer (line 7) | class TestMailer < Devise::Mailer
method confirmation_instructions (line 8) | def confirmation_instructions(record, token, opts = {})
class TestMailerWithDefault (line 22) | class TestMailerWithDefault < Devise::Mailer
method confirmation_instructions (line 26) | def confirmation_instructions(record, token, opts = {})
method computed_from (line 33) | def computed_from
method computed_reply_to (line 37) | def computed_reply_to
FILE: test/mailers/reset_password_instructions_test.rb
class ResetPasswordInstructionsTest (line 5) | class ResetPasswordInstructionsTest < ActionMailer::TestCase
method setup (line 6) | def setup
method teardown (line 12) | def teardown
method user (line 17) | def user
method mail (line 25) | def mail
FILE: test/mailers/unlock_instructions_test.rb
class UnlockInstructionsTest (line 5) | class UnlockInstructionsTest < ActionMailer::TestCase
method setup (line 7) | def setup
method teardown (line 13) | def teardown
method user (line 18) | def user
method mail (line 26) | def mail
FILE: test/mapping_test.rb
class FakeRequest (line 5) | class FakeRequest < Struct.new(:path_info, :params)
class MappingTest (line 8) | class MappingTest < ActiveSupport::TestCase
method fake_request (line 9) | def fake_request(path, params = {})
method devise_scope (line 78) | def user.devise_scope; :special_scope; end
FILE: test/models/authenticatable_test.rb
class AuthenticatableTest (line 5) | class AuthenticatableTest < ActiveSupport::TestCase
FILE: test/models/confirmable_test.rb
class ConfirmableTest (line 5) | class ConfirmableTest < ActiveSupport::TestCase
method setup (line 7) | def setup
method confirmation_required? (line 186) | def confirmation_required?; false end
method confirmation_required? (line 288) | def confirmation_required?; false end
method confirmation_required? (line 297) | def confirmation_required?; false end
method confirm_user_by_token_with_confirmation_sent_at (line 321) | def confirm_user_by_token_with_confirmation_sent_at(confirmation_sent_at)
class ReconfirmableTest (line 392) | class ReconfirmableTest < ActiveSupport::TestCase
class Admin::WithSaveInCallback (line 545) | class Admin::WithSaveInCallback < Admin
FILE: test/models/database_authenticatable_test.rb
class DatabaseAuthenticatableTest (line 7) | class DatabaseAuthenticatableTest < ActiveSupport::TestCase
method setup (line 8) | def setup
FILE: test/models/lockable_test.rb
class LockableTest (line 5) | class LockableTest < ActiveSupport::TestCase
method setup (line 6) | def setup
FILE: test/models/omniauthable_test.rb
class OmniauthableTest (line 5) | class OmniauthableTest < ActiveSupport::TestCase
FILE: test/models/recoverable_test.rb
class RecoverableTest (line 5) | class RecoverableTest < ActiveSupport::TestCase
method setup (line 7) | def setup
FILE: test/models/registerable_test.rb
class RegisterableTest (line 5) | class RegisterableTest < ActiveSupport::TestCase
FILE: test/models/rememberable_test.rb
class RememberableTest (line 5) | class RememberableTest < ActiveSupport::TestCase
method resource_class (line 6) | def resource_class
method create_resource (line 10) | def create_resource
method remember_token (line 109) | def user_with_remember_token.remember_token; '123-token'; end
method authenticatable_salt (line 113) | def user_with_salt.authenticatable_salt; '123-salt'; end
method authenticatable_salt (line 119) | def user.authenticatable_salt; nil; end
method authenticatable_salt (line 125) | def user.authenticatable_salt; ""; end
FILE: test/models/serializable_test.rb
class SerializableTest (line 5) | class SerializableTest < ActiveSupport::TestCase
method assert_key (line 34) | def assert_key(key, subject)
method assert_no_key (line 38) | def assert_no_key(key, subject)
method from_json (line 42) | def from_json(options = nil)
FILE: test/models/timeoutable_test.rb
class TimeoutableTest (line 5) | class TimeoutableTest < ActiveSupport::TestCase
method timeout_in (line 21) | def timeout_in; 10.minutes end
method timeout_in (line 29) | def timeout_in; nil end
FILE: test/models/trackable_test.rb
class TrackableTest (line 5) | class TrackableTest < ActiveSupport::TestCase
class UserWithOverride (line 64) | class UserWithOverride < User
method extract_ip_from (line 66) | def extract_ip_from(request)
FILE: test/models/validatable_test.rb
class ValidatableTest (line 6) | class ValidatableTest < ActiveSupport::TestCase
FILE: test/models_test.rb
class ActiveRecordTest (line 6) | class ActiveRecordTest < ActiveSupport::TestCase
method include_module? (line 7) | def include_module?(klass, mod)
method assert_include_modules (line 12) | def assert_include_modules(klass, *modules)
method send_devise_notification (line 90) | def send_devise_notification(*); end
type StubModelFilters (line 97) | module StubModelFilters
function stub_filter (line 98) | def stub_filter(name)
class CheckFieldsTest (line 103) | class CheckFieldsTest < ActiveSupport::TestCase
FILE: test/omniauth/config_test.rb
class OmniAuthConfigTest (line 5) | class OmniAuthConfigTest < ActiveSupport::TestCase
class MyStrategy (line 6) | class MyStrategy
class NamedTestStrategy (line 30) | class NamedTestStrategy
class UnNamedTestStrategy (line 40) | class UnNamedTestStrategy
FILE: test/omniauth/url_helpers_test.rb
class OmniAuthRoutesTest (line 5) | class OmniAuthRoutesTest < ActionController::TestCase
method assert_path (line 8) | def assert_path(action, provider, with_param = true)
FILE: test/orm/active_record.rb
class ActiveSupport::TestCase (line 14) | class ActiveSupport::TestCase
FILE: test/orm/mongoid.rb
class ActiveSupport::TestCase (line 11) | class ActiveSupport::TestCase
FILE: test/parameter_sanitizer_test.rb
class ParameterSanitizerTest (line 6) | class ParameterSanitizerTest < ActiveSupport::TestCase
method sanitizer (line 7) | def sanitizer(params)
FILE: test/rails_app/app/active_record/admin.rb
class Admin (line 5) | class Admin < ActiveRecord::Base
FILE: test/rails_app/app/active_record/shim.rb
type Shim (line 3) | module Shim
FILE: test/rails_app/app/active_record/user.rb
class User (line 5) | class User < ActiveRecord::Base
method after_validation_callback (line 15) | def after_validation_callback
FILE: test/rails_app/app/active_record/user_on_engine.rb
class UserOnEngine (line 5) | class UserOnEngine < ActiveRecord::Base
FILE: test/rails_app/app/active_record/user_on_main_app.rb
class UserOnMainApp (line 5) | class UserOnMainApp < ActiveRecord::Base
FILE: test/rails_app/app/active_record/user_with_validations.rb
class UserWithValidations (line 5) | class UserWithValidations < ActiveRecord::Base
FILE: test/rails_app/app/active_record/user_without_email.rb
class UserWithoutEmail (line 5) | class UserWithoutEmail < ActiveRecord::Base
FILE: test/rails_app/app/controllers/admins/sessions_controller.rb
class Admins::SessionsController (line 3) | class Admins::SessionsController < Devise::SessionsController
method new (line 4) | def new
FILE: test/rails_app/app/controllers/admins_controller.rb
class AdminsController (line 3) | class AdminsController < ApplicationController
method index (line 6) | def index
FILE: test/rails_app/app/controllers/application_controller.rb
class ApplicationController (line 6) | class ApplicationController < ActionController::Base
method set_locale (line 17) | def set_locale
method default_url_options (line 21) | def default_url_options
FILE: test/rails_app/app/controllers/application_with_fake_engine.rb
class ApplicationWithFakeEngine (line 3) | class ApplicationWithFakeEngine < ApplicationController
method fake_engine (line 7) | def fake_engine
class FakeEngine (line 12) | class FakeEngine
method user_on_engine_confirmation_path (line 13) | def user_on_engine_confirmation_path
method new_user_on_engine_session_path (line 17) | def new_user_on_engine_session_path
method new_user_on_engine_registration_path (line 21) | def new_user_on_engine_registration_path
method new_user_on_engine_password_path (line 25) | def new_user_on_engine_password_path
method new_user_on_engine_unlock_path (line 29) | def new_user_on_engine_unlock_path
FILE: test/rails_app/app/controllers/custom/registrations_controller.rb
class Custom::RegistrationsController (line 3) | class Custom::RegistrationsController < Devise::RegistrationsController
method new (line 4) | def new
method create (line 10) | def create
method update (line 16) | def update
method create_block_called? (line 22) | def create_block_called?
method update_block_called? (line 26) | def update_block_called?
method new_block_called? (line 30) | def new_block_called?
FILE: test/rails_app/app/controllers/home_controller.rb
class HomeController (line 3) | class HomeController < ApplicationController
method index (line 4) | def index
method private (line 7) | def private
method user_dashboard (line 10) | def user_dashboard
method admin_dashboard (line 13) | def admin_dashboard
method join (line 16) | def join
method set (line 19) | def set
method unauthenticated (line 24) | def unauthenticated
FILE: test/rails_app/app/controllers/publisher/registrations_controller.rb
class Publisher::RegistrationsController (line 3) | class Publisher::RegistrationsController < ApplicationController
FILE: test/rails_app/app/controllers/publisher/sessions_controller.rb
class Publisher::SessionsController (line 3) | class Publisher::SessionsController < ApplicationController
FILE: test/rails_app/app/controllers/streaming_controller.rb
class StreamingController (line 3) | class StreamingController < ApplicationController
method index (line 8) | def index
FILE: test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController (line 3) | class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksCont...
method facebook (line 4) | def facebook
method sign_in_facebook (line 10) | def sign_in_facebook
FILE: test/rails_app/app/controllers/users_controller.rb
class UsersController (line 3) | class UsersController < ApplicationController
method index (line 9) | def index
method edit_form (line 14) | def edit_form
method update_form (line 18) | def update_form
method accept (line 22) | def accept
method exhibit (line 26) | def exhibit
method expire (line 30) | def expire
FILE: test/rails_app/app/helpers/application_helper.rb
type ApplicationHelper (line 4) | module ApplicationHelper
FILE: test/rails_app/app/mailers/users/from_proc_mailer.rb
class Users::FromProcMailer (line 3) | class Users::FromProcMailer < Devise::Mailer
FILE: test/rails_app/app/mailers/users/mailer.rb
class Users::Mailer (line 3) | class Users::Mailer < Devise::Mailer
FILE: test/rails_app/app/mailers/users/reply_to_mailer.rb
class Users::ReplyToMailer (line 3) | class Users::ReplyToMailer < Devise::Mailer
FILE: test/rails_app/app/mongoid/admin.rb
class Admin (line 5) | class Admin
FILE: test/rails_app/app/mongoid/shim.rb
type Shim (line 3) | module Shim
type ClassMethods (line 11) | module ClassMethods
function order (line 12) | def order(attribute)
function find_by_email (line 16) | def find_by_email(email)
function == (line 22) | def ==(other)
FILE: test/rails_app/app/mongoid/user.rb
class User (line 5) | class User
method after_validation_callback (line 46) | def after_validation_callback
FILE: test/rails_app/app/mongoid/user_on_engine.rb
class UserOnEngine (line 5) | class UserOnEngine
FILE: test/rails_app/app/mongoid/user_on_main_app.rb
class UserOnMainApp (line 5) | class UserOnMainApp
FILE: test/rails_app/app/mongoid/user_with_validations.rb
class UserWithValidations (line 5) | class UserWithValidations
FILE: test/rails_app/app/mongoid/user_without_email.rb
class UserWithoutEmail (line 5) | class UserWithoutEmail
FILE: test/rails_app/config/application.rb
type RailsApp (line 19) | module RailsApp
class Application (line 20) | class Application < Rails::Application
FILE: test/rails_app/config/boot.rb
type Devise (line 7) | module Devise
type Test (line 8) | module Test
function rails71_and_up? (line 11) | def self.rails71_and_up?
function rails70_and_up? (line 15) | def self.rails70_and_up?
function rails70? (line 19) | def self.rails70?
FILE: test/rails_app/db/migrate/20100401102949_create_tables.rb
class CreateTables (line 3) | class CreateTables < ActiveRecord::Migration[5.0]
method up (line 4) | def self.up
method down (line 69) | def self.down
FILE: test/rails_app/lib/lazy_load_test_module.rb
type LazyLoadTestModule (line 1) | module LazyLoadTestModule
function lazy_loading_works? (line 2) | def lazy_loading_works?
FILE: test/rails_app/lib/shared_admin.rb
type SharedAdmin (line 3) | module SharedAdmin
function raw_confirmation_token (line 16) | def raw_confirmation_token
FILE: test/rails_app/lib/shared_user.rb
type SharedUser (line 3) | module SharedUser
function raw_confirmation_token (line 18) | def raw_confirmation_token
type ExtendMethods (line 22) | module ExtendMethods
function new_with_session (line 23) | def new_with_session(params, session)
FILE: test/rails_app/lib/shared_user_without_email.rb
type SharedUserWithoutEmail (line 3) | module SharedUserWithoutEmail
function email_changed? (line 20) | def email_changed?
function respond_to? (line 24) | def respond_to?(method_name, include_all = false)
FILE: test/rails_app/lib/shared_user_without_omniauth.rb
type SharedUserWithoutOmniauth (line 3) | module SharedUserWithoutOmniauth
function raw_confirmation_token (line 12) | def raw_confirmation_token
FILE: test/rails_test.rb
class RailsTest (line 5) | class RailsTest < ActiveSupport::TestCase
FILE: test/routes_test.rb
class DefaultRoutingTest (line 7) | class DefaultRoutingTest < ActionController::TestCase
method assert_named_route (line 115) | def assert_named_route(result, *args)
class CustomizedRoutingTest (line 120) | class CustomizedRoutingTest < ActionController::TestCase
class ScopedRoutingTest (line 266) | class ScopedRoutingTest < ActionController::TestCase
FILE: test/support/action_controller/record_identifier.rb
type ActionController (line 9) | module ActionController
FILE: test/support/assertions.rb
class ActiveSupport::TestCase (line 5) | class ActiveSupport::TestCase
method assert_blank (line 6) | def assert_blank(assertion)
method assert_present (line 10) | def assert_present(assertion)
method assert_email_sent (line 14) | def assert_email_sent(address = nil, &block)
method assert_email_not_sent (line 21) | def assert_email_not_sent(&block)
method assert_raise_with_message (line 25) | def assert_raise_with_message(exception_klass, message, &block)
FILE: test/support/helpers.rb
class ActiveSupport::TestCase (line 5) | class ActiveSupport::TestCase
method setup_mailer (line 6) | def setup_mailer
method store_translations (line 10) | def store_translations(locale, translations, &block)
method generate_unique_email (line 22) | def generate_unique_email
method valid_attributes (line 28) | def valid_attributes(attributes = {})
method new_user (line 35) | def new_user(attributes = {})
method create_user (line 39) | def create_user(attributes = {})
method create_admin (line 43) | def create_admin(attributes = {})
method create_user_without_email (line 49) | def create_user_without_email(attributes = {})
method create_user_with_validations (line 53) | def create_user_with_validations(attributes = {})
method swap (line 59) | def swap(object, new_values)
method swap_model_config (line 74) | def swap_model_config(model, new_values)
method clear_cached_variables (line 85) | def clear_cached_variables(options)
FILE: test/support/http_method_compatibility.rb
type Devise (line 3) | module Devise
class IntegrationTest (line 4) | class IntegrationTest < ActionDispatch::IntegrationTest
class ControllerTestCase (line 7) | class ControllerTestCase < ActionController::TestCase
FILE: test/support/integration.rb
class ActionDispatch::IntegrationTest (line 5) | class ActionDispatch::IntegrationTest
method warden (line 6) | def warden
method create_user (line 10) | def create_user(options = {})
method create_admin (line 27) | def create_admin(options = {})
method sign_in_as_user (line 39) | def sign_in_as_user(options = {}, &block)
method sign_in_as_admin (line 50) | def sign_in_as_admin(options = {}, &block)
method assert_redirected_to (line 63) | def assert_redirected_to(url)
method assert_current_url (line 70) | def assert_current_url(expected)
method assert_url (line 74) | def assert_url(expected, actual)
method visit_with_option (line 80) | def visit_with_option(given, default)
method prepend_host (line 91) | def prepend_host(url)
FILE: test/support/webrat/integrations/rails.rb
type Webrat (line 6) | module Webrat
function parse_rails_request_params (line 8) | def self.parse_rails_request_params(params)
type Logging (line 13) | module Logging
function logger (line 15) | def logger # :nodoc:
class RailsAdapter (line 20) | class RailsAdapter
method response (line 23) | def response
method do_request (line 29) | def do_request(http_method, url, data, headers)
type ActionDispatch (line 36) | module ActionDispatch #:nodoc:
FILE: test/support/webrat/matchers.rb
type Webrat (line 2) | module Webrat
type Matchers (line 3) | module Matchers
class HaveSelector (line 4) | class HaveSelector
method query (line 5) | def query
FILE: test/test/controller_helpers_test.rb
class TestControllerHelpersTest (line 5) | class TestControllerHelpersTest < Devise::ControllerTestCase
method redirect (line 72) | def redirect
method respond (line 85) | def respond
class TestControllerHelpersForStreamingControllerTest (line 195) | class TestControllerHelpersForStreamingControllerTest < Devise::Controll...
FILE: test/test/integration_helpers_test.rb
class TestIntegrationsHelpersTest (line 5) | class TestIntegrationsHelpersTest < Devise::IntegrationTest
FILE: test/test_models.rb
class Configurable (line 3) | class Configurable < User
class WithValidation (line 9) | class WithValidation < Admin
class UserWithValidation (line 13) | class UserWithValidation < User
class UserWithCustomHashing (line 17) | class UserWithCustomHashing < User
method password_digest (line 19) | def password_digest(password)
class UserWithVirtualAttributes (line 24) | class UserWithVirtualAttributes < User
class Several (line 29) | class Several < Admin
class Inheritable (line 34) | class Inheritable < Admin
Condensed preview — 272 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (714K chars).
[
{
"path": ".devcontainer/devcontainer.json",
"chars": 941,
"preview": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the\n// README at: https://github.co"
},
{
"path": ".github/code-scanning.yml",
"chars": 26,
"preview": "paths-ignore:\n - test/**\n"
},
{
"path": ".github/dependabot.yml",
"chars": 118,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"github-actions\"\n directory: \"/\"\n schedule:\n interval: \"weekly\"\n"
},
{
"path": ".github/workflows/test.yml",
"chars": 1989,
"preview": "name: Test\n\npermissions:\n contents: read\non:\n push:\n branches:\n - main\n pull_request:\n workflow_dispatch:\njo"
},
{
"path": ".gitignore",
"chars": 116,
"preview": "test/rails_app/log/*\ntest/rails_app/tmp/*\n*~\ncoverage/*\n*.sqlite3\n.bundle\nrdoc/*\npkg\nlog\ntest/tmp/*\ngemfiles/*.lock\n"
},
{
"path": ".yardopts",
"chars": 108,
"preview": "--protected\n--no-private\n--embed-mixin ClassMethods\n-\nREADME.md\nCHANGELOG.rdoc\nCONTRIBUTING.md\nMIT-LICENSE\n\n"
},
{
"path": "CHANGELOG.md",
"chars": 7118,
"preview": "### 5.0.3 - 2026-03-16\n\n* security fixes\n * Fix race condition vulnerability on confirmable \"change email\" which would "
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 2037,
"preview": "# Contributor Code of Conduct\n\nAs contributors and maintainers of this project, and in the interest of fostering an open"
},
{
"path": "CONTRIBUTING.md",
"chars": 4324,
"preview": "# How to contribute to Devise\n\nThanks for your interest on contributing to Devise! Here are a few general\nguidelines on "
},
{
"path": "Gemfile",
"chars": 536,
"preview": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngemspec\n\ngem \"omniauth\"\ngem \"omniauth-oauth2\"\ngem \"rails\","
},
{
"path": "ISSUE_TEMPLATE.md",
"chars": 645,
"preview": "## Pre-check\n\n- Do not use the issues tracker for help or support, try Stack Overflow.\n- For bugs, do a quick search and"
},
{
"path": "MIT-LICENSE",
"chars": 1128,
"preview": "Copyright (c) 2020-CURRENT Rafael França, Carlos Antonio da Silva\nCopyright (c) 2009-2019 Plataformatec\n\nPermission is h"
},
{
"path": "README.md",
"chars": 34760,
"preview": "\n\nDevise is a flexible authentication solution f"
},
{
"path": "Rakefile",
"chars": 1026,
"preview": "# encoding: UTF-8\n# frozen_string_literal: true\n\nrequire 'bundler/gem_tasks'\nrequire 'rake/testtask'\nrequire 'rdoc/task'"
},
{
"path": "app/controllers/devise/confirmations_controller.rb",
"chars": 1675,
"preview": "# frozen_string_literal: true\n\nclass Devise::ConfirmationsController < DeviseController\n # GET /resource/confirmation/n"
},
{
"path": "app/controllers/devise/omniauth_callbacks_controller.rb",
"chars": 1235,
"preview": "# frozen_string_literal: true\n\nclass Devise::OmniauthCallbacksController < DeviseController\n prepend_before_action { re"
},
{
"path": "app/controllers/devise/passwords_controller.rb",
"chars": 2894,
"preview": "# frozen_string_literal: true\n\nclass Devise::PasswordsController < DeviseController\n prepend_before_action :require_no_"
},
{
"path": "app/controllers/devise/registrations_controller.rb",
"chars": 5613,
"preview": "# frozen_string_literal: true\n\nclass Devise::RegistrationsController < DeviseController\n prepend_before_action :require"
},
{
"path": "app/controllers/devise/sessions_controller.rb",
"chars": 2635,
"preview": "# frozen_string_literal: true\n\nclass Devise::SessionsController < DeviseController\n prepend_before_action :require_no_a"
},
{
"path": "app/controllers/devise/unlocks_controller.rb",
"chars": 1541,
"preview": "# frozen_string_literal: true\n\nclass Devise::UnlocksController < DeviseController\n prepend_before_action :require_no_au"
},
{
"path": "app/controllers/devise_controller.rb",
"chars": 6982,
"preview": "# frozen_string_literal: true\n\n# All Devise controllers are inherited from here.\nclass DeviseController < Devise.parent_"
},
{
"path": "app/helpers/devise_helper.rb",
"chars": 111,
"preview": "# frozen_string_literal: true\n\n# Keeping the helper around for backward compatibility.\nmodule DeviseHelper\nend\n"
},
{
"path": "app/mailers/devise/mailer.rb",
"chars": 804,
"preview": "# frozen_string_literal: true\n\nif defined?(ActionMailer)\n class Devise::Mailer < Devise.parent_mailer.constantize\n i"
},
{
"path": "app/views/devise/confirmations/new.html.erb",
"chars": 595,
"preview": "<h2>Resend confirmation instructions</h2>\n\n<%= form_for(resource, as: resource_name, url: confirmation_path(resource_nam"
},
{
"path": "app/views/devise/mailer/confirmation_instructions.html.erb",
"chars": 198,
"preview": "<p>Welcome <%= @email %>!</p>\n\n<p>You can confirm your account email through the link below:</p>\n\n<p><%= link_to 'Confir"
},
{
"path": "app/views/devise/mailer/email_changed.html.erb",
"chars": 314,
"preview": "<p>Hello <%= @email %>!</p>\n\n<% if @resource.try(:unconfirmed_email?) %>\n <p>We're contacting you to notify you that yo"
},
{
"path": "app/views/devise/mailer/password_change.html.erb",
"chars": 117,
"preview": "<p>Hello <%= @resource.email %>!</p>\n\n<p>We're contacting you to notify you that your password has been changed.</p>\n"
},
{
"path": "app/views/devise/mailer/reset_password_instructions.html.erb",
"chars": 393,
"preview": "<p>Hello <%= @resource.email %>!</p>\n\n<p>Someone has requested a link to change your password. You can do this through t"
},
{
"path": "app/views/devise/mailer/unlock_instructions.html.erb",
"chars": 276,
"preview": "<p>Hello <%= @resource.email %>!</p>\n\n<p>Your account has been locked due to an excessive number of unsuccessful sign in"
},
{
"path": "app/views/devise/passwords/edit.html.erb",
"chars": 873,
"preview": "<h2>Change your password</h2>\n\n<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { meth"
},
{
"path": "app/views/devise/passwords/new.html.erb",
"chars": 494,
"preview": "<h2>Forgot your password?</h2>\n\n<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { met"
},
{
"path": "app/views/devise/registrations/edit.html.erb",
"chars": 1572,
"preview": "<h2>Edit <%= resource_name.to_s.humanize %></h2>\n\n<%= form_for(resource, as: resource_name, url: registration_path(resou"
},
{
"path": "app/views/devise/registrations/new.html.erb",
"chars": 870,
"preview": "<h2>Sign up</h2>\n\n<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>\n <%= rende"
},
{
"path": "app/views/devise/sessions/new.html.erb",
"chars": 677,
"preview": "<h2>Log in</h2>\n\n<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>\n <div class=\"fie"
},
{
"path": "app/views/devise/shared/_error_messages.html.erb",
"chars": 419,
"preview": "<% if resource.errors.any? %>\n <div id=\"error_explanation\" data-turbo-temporary>\n <h2>\n <%= I18n.t(\"errors.mess"
},
{
"path": "app/views/devise/shared/_links.html.erb",
"chars": 1174,
"preview": "<%- if controller_name != 'sessions' %>\n <p><%= link_to \"Log in\", new_session_path(resource_name) %></p>\n<% end %>\n\n<%-"
},
{
"path": "app/views/devise/unlocks/new.html.erb",
"chars": 488,
"preview": "<h2>Resend unlock instructions</h2>\n\n<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { "
},
{
"path": "bin/test",
"chars": 347,
"preview": "#!/usr/bin/env ruby\n$: << File.expand_path(File.expand_path('../../test', __FILE__))\n\nrequire 'bundler/setup'\nrequire 'r"
},
{
"path": "config/locales/en.yml",
"chars": 4283,
"preview": "# Additional translations at https://github.com/heartcombo/devise/wiki/I18n\n\nen:\n devise:\n confirmations:\n conf"
},
{
"path": "devise.gemspec",
"chars": 1423,
"preview": "# -*- encoding: utf-8 -*-\n# frozen_string_literal: true\n\n$:.push File.expand_path(\"../lib\", __FILE__)\nrequire \"devise/ve"
},
{
"path": "gemfiles/Gemfile-rails-7-0",
"chars": 502,
"preview": "source \"https://rubygems.org\"\n\ngemspec path: \"..\"\n\ngem \"rails\", \"~> 7.0.0\"\ngem \"omniauth\"\ngem \"omniauth-oauth2\"\ngem \"rdo"
},
{
"path": "gemfiles/Gemfile-rails-7-1",
"chars": 477,
"preview": "source \"https://rubygems.org\"\n\ngemspec path: \"..\"\n\ngem \"rails\", \"~> 7.1.0\"\ngem \"omniauth\"\ngem \"omniauth-oauth2\"\ngem \"rdo"
},
{
"path": "gemfiles/Gemfile-rails-7-2",
"chars": 483,
"preview": "source \"https://rubygems.org\"\n\ngemspec path: \"..\"\n\ngem \"rails\", \"~> 7.2.0\"\ngem \"omniauth\"\ngem \"omniauth-oauth2\"\ngem \"rdo"
},
{
"path": "gemfiles/Gemfile-rails-8-0",
"chars": 467,
"preview": "source \"https://rubygems.org\"\n\ngemspec path: \"..\"\n\ngem \"rails\", \"~> 8.0.0\"\ngem \"omniauth\"\ngem \"omniauth-oauth2\"\ngem \"rdo"
},
{
"path": "gemfiles/Gemfile-rails-main",
"chars": 554,
"preview": "source \"https://rubygems.org\"\n\ngemspec path: \"..\"\n\ngem \"rails\", github: \"rails/rails\", branch: \"main\"\ngem \"omniauth\"\ngem"
},
{
"path": "guides/bug_report_templates/integration_test.rb",
"chars": 2243,
"preview": "# frozen_string_literal: true\n\nbegin\n require 'bundler/inline'\nrescue LoadError => e\n $stderr.puts 'Bundler version 1."
},
{
"path": "lib/devise/controllers/helpers.rb",
"chars": 11705,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Controllers\n # Those helpers are convenience methods added to A"
},
{
"path": "lib/devise/controllers/rememberable.rb",
"chars": 1956,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Controllers\n # A module that may be optionally included in a co"
},
{
"path": "lib/devise/controllers/responder.rb",
"chars": 1375,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Controllers\n # Custom Responder to configure default statuses t"
},
{
"path": "lib/devise/controllers/scoped_views.rb",
"chars": 368,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Controllers\n module ScopedViews\n extend ActiveSupport::Con"
},
{
"path": "lib/devise/controllers/sign_in_out.rb",
"chars": 4251,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Controllers\n # Provide sign in and sign out functionality.\n "
},
{
"path": "lib/devise/controllers/store_location.rb",
"chars": 2090,
"preview": "# frozen_string_literal: true\n\nrequire \"uri\"\n\nmodule Devise\n module Controllers\n # Provide the ability to store a lo"
},
{
"path": "lib/devise/controllers/url_helpers.rb",
"chars": 2493,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Controllers\n # Create url helpers to be used with resource/scop"
},
{
"path": "lib/devise/delegator.rb",
"chars": 423,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n # Checks the scope in the given environment and returns the associated fa"
},
{
"path": "lib/devise/encryptor.rb",
"chars": 675,
"preview": "# frozen_string_literal: true\n\nrequire 'bcrypt'\n\nmodule Devise\n module Encryptor\n def self.digest(klass, password)\n "
},
{
"path": "lib/devise/failure_app.rb",
"chars": 8619,
"preview": "# frozen_string_literal: true\n\nrequire \"action_controller/metal\"\n\nmodule Devise\n # Failure application that will be cal"
},
{
"path": "lib/devise/hooks/activatable.rb",
"chars": 565,
"preview": "# frozen_string_literal: true\n\n# Deny user access whenever their account is not active yet.\n# We need this as hook to va"
},
{
"path": "lib/devise/hooks/csrf_cleaner.rb",
"chars": 507,
"preview": "# frozen_string_literal: true\n\nWarden::Manager.after_authentication do |record, warden, options|\n clean_up_for_winning_"
},
{
"path": "lib/devise/hooks/forgetable.rb",
"chars": 464,
"preview": "# frozen_string_literal: true\n\n# Before logout hook to forget the user in the given scope, if it responds\n# to forget_me"
},
{
"path": "lib/devise/hooks/lockable.rb",
"chars": 390,
"preview": "# frozen_string_literal: true\n\n# After each sign in, if resource responds to failed_attempts, sets it to 0\n# This is onl"
},
{
"path": "lib/devise/hooks/proxy.rb",
"chars": 486,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Hooks\n # A small warden proxy so we can remember, forget and\n "
},
{
"path": "lib/devise/hooks/rememberable.rb",
"chars": 324,
"preview": "# frozen_string_literal: true\n\nWarden::Manager.after_set_user except: :fetch do |record, warden, options|\n scope = opti"
},
{
"path": "lib/devise/hooks/timeoutable.rb",
"chars": 1375,
"preview": "# frozen_string_literal: true\n\n# Each time a record is set we check whether its session has already timed out\n# or not, "
},
{
"path": "lib/devise/hooks/trackable.rb",
"chars": 541,
"preview": "# frozen_string_literal: true\n\n# After each sign in, update sign in time, sign in count and sign in IP.\n# This is only t"
},
{
"path": "lib/devise/mailers/helpers.rb",
"chars": 2376,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Mailers\n module Helpers\n extend ActiveSupport::Concern\n\n "
},
{
"path": "lib/devise/mapping.rb",
"chars": 5519,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n # Responsible for handling devise mappings and routes configuration. Each"
},
{
"path": "lib/devise/models/authenticatable.rb",
"chars": 12220,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/hooks/activatable'\nrequire 'devise/hooks/csrf_cleaner'\n\nmodule Devise\n m"
},
{
"path": "lib/devise/models/confirmable.rb",
"chars": 16029,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Models\n # Confirmable is responsible to verify if an account is"
},
{
"path": "lib/devise/models/database_authenticatable.rb",
"chars": 7039,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/strategies/database_authenticatable'\n\nmodule Devise\n module Models\n #"
},
{
"path": "lib/devise/models/lockable.rb",
"chars": 7800,
"preview": "# frozen_string_literal: true\n\nrequire \"devise/hooks/lockable\"\n\nmodule Devise\n module Models\n # Handles blocking a u"
},
{
"path": "lib/devise/models/omniauthable.rb",
"chars": 656,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/omniauth'\n\nmodule Devise\n module Models\n # Adds OmniAuth support to y"
},
{
"path": "lib/devise/models/recoverable.rb",
"chars": 6400,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Models\n\n # Recoverable takes care of resetting the user passwor"
},
{
"path": "lib/devise/models/registerable.rb",
"chars": 825,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Models\n # Registerable is responsible for everything related to"
},
{
"path": "lib/devise/models/rememberable.rb",
"chars": 5632,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/strategies/rememberable'\nrequire 'devise/hooks/rememberable'\nrequire 'dev"
},
{
"path": "lib/devise/models/timeoutable.rb",
"chars": 1105,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/hooks/timeoutable'\n\nmodule Devise\n module Models\n # Timeoutable takes"
},
{
"path": "lib/devise/models/trackable.rb",
"chars": 1727,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/hooks/trackable'\n\nmodule Devise\n module Models\n # Track information a"
},
{
"path": "lib/devise/models/validatable.rb",
"chars": 2666,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Models\n # Validatable creates all needed validations for a user"
},
{
"path": "lib/devise/models.rb",
"chars": 3579,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Models\n class MissingAttribute < StandardError\n def initia"
},
{
"path": "lib/devise/modules.rb",
"chars": 1107,
"preview": "# frozen_string_literal: true\n\nrequire 'active_support/core_ext/object/with_options'\n\nDevise.with_options model: true do"
},
{
"path": "lib/devise/omniauth/config.rb",
"chars": 1413,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module OmniAuth\n class StrategyNotFound < NameError\n def initiali"
},
{
"path": "lib/devise/omniauth/url_helpers.rb",
"chars": 1030,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module OmniAuth\n module UrlHelpers\n def omniauth_authorize_path(r"
},
{
"path": "lib/devise/omniauth.rb",
"chars": 883,
"preview": "# frozen_string_literal: true\n\nbegin\n gem \"omniauth\", \">= 1.0.0\"\n\n require \"omniauth\"\nrescue LoadError\n warn \"Could n"
},
{
"path": "lib/devise/orm/active_record.rb",
"chars": 146,
"preview": "# frozen_string_literal: true\n\nrequire 'orm_adapter/adapters/active_record'\n\nActiveSupport.on_load(:active_record) do\n "
},
{
"path": "lib/devise/orm/mongoid.rb",
"chars": 176,
"preview": "# frozen_string_literal: true\n\nActiveSupport.on_load(:mongoid) do\n require 'orm_adapter/adapters/mongoid'\n\n Mongoid::D"
},
{
"path": "lib/devise/orm.rb",
"chars": 2286,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Orm # :nodoc:\n def self.active_record?(model)\n defined?(Ac"
},
{
"path": "lib/devise/parameter_filter.rb",
"chars": 1272,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n class ParameterFilter\n def initialize(case_insensitive_keys, strip_whi"
},
{
"path": "lib/devise/parameter_sanitizer.rb",
"chars": 5606,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n # The +ParameterSanitizer+ deals with permitting specific parameters valu"
},
{
"path": "lib/devise/rails/routes.rb",
"chars": 20127,
"preview": "# frozen_string_literal: true\n\nrequire \"active_support/core_ext/object/try\"\nrequire \"active_support/core_ext/hash/slice\""
},
{
"path": "lib/devise/rails/warden_compat.rb",
"chars": 233,
"preview": "# frozen_string_literal: true\n\nmodule Warden::Mixins::Common\n def request\n @request ||= ActionDispatch::Request.new("
},
{
"path": "lib/devise/rails.rb",
"chars": 1698,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/rails/routes'\nrequire 'devise/rails/warden_compat'\n\nmodule Devise\n class"
},
{
"path": "lib/devise/strategies/authenticatable.rb",
"chars": 6241,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/strategies/base'\n\nmodule Devise\n module Strategies\n # This strategy s"
},
{
"path": "lib/devise/strategies/base.rb",
"chars": 638,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Strategies\n # Base strategy for Devise. Responsible for verifyi"
},
{
"path": "lib/devise/strategies/database_authenticatable.rb",
"chars": 1234,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/strategies/authenticatable'\n\nmodule Devise\n module Strategies\n # Defa"
},
{
"path": "lib/devise/strategies/rememberable.rb",
"chars": 1973,
"preview": "# frozen_string_literal: true\n\nrequire 'devise/strategies/authenticatable'\n\nmodule Devise\n module Strategies\n # Reme"
},
{
"path": "lib/devise/test/controller_helpers.rb",
"chars": 5312,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Test\n # `Devise::Test::ControllerHelpers` provides a facility t"
},
{
"path": "lib/devise/test/integration_helpers.rb",
"chars": 1733,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n # Devise::Test::IntegrationHelpers is a helper module for facilitating\n "
},
{
"path": "lib/devise/time_inflector.rb",
"chars": 299,
"preview": "# frozen_string_literal: true\n\nrequire \"active_support/core_ext/module/delegation\"\n\nmodule Devise\n class TimeInflector\n"
},
{
"path": "lib/devise/token_generator.rb",
"chars": 716,
"preview": "# frozen_string_literal: true\n\nrequire 'openssl'\n\nmodule Devise\n class TokenGenerator\n def initialize(key_generator,"
},
{
"path": "lib/devise/version.rb",
"chars": 76,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n VERSION = \"5.0.3\".freeze\nend\n"
},
{
"path": "lib/devise.rb",
"chars": 17661,
"preview": "# frozen_string_literal: true\n\nrequire 'rails'\nrequire 'active_support/core_ext/numeric/time'\nrequire 'active_support/de"
},
{
"path": "lib/generators/active_record/devise_generator.rb",
"chars": 3726,
"preview": "# frozen_string_literal: true\n\nrequire 'rails/generators/active_record'\nrequire 'generators/devise/orm_helpers'\n\nmodule "
},
{
"path": "lib/generators/active_record/templates/migration.rb",
"chars": 666,
"preview": "# frozen_string_literal: true\n\nclass DeviseCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_versi"
},
{
"path": "lib/generators/active_record/templates/migration_existing.rb",
"chars": 998,
"preview": "# frozen_string_literal: true\n\nclass AddDeviseTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_versio"
},
{
"path": "lib/generators/devise/controllers_generator.rb",
"chars": 1579,
"preview": "# frozen_string_literal: true\n\nrequire 'rails/generators/base'\n\nmodule Devise\n module Generators\n class ControllersG"
},
{
"path": "lib/generators/devise/devise_generator.rb",
"chars": 869,
"preview": "# frozen_string_literal: true\n\nrequire 'rails/generators/named_base'\n\nmodule Devise\n module Generators\n class Devise"
},
{
"path": "lib/generators/devise/install_generator.rb",
"chars": 1137,
"preview": "# frozen_string_literal: true\n\nrequire 'rails/generators/base'\nrequire 'securerandom'\n\nmodule Devise\n module Generators"
},
{
"path": "lib/generators/devise/orm_helpers.rb",
"chars": 877,
"preview": "# frozen_string_literal: true\n\nmodule Devise\n module Generators\n module OrmHelpers\n def model_contents\n "
},
{
"path": "lib/generators/devise/views_generator.rb",
"chars": 4491,
"preview": "# frozen_string_literal: true\n\nrequire 'rails/generators/base'\n\nmodule Devise\n module Generators\n # Include this mod"
},
{
"path": "lib/generators/mongoid/devise_generator.rb",
"chars": 1748,
"preview": "# frozen_string_literal: true\n\nrequire 'rails/generators/named_base'\nrequire 'generators/devise/orm_helpers'\n\nmodule Mon"
},
{
"path": "lib/generators/templates/README",
"chars": 1210,
"preview": "===============================================================================\n\nDepending on your application's configu"
},
{
"path": "lib/generators/templates/controllers/README",
"chars": 440,
"preview": "===============================================================================\n\nSome setup you must do manually if you "
},
{
"path": "lib/generators/templates/controllers/confirmations_controller.rb",
"chars": 676,
"preview": "# frozen_string_literal: true\n\nclass <%= @scope_prefix %>ConfirmationsController < Devise::ConfirmationsController\n # G"
},
{
"path": "lib/generators/templates/controllers/omniauth_callbacks_controller.rb",
"chars": 680,
"preview": "# frozen_string_literal: true\n\nclass <%= @scope_prefix %>OmniauthCallbacksController < Devise::OmniauthCallbacksControll"
},
{
"path": "lib/generators/templates/controllers/passwords_controller.rb",
"chars": 663,
"preview": "# frozen_string_literal: true\n\nclass <%= @scope_prefix %>PasswordsController < Devise::PasswordsController\n # GET /reso"
},
{
"path": "lib/generators/templates/controllers/registrations_controller.rb",
"chars": 1450,
"preview": "# frozen_string_literal: true\n\nclass <%= @scope_prefix %>RegistrationsController < Devise::RegistrationsController\n # b"
},
{
"path": "lib/generators/templates/controllers/sessions_controller.rb",
"chars": 556,
"preview": "# frozen_string_literal: true\n\nclass <%= @scope_prefix %>SessionsController < Devise::SessionsController\n # before_acti"
},
{
"path": "lib/generators/templates/controllers/unlocks_controller.rb",
"chars": 595,
"preview": "# frozen_string_literal: true\n\nclass <%= @scope_prefix %>UnlocksController < Devise::UnlocksController\n # GET /resource"
},
{
"path": "lib/generators/templates/devise.rb",
"chars": 15538,
"preview": "# frozen_string_literal: true\n\n# Assuming you have not yet modified this file, each configuration option below\n# is set "
},
{
"path": "lib/generators/templates/markerb/confirmation_instructions.markerb",
"chars": 163,
"preview": "Welcome <%= @email %>!\n\nYou can confirm your account through the link below:\n\n[Confirm my account](<%= confirmation_url("
},
{
"path": "lib/generators/templates/markerb/email_changed.markerb",
"chars": 289,
"preview": "Hello <%= @email %>!\n\n<% if @resource.try(:unconfirmed_email?) %>\nWe're contacting you to notify you that your email is "
},
{
"path": "lib/generators/templates/markerb/password_change.markerb",
"chars": 103,
"preview": "Hello <%= @resource.email %>!\n\nWe're contacting you to notify you that your password has been changed.\n"
},
{
"path": "lib/generators/templates/markerb/reset_password_instructions.markerb",
"chars": 354,
"preview": "Hello <%= @resource.email %>!\n\nSomeone has requested a link to change your password, and you can do this through the lin"
},
{
"path": "lib/generators/templates/markerb/unlock_instructions.markerb",
"chars": 240,
"preview": "Hello <%= @resource.email %>!\n\nYour account has been locked due to an excessive number of unsuccessful sign in attempts."
},
{
"path": "lib/generators/templates/simple_form_for/confirmations/new.html.erb",
"chars": 677,
"preview": "<h2>Resend confirmation instructions</h2>\n\n<%= simple_form_for(resource, as: resource_name, url: confirmation_path(resou"
},
{
"path": "lib/generators/templates/simple_form_for/passwords/edit.html.erb",
"chars": 935,
"preview": "<h2>Change your password</h2>\n\n<%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html:"
},
{
"path": "lib/generators/templates/simple_form_for/passwords/new.html.erb",
"chars": 518,
"preview": "<h2>Forgot your password?</h2>\n\n<%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html"
},
{
"path": "lib/generators/templates/simple_form_for/registrations/edit.html.erb",
"chars": 1343,
"preview": "<h2>Edit <%= resource_name.to_s.humanize %></h2>\n\n<%= simple_form_for(resource, as: resource_name, url: registration_pat"
},
{
"path": "lib/generators/templates/simple_form_for/registrations/new.html.erb",
"chars": 815,
"preview": "<h2>Sign up</h2>\n\n<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>\n <%"
},
{
"path": "lib/generators/templates/simple_form_for/sessions/new.html.erb",
"chars": 624,
"preview": "<h2>Log in</h2>\n\n<%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>\n <div cla"
},
{
"path": "lib/generators/templates/simple_form_for/unlocks/new.html.erb",
"chars": 548,
"preview": "<h2>Resend unlock instructions</h2>\n\n<%= simple_form_for(resource, as: resource_name, url: unlock_path(resource_name), h"
},
{
"path": "test/controllers/custom_registrations_controller_test.rb",
"chars": 1499,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass CustomRegistrationsControllerTest < Devise::ControllerTestCa"
},
{
"path": "test/controllers/custom_strategy_test.rb",
"chars": 1885,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\nrequire 'ostruct'\nrequire 'warden/strategies/base'\nrequire 'devise/"
},
{
"path": "test/controllers/helper_methods_test.rb",
"chars": 636,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass ApiController < ActionController::Metal\n include Devise::Co"
},
{
"path": "test/controllers/helpers_test.rb",
"chars": 12828,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\nrequire 'ostruct'\n\nclass ControllerAuthenticatableTest < Devise::Co"
},
{
"path": "test/controllers/inherited_controller_i18n_messages_test.rb",
"chars": 1318,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass SessionsInheritedController < Devise::SessionsController\n d"
},
{
"path": "test/controllers/internal_helpers_test.rb",
"chars": 4738,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass MyController < DeviseController\nend\n\nclass HelpersTest < Dev"
},
{
"path": "test/controllers/load_hooks_controller_test.rb",
"chars": 537,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass LoadHooksControllerTest < Devise::ControllerTestCase\n setup"
},
{
"path": "test/controllers/passwords_controller_test.rb",
"chars": 1250,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass PasswordsControllerTest < Devise::ControllerTestCase\n tests"
},
{
"path": "test/controllers/sessions_controller_test.rb",
"chars": 3339,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass SessionsControllerTest < Devise::ControllerTestCase\n tests "
},
{
"path": "test/controllers/url_helpers_test.rb",
"chars": 2401,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass RoutesTest < Devise::ControllerTestCase\n tests ApplicationC"
},
{
"path": "test/delegator_test.rb",
"chars": 661,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass DelegatorTest < ActiveSupport::TestCase\n def delegator\n "
},
{
"path": "test/devise_test.rb",
"chars": 3507,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nmodule Devise\n def self.yield_and_restore\n @@warden_configured"
},
{
"path": "test/failure_app_test.rb",
"chars": 18642,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\nrequire 'ostruct'\n\nclass FailureTest < ActiveSupport::TestCase\n cl"
},
{
"path": "test/generators/active_record_generator_test.rb",
"chars": 4206,
"preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nif DEVISE_ORM == :active_record\n require \"generators/active_recor"
},
{
"path": "test/generators/controllers_generator_test.rb",
"chars": 1912,
"preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nclass ControllersGeneratorTest < Rails::Generators::TestCase\n tes"
},
{
"path": "test/generators/devise_generator_test.rb",
"chars": 1123,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nrequire \"generators/devise/devise_generator\"\n\nclass DeviseGenerato"
},
{
"path": "test/generators/install_generator_test.rb",
"chars": 1055,
"preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nclass InstallGeneratorTest < Rails::Generators::TestCase\n tests D"
},
{
"path": "test/generators/mongoid_generator_test.rb",
"chars": 653,
"preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nif DEVISE_ORM == :mongoid\n require \"generators/mongoid/devise_gen"
},
{
"path": "test/generators/views_generator_test.rb",
"chars": 4892,
"preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nclass ViewsGeneratorTest < Rails::Generators::TestCase\n tests Dev"
},
{
"path": "test/helpers/devise_helper_test.rb",
"chars": 1311,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass DeviseHelperTest < Devise::IntegrationTest\n setup do\n mo"
},
{
"path": "test/integration/authenticatable_test.rb",
"chars": 21739,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass AuthenticationSanityTest < Devise::IntegrationTest\n test 's"
},
{
"path": "test/integration/confirmable_test.rb",
"chars": 14951,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass ConfirmationTest < Devise::IntegrationTest\n\n def visit_user"
},
{
"path": "test/integration/database_authenticatable_test.rb",
"chars": 3282,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass DatabaseAuthenticationTest < Devise::IntegrationTest\n test "
},
{
"path": "test/integration/http_authenticatable_test.rb",
"chars": 4124,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass HttpAuthenticationTest < Devise::IntegrationTest\n test 'sig"
},
{
"path": "test/integration/lockable_test.rb",
"chars": 7647,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass LockTest < Devise::IntegrationTest\n\n def visit_user_unlock_"
},
{
"path": "test/integration/mounted_engine_test.rb",
"chars": 1780,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nmodule MyMountableEngine\n class Engine < ::Rails::Engine\n isol"
},
{
"path": "test/integration/omniauthable_test.rb",
"chars": 5403,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\n\nclass OmniauthableIntegrationTest < Devise::IntegrationTest\n FAC"
},
{
"path": "test/integration/recoverable_test.rb",
"chars": 13410,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass PasswordTest < Devise::IntegrationTest\n\n def visit_new_pass"
},
{
"path": "test/integration/registerable_test.rb",
"chars": 14490,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass RegistrationTest < Devise::IntegrationTest\n\n test 'a guest "
},
{
"path": "test/integration/rememberable_test.rb",
"chars": 6466,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass RememberMeTest < Devise::IntegrationTest\n def create_user_a"
},
{
"path": "test/integration/timeoutable_test.rb",
"chars": 5252,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass SessionTimeoutTest < Devise::IntegrationTest\n\n def last_req"
},
{
"path": "test/integration/trackable_test.rb",
"chars": 2553,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass TrackableHooksTest < Devise::IntegrationTest\n test \"trackab"
},
{
"path": "test/mailers/confirmation_instructions_test.rb",
"chars": 3245,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass ConfirmationInstructionsTest < ActionMailer::TestCase\n\n def"
},
{
"path": "test/mailers/email_changed_test.rb",
"chars": 3511,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass EmailChangedTest < ActionMailer::TestCase\n def setup\n se"
},
{
"path": "test/mailers/mailer_test.rb",
"chars": 1301,
"preview": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nclass MailerTest < ActionMailer::TestCase\n test \"pass given block"
},
{
"path": "test/mailers/reset_password_instructions_test.rb",
"chars": 2742,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass ResetPasswordInstructionsTest < ActionMailer::TestCase\n def"
},
{
"path": "test/mailers/unlock_instructions_test.rb",
"chars": 2478,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass UnlockInstructionsTest < ActionMailer::TestCase\n\n def setup"
},
{
"path": "test/mapping_test.rb",
"chars": 4762,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass FakeRequest < Struct.new(:path_info, :params)\nend\n\nclass Map"
},
{
"path": "test/models/authenticatable_test.rb",
"chars": 2262,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass AuthenticatableTest < ActiveSupport::TestCase\n test 'requir"
},
{
"path": "test/models/confirmable_test.rb",
"chars": 19372,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass ConfirmableTest < ActiveSupport::TestCase\n\n def setup\n s"
},
{
"path": "test/models/database_authenticatable_test.rb",
"chars": 11113,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\nrequire 'test_models'\nrequire 'digest/sha1'\n\nclass DatabaseAuthenti"
},
{
"path": "test/models/lockable_test.rb",
"chars": 12400,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass LockableTest < ActiveSupport::TestCase\n def setup\n setup"
},
{
"path": "test/models/omniauthable_test.rb",
"chars": 256,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass OmniauthableTest < ActiveSupport::TestCase\n test 'required_"
},
{
"path": "test/models/recoverable_test.rb",
"chars": 8978,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass RecoverableTest < ActiveSupport::TestCase\n\n def setup\n s"
},
{
"path": "test/models/registerable_test.rb",
"chars": 256,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass RegisterableTest < ActiveSupport::TestCase\n test 'required_"
},
{
"path": "test/models/rememberable_test.rb",
"chars": 5739,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass RememberableTest < ActiveSupport::TestCase\n def resource_cl"
},
{
"path": "test/models/serializable_test.rb",
"chars": 1447,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass SerializableTest < ActiveSupport::TestCase\n setup do\n @u"
},
{
"path": "test/models/timeoutable_test.rb",
"chars": 1482,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass TimeoutableTest < ActiveSupport::TestCase\n\n test 'should be"
},
{
"path": "test/models/trackable_test.rb",
"chars": 2201,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass TrackableTest < ActiveSupport::TestCase\n test 'required_fie"
},
{
"path": "test/models/validatable_test.rb",
"chars": 4157,
"preview": "# encoding: UTF-8\n# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass ValidatableTest < ActiveSupport::TestCase\n"
},
{
"path": "test/models_test.rb",
"chars": 4781,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\nrequire 'test_models'\n\nclass ActiveRecordTest < ActiveSupport::Test"
},
{
"path": "test/omniauth/config_test.rb",
"chars": 1890,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass OmniAuthConfigTest < ActiveSupport::TestCase\n class MyStrat"
},
{
"path": "test/omniauth/url_helpers_test.rb",
"chars": 1807,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\n\nclass OmniAuthRoutesTest < ActionController::TestCase\n tests Appl"
},
{
"path": "test/orm/active_record.rb",
"chars": 541,
"preview": "# frozen_string_literal: true\n\nActiveRecord::Migration.verbose = false\nActiveRecord::Base.logger = Logger.new(nil)\nActiv"
},
{
"path": "test/orm/mongoid.rb",
"chars": 275,
"preview": "# frozen_string_literal: true\n\nrequire 'mongoid/version'\n\nMongoid.configure do |config|\n config.load!('test/support/mon"
},
{
"path": "test/parameter_sanitizer_test.rb",
"chars": 3248,
"preview": "# frozen_string_literal: true\n\nrequire 'test_helper'\nrequire 'devise/parameter_sanitizer'\n\nclass ParameterSanitizerTest "
},
{
"path": "test/rails_app/Rakefile",
"chars": 249,
"preview": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they wil"
},
{
"path": "test/rails_app/app/active_record/admin.rb",
"chars": 129,
"preview": "# frozen_string_literal: true\n\nrequire 'shared_admin'\n\nclass Admin < ActiveRecord::Base\n include Shim\n include SharedA"
},
{
"path": "test/rails_app/app/active_record/shim.rb",
"chars": 47,
"preview": "# frozen_string_literal: true\n\nmodule Shim\nend\n"
},
{
"path": "test/rails_app/app/active_record/user.rb",
"chars": 395,
"preview": "# frozen_string_literal: true\n\nrequire 'shared_user'\n\nclass User < ActiveRecord::Base\n include Shim\n include SharedUse"
},
{
"path": "test/rails_app/app/active_record/user_on_engine.rb",
"chars": 194,
"preview": "# frozen_string_literal: true\n\nrequire 'shared_user_without_omniauth'\n\nclass UserOnEngine < ActiveRecord::Base\n self.ta"
},
{
"path": "test/rails_app/app/active_record/user_on_main_app.rb",
"chars": 195,
"preview": "# frozen_string_literal: true\n\nrequire 'shared_user_without_omniauth'\n\nclass UserOnMainApp < ActiveRecord::Base\n self.t"
},
{
"path": "test/rails_app/app/active_record/user_with_validations.rb",
"chars": 206,
"preview": "# frozen_string_literal: true\n\nrequire 'shared_user'\n\nclass UserWithValidations < ActiveRecord::Base\n self.table_name ="
},
{
"path": "test/rails_app/app/active_record/user_without_email.rb",
"chars": 193,
"preview": "# frozen_string_literal: true\n\nrequire \"shared_user_without_email\"\n\nclass UserWithoutEmail < ActiveRecord::Base\n self.t"
},
{
"path": "test/rails_app/app/controllers/admins/sessions_controller.rb",
"chars": 197,
"preview": "# frozen_string_literal: true\n\nclass Admins::SessionsController < Devise::SessionsController\n def new\n flash[:specia"
},
{
"path": "test/rails_app/app/controllers/admins_controller.rb",
"chars": 138,
"preview": "# frozen_string_literal: true\n\nclass AdminsController < ApplicationController\n before_action :authenticate_admin!\n\n de"
},
{
"path": "test/rails_app/app/controllers/application_controller.rb",
"chars": 683,
"preview": "# frozen_string_literal: true\n\n# Filters added to this controller apply to all controllers in the application.\n# Likewis"
},
{
"path": "test/rails_app/app/controllers/application_with_fake_engine.rb",
"chars": 624,
"preview": "# frozen_string_literal: true\n\nclass ApplicationWithFakeEngine < ApplicationController\n private\n\n helper_method :fake_"
},
{
"path": "test/rails_app/app/controllers/custom/registrations_controller.rb",
"chars": 553,
"preview": "# frozen_string_literal: true\n\nclass Custom::RegistrationsController < Devise::RegistrationsController\n def new\n sup"
},
{
"path": "test/rails_app/app/controllers/home_controller.rb",
"chars": 355,
"preview": "# frozen_string_literal: true\n\nclass HomeController < ApplicationController\n def index\n end\n\n def private\n end\n\n de"
}
]
// ... and 72 more files (download for full content)
About this extraction
This page contains the full source code of the heartcombo/devise GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 272 files (656.7 KB), approximately 168.8k tokens, and a symbol index with 1041 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.