Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract model callbacks #525

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ test/dummy/.sass-cache
test/dummy/config/application.yml
coverage
.idea
.irb_history
.ruby-version
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ The following settings are available for configuration in `config/initializers/d
| **`redirect_whitelist`** | `nil` | As an added security measure, you can limit the URLs to which the API will redirect after email token validation (password reset, email confirmation, etc.). This value should be an array containing exact matches to the client URLs to be visited after validation. |
| **`enable_standard_devise_support`** | `false` | By default, only Bearer Token authentication is implemented out of the box. If, however, you wish to integrate with legacy Devise authentication, you can do so by enabling this flag. NOTE: This feature is highly experimental! |
| **`remove_tokens_after_password_reset`** | `false` | By default, old tokens are not invalidated when password is changed. Enable this option if you want to make passwords updates to logout other devices. |
| **`default_callbacks`** | `true` | By default User model will include the `DeviseTokenAuth::Concerns::UserOmniauthCallbacks` concern, which has `email`, `uid` validations & `uid` synchronization callbacks. |


Additionally, you can configure other aspects of devise by manually creating the traditional devise.rb file at `config/initializers/devise.rb`. Here are some examples of what you can do in this file:
Expand Down
23 changes: 3 additions & 20 deletions app/models/devise_token_auth/concerns/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,14 @@ def self.tokens_match?(token_hash, token)
serialize :tokens, JSON
end

validates :email, presence: true, email: true, if: Proc.new { |u| u.provider == 'email' }
validates_presence_of :uid, if: Proc.new { |u| u.provider != 'email' }

# only validate unique emails among email registration users
validate :unique_email_user, on: :create
if DeviseTokenAuth.default_callbacks
include DeviseTokenAuth::Concerns::UserOmniauthCallbacks
end

# can't set default on text fields in mysql, simulate here instead.
after_save :set_empty_token_hash
after_initialize :set_empty_token_hash

# keep uid in sync with email
before_save :sync_uid
before_create :sync_uid

# get rid of dead tokens
before_save :destroy_expired_tokens

Expand Down Expand Up @@ -239,21 +233,10 @@ def token_validation_response

protected

# only validate unique email among users that registered by email
def unique_email_user
if provider == 'email' and self.class.where(provider: 'email', email: email).count > 0
errors.add(:email, I18n.t("errors.messages.already_in_use"))
end
end

def set_empty_token_hash
self.tokens ||= {} if has_attribute?(:tokens)
end

def sync_uid
self.uid = email if provider == 'email'
end

def destroy_expired_tokens
if self.tokens
self.tokens.delete_if do |cid, v|
Expand Down
28 changes: 28 additions & 0 deletions app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module DeviseTokenAuth::Concerns::UserOmniauthCallbacks
extend ActiveSupport::Concern

included do
validates :email, presence: true, email: true, if: Proc.new { |u| u.provider == 'email' }
validates_presence_of :uid, if: Proc.new { |u| u.provider != 'email' }

# only validate unique emails among email registration users
validate :unique_email_user, on: :create

# keep uid in sync with email
before_save :sync_uid
before_create :sync_uid
end

protected

# only validate unique email among users that registered by email
def unique_email_user
if provider == 'email' and self.class.where(provider: 'email', email: email).count > 0
errors.add(:email, I18n.t("errors.messages.already_in_use"))
end
end

def sync_uid
self.uid = email if provider == 'email'
end
end
4 changes: 3 additions & 1 deletion lib/devise_token_auth/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class Engine < ::Rails::Engine
:redirect_whitelist,
:check_current_password_before_update,
:enable_standard_devise_support,
:remove_tokens_after_password_reset
:remove_tokens_after_password_reset,
:default_callbacks

self.change_headers_on_each_request = true
self.max_number_of_devices = 10
Expand All @@ -32,6 +33,7 @@ class Engine < ::Rails::Engine
self.check_current_password_before_update = false
self.enable_standard_devise_support = false
self.remove_tokens_after_password_reset = false
self.default_callbacks = true

def self.setup(&block)
yield self
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
# password is updated.
# config.check_current_password_before_update = :attributes

# By default we will use callbacks for single omniauth.
# It depends on fields like email, provider and uid.
# config.default_callbacks = true

# By default, only Bearer Token authentication is implemented out of the box.
# If, however, you wish to integrate with legacy Devise authentication, you can
# do so by enabling this flag. NOTE: This feature is highly experimental!
Expand Down