rails 4 devise confirmation form allows blank emails -
devise version: 3.4.0
i have noticed odd issue devise configuration confirmations controller allows blank emails in create method:
def create self.resource = resource_class.send_confirmation_instructions(resource_params) yield resource if block_given? if successfully_sent?(resource) puts "4 = successfully_sent" binding.pry respond_with({}, location: :user_verification_sent) # respond_with resource, location: :user_verification_sent else puts "3 = error" binding.pry respond_with(resource) end end i should note overriding default setups devise , controller linked:
class users::confirmationscontroller < devise::confirmationscontroller before_filter :set_registration_current_step the confirmation form looks like:
= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { id: "confirm-frm" }) |f| div[class="row"] div[class="large-12 columns"] = f.email_field(:email, html_options = { class: "large text-field", id: "confirm-email", \ autocomplete: "off", autocorrect: "off", autocapitalize: "off", spellcheck: "false", \ maxlength: "100", placeholder: "email address", autofocus: true}) div[class="row"] div[class="large-12 large-centered columns"] a[href="#" id="confirm-btn" class="button button-flat-grey text-emphasis expand"] |resend confirmation i[class="fa fa-arrow-circle-right"] my routes:
scope '/account' # confirmation after business relationship created '/verification', to: 'users/confirmations#verification_sent', as: 'user_verification_sent' # verify user's token emailed them '/confirm', to: 'users/confirmations#show', as: 'user_confirmation' '/confirm/resend', to: 'users/confirmations#new', as: 'new_user_confirmation' post '/confirm', to: 'users/confirmations#create' end and here pry snapshot of showing true:
before manually check email param, prepare this, seems odd devise allows occur. crazy fellow rubyists?
update_1
i should note, if dump resource_class resource_class.send_confirmation_instructions(resource_params) get:
=> #<user id: nil, agreed_to_terms: false, date_of_birth: nil, first_name: nil, last_name: nil, username: nil, email: nil, encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: nil, updated_at: nil> this occurs when user tries request confirmation not come in email address. db can empty.
update_2
when started dissecting gem, think found occurring....
260: def send_confirmation_instructions(attributes={}) 261: => 262: binding.pry 263: 264: 265: 266: confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable 267: unless confirmable.try(:persisted?) 268: confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found) 269: end 270: confirmable.resend_confirmation_instructions if confirmable.persisted? 271: confirmable 272: end [1] pry(user)> find_by_unconfirmed_email_with_errors(attributes) => #<user id: nil, agreed_to_terms: false, date_of_birth: nil, first_name: nil, last_name: nil, username: nil, email: nil, encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: nil, updated_at: nil> [2] pry(user)> if reconfirmable [2] pry(user)* puts true [2] pry(user)* end true => nil [3] pry(user)> confirmable = find_by_unconfirmed_email_with_errors(attributes) if reconfirmable => #<user id: nil, agreed_to_terms: false, date_of_birth: nil, first_name: nil, last_name: nil, username: nil, email: nil, encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: nil, updated_at: nil> [4] pry(user)> confirmable.try(:persisted?) => false [5] pry(user)> unless confirmable.try(:persisted?) [5] pry(user)* puts "go [5] pry(user)* " [5] pry(user)* end go => nil [6] pry(user)> find_or_initialize_with_errors(confirmation_keys, attributes, :not_found) => #<user id: nil, agreed_to_terms: false, date_of_birth: nil, first_name: nil, last_name: nil, username: nil, email: nil, encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: nil, updated_at: nil> [7] pry(user)> confirmable.persisted? => false [8] pry(user)> update_3
so if create user record looks like:
[3] pry(main)> user.all 2014-10-26 15:48:42.161 [debug]::: user load (0.6ms) select "users".* "users" (pid:4440) => [#<user id: 2, agreed_to_terms: true, date_of_birth: "1994-03-02", first_name: "testfirst", last_name: "testlast", username: "testuser", email: "test@gmail.com", encrypted_password: "$2a$10$zu7wi3gc55wc3lnrzatctetp4rwcpernlhwtdc0rggd...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: "3574edb740c64d826b6da4a8f1365a1b753f6b483e10817282...", confirmed_at: nil, confirmation_sent_at: "2014-10-26 22:48:34", unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: "2014-10-26 22:48:34", updated_at: "2014-10-26 22:48:34">] and digging gem, has required attributes , find_or_initialize_with_errors method. still tracking.... not sure here..
update_4
here current user model code , using gem 'validates_email_format_of':
class user < activerecord::base attr_accessor :email_confirmation, :password_confirmation devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable #:timeoutable :=> should not utilize rememberable , timeoutable validates :username, :date_of_birth, :first_name, :last_name, :agreed_to_terms, :email_confirmation, :password_confirmation, presence: true validates :email, allow_nil: false, allow_blank: false, uniqueness: { case_sensitive: false }, email_format: { check_mx: true } validates :username, uniqueness: { case_sensitive: false }, length: { minimum: 5 } validates_confirmation_of :email validates_date :date_of_birth, before: lambda { 18.years.ago } end update_5
# utilize hook configure devise mailer, warden hooks , forth. # many of these configuration options can set straight in model. devise.setup |config| # secret key used devise. devise uses key generate # random tokens. changing key render invalid existing # confirmation, reset password , unlock tokens in database. config.secret_key = rails.application.secrets.my_devise_secret_key # ==> mailer configuration # configure e-mail address shown in devise::mailer, # note overwritten if utilize own mailer class # default 'from' parameter. config.mailer_sender = rails.application.secrets.my_devise_from_email # configure class responsible send e-mails. # config.mailer = 'devise::mailer' # ==> orm configuration # load , configure orm. supports :active_record (default) , # :mongoid (bson_ext recommended) default. other orms may # available additional gems. require 'devise/orm/active_record' # ==> configuration authentication mechanism # configure keys used when authenticating user. default # :email. can configure utilize [:username, :subdomain], # authenticating user, both parameters required. remember # parameters used when authenticating , not when retrieving # session. if need permissions, should implement in before filter. # can supply hash value boolean determining whether # or not authentication should aborted when value not present. config.authentication_keys = [ :email ] # configure parameters request object used authentication. each entry # given should request method , automatically passed # find_for_authentication method , considered in model lookup. instance, # if set :request_keys [:subdomain], :subdomain used on authentication. # same considerations mentioned authentication_keys apply request_keys. # config.request_keys = [] # configure authentication keys should case-insensitive. # these keys downcased upon creating or modifying user , when used # authenticate or find user. default :email. config.case_insensitive_keys = [ :email ] # configure authentication keys should have whitespace stripped. # these keys have whitespace before , after removed upon creating or # modifying user , when used authenticate or find user. default :email. config.strip_whitespace_keys = [ :email ] # tell if authentication through request.params enabled. true default. # can set array enable params authentication # given strategies, example, `config.params_authenticatable = [:database]` # enable database (email + password) authentication. # config.params_authenticatable = true # tell if authentication through http auth enabled. false default. # can set array enable http authentication # given strategies, example, `config.http_authenticatable = [:database]` # enable database authentication. supported strategies are: # :database = back upwards basic authentication authentication key + password # config.http_authenticatable = false # if http headers should returned ajax requests. true default. # config.http_authenticatable_on_xhr = true # realm used in http basic authentication. 'application' default. # config.http_authentication_realm = 'application' # alter confirmation, password recovery , other workflows # behave same regardless if e-mail provided right or wrong. # not impact registerable. config.paranoid = true # default devise store user in session. can skip storage # particular strategies setting option. # notice if skipping storage authentication paths, # may want disable generating routes devise's sessions controller # passing skip: :sessions `devise_for` in config/routes.rb config.skip_session_storage = [:http_auth] # default, devise cleans csrf token on authentication # avoid csrf token fixation attacks. means that, when using ajax # requests sign in , sign up, need new csrf token # server. can disable alternative @ own risk. # config.clean_up_csrf_token_on_authentication = true # ==> configuration :database_authenticatable # bcrypt, cost hashing password , defaults 10. if # using other encryptors, sets how many times want password re-encrypted. # # limiting stretches 1 in testing increment performance of # test suite dramatically. however, recommended not utilize # value less 10 in other environments. note that, bcrypt (the default # encryptor), cost increases exponentially number of stretches (e.g. # value of 20 extremely slow: approx. 60 seconds 1 calculation). config.stretches = rails.env.test? ? 1 : 10 # setup pepper generate encrypted password. config.pepper = rails.application.secrets.my_devise_pepper # ==> configuration :confirmable # period user allowed access website without # confirming account. instance, if set 2.days, user # able access website 2 days without confirming account, # access blocked in 3rd day. default 0.days, meaning # user cannot access website without confirming account. config.allow_unconfirmed_access_for = 0.days # period user allowed confirm business relationship before # token becomes invalid. example, if set 3.days, user can confirm # business relationship within 3 days after mail service sent, on 4th day # business relationship can't confirmed token more. # default nil, meaning there no restriction on how long user can take # before confirming account. config.confirm_within = 7.days # if true, requires email changes confirmed (exactly same way # initial business relationship confirmation) applied. requires additional unconfirmed_email # db field (see migrations). until confirmed, new email stored in # unconfirmed_email column, , copied email column on successful confirmation. config.reconfirmable = true # defines key used when confirming business relationship config.confirmation_keys = [ :email ] # ==> configuration :rememberable # time user remembered without asking credentials again. # config.remember_for = 5.days config.remember_for = 4.weeks # invalidates remember me tokens when user signs out. config.expire_all_remember_me_on_sign_out = true # if true, extends user's remember period when remembered via cookie. # config.extend_remember_period = false # options passed created cookie. instance, can set # secure: true in order forcefulness ssl cookies. # has been set secure in rails 4 initializer # config.rememberable_options = { secure: rails.env == 'production'} # ==> configuration :validatable # range password length. config.password_length = 8..128 # email regex used validate email formats. asserts # 1 (and one) @ exists in given string. # give user feedback , not assert e-mail validity. config.email_regexp = /\a[^@]+@[^@]+\z/ # ==> configuration :timeoutable # time want timeout user session without activity. after # time user asked credentials again. default 30 minutes. config.timeout_in = 5.hours # if true, expires auth token on session timeout. config.expire_auth_token_on_timeout = true # ==> configuration :lockable # defines strategy used lock account. # :failed_attempts = locks business relationship after number of failed attempts sign in. # :none = no lock strategy. should handle locking yourself. config.lock_strategy = :failed_attempts # defines key used when locking , unlocking business relationship config.unlock_keys = [ :email ] # defines strategy used unlock account. # :email = sends unlock link user email # :time = re-enables login after amount of time (see :unlock_in below) # :both = enables both strategies # :none = no unlock strategy. should handle unlocking yourself. config.unlock_strategy = :both # number of authentication tries before locking business relationship if lock_strategy # failed attempts. config.maximum_attempts = 5 # time interval unlock business relationship if :time enabled unlock_strategy. config.unlock_in = 1.hour # warn on lastly effort before business relationship locked. config.last_attempt_warning = true # ==> configuration :recoverable # # defines key used when recovering password business relationship config.reset_password_keys = [ :email ] # time interval can reset password reset password key. # don't set little interval or users won't have time # alter passwords. config.reset_password_within = 12.hours # ==> configuration :encryptable # allow utilize encryption algorithm besides bcrypt (default). can utilize # :sha1, :sha512 or encryptors others authentication tools :clearance_sha1, # :authlogic_sha512 (then should set stretches above 20 default behavior) # , :restful_authentication_sha1 (then should set stretches 10, , re-create # rest_auth_site_key pepper). # # require `devise-encryptable` gem when using other bcrypt # config.encryptor = :sha512 # ==> scopes configuration # turn scoped views on. before rendering 'sessions/new', first check # 'users/sessions/new'. it's turned off default because it's slower if # using default views. config.scoped_views = true # configure default scope given warden. default it's first # devise role declared in routes (usually :user). config.default_scope = :user # set configuration false if want /users/sign_out sign out # current scope. default, devise signs out scopes. config.sign_out_all_scopes = true # ==> navigation configuration # lists formats should treated navigational. formats # :html, should redirect sign in page when user not have # access, formats :xml or :json, should homecoming 401. # # if have navigational formats, :iphone or :mobile, # should add together them navigational formats lists. # # "*/*" below required match net explorer requests. # config.navigational_formats = ['*/*', :html] # default http method used sign out resource. default :delete. config.sign_out_via = :delete # ==> omniauth # add together new omniauth provider. check wiki more info on setting # on models , hooks. # config.omniauth :github, 'app_id', 'app_secret', scope: 'user,public_repo' # ==> warden configuration # if want utilize other strategies, not supported devise, or # alter failure app, can configure them within config.warden block. # # config.warden |manager| # manager.intercept_401 = false # manager.default_strategies(scope: :user).unshift :some_external_strategy # end # ==> mountable engine configurations # when using devise within engine, let's phone call `myengine`, , engine # mountable, there configurations taken account. # next options available, assuming engine mounted as: # # mount myengine, at: '/my_engine' # # router invoked `devise_for`, in illustration above, be: # config.router_name = :my_engine # # when using omniauth, devise cannot automatically set omniauth path, # need manually. users scope, be: # config.omniauth_path_prefix = '/my_engine/users/auth' end rails.application.config.to_prepare devise::sessionscontroller.layout 'nested/login' devise::passwordscontroller.layout 'nested/passwords' devise::registrationscontroller.layout proc{ |controller| user_signed_in? ? 'application' : 'nested/create' } devise::confirmationscontroller.layout 'nested/create' # devise::unlockscontroller.layout 'devise' end
ok, here goes! if googling issue, please warned here cause devise init:
# alter confirmation, password recovery , other workflows # behave same regardless if e-mail provided right or wrong. # not impact registerable. config.paranoid = false it located in dissecting method in authenticatable.rb:
# helper utilize after calling send_*_instructions methods on resource. # if in paranoid mode, deed if resource valid # , instructions sent. def successfully_sent?(resource) notice = if devise.paranoid resource.errors.clear :send_paranoid_instructions elsif resource.errors.empty? :send_instructions end if notice set_flash_message :notice, notice if is_flashing_format? true end end ruby-on-rails devise
No comments:
Post a Comment