Monday, March 12, 2018

Devise after_sign_in_path_for not working; being ignored when model has validations on: :update

Leave a Comment

My method is executing, but Devise is not using the return value at all. On the sign in page, it just reloads the page with a 'Signed in successfully' notice. It doesn't redirect to the value returned from the method.

Log

Started POST "/users/sign_in" for 127.0.0.1 at 2018-03-05 22:19:50 -0500 Processing by Users::SessionsController#create as HTML   Parameters: {"utf8"=>"√", "authenticity_token"=>"tQd5a43StP85oyyCpEmFU8cAkFXdJL2OLpuAK1+sqQC6/rIqcd+fB2iE4RT0RoPKPCqreNBYlv2bxjl9gZFrWg==", "user"=>{"email"=>"test11@example.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Log in"}   User Load (2.0ms)  SELECT  "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["email", "test11@example.com"], ["LIMIT", 1]]    (5.0ms)  BEGIN   User Exists (3.0ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = $1 AND ("users"."id" != $2) LIMIT $3  [["email", "test11@example.com"], ["id", 23], ["LIMIT", 1]]   Sector Load (0.0ms)  SELECT "sectors".* FROM "sectors" INNER JOIN "sectors_users" ON "sectors"."id" = "sectors_users"."sector_id" WHERE "sectors_users"."user_id" = $1  [["user_id", 23]]   Region Load (0.0ms)  SELECT "regions".* FROM "regions" INNER JOIN "regions_users" ON "regions"."id" = "regions_users"."region_id" WHERE "regions_users"."user_id" = $1  [["user_id", 23]]   Criterium Load (0.0ms)  SELECT "criteria".* FROM "criteria" INNER JOIN "criteria_users" ON "criteria"."id" = "criteria_users"."criterium_id" WHERE "criteria_users"."user_id" = $1  [["user_id", 23]]   AssetType Load (0.0ms)  SELECT "asset_types".* FROM "asset_types" INNER JOIN "asset_types_users" ON "asset_types"."id" = "asset_types_users"."asset_type_id" WHERE "asset_types_users"."user_id" = $1  [["user_id", 23]]   Company Load (1.0ms)  SELECT  "companies".* FROM "companies" WHERE "companies"."id" = $1 LIMIT $2  [["id", 42], ["LIMIT", 1]]    (5.0ms)  ROLLBACK ############### /users/23/edit   Rendering users/sessions/new.haml within layouts/application   Rendered users/shared/_links.html.erb (3.0ms)   Rendered users/sessions/new.haml within layouts/application (251.2ms)   Rendered layouts/_footer.haml (15.0ms) Completed 200 OK in 6554ms (Views: 3364.9ms | ActiveRecord: 86.1ms) 

Notice it is rendering users/sessions/new.haml instead of the edit page?

Code

class ApplicationController < ActionController::Base ...   def after_sign_in_path_for(resource)     logger.debug '############### ' + edit_user_path(resource) if resource.is_a?(User) && resource.signature.blank?     return edit_user_path resource if resource.is_a?(User) && resource.signature.blank?     stored_location_for(resource) ||       if resource.is_a?(User)         dashboard_path       elsif resource.is_a?(Facilitator) && resource.name.nil?         edit_facilitator_path resource       elsif resource.is_a?(Facilitator)         facilitator_path resource       else         super       end   end 

I completely commented out the method and it still reloaded the login page.

Started POST "/users/sign_in" for 127.0.0.1 at 2018-03-05 22:25:21 -0500 ...   Rendering users/sessions/new.haml within layouts/application 

Devise 4.4.0

Documentation:

https://github.com/plataformatec/devise/wiki/How-To%3A-Redirect-to-a-specific-page-on-successful-sign-in-and-sign-out

http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Controllers/Helpers:after_sign_in_path_for


I added

  def after_sign_in_path_for(resource)     logger.debug '############# ' + resource.errors.full_messages.join(', ') 

And did discover validation errors like

 ############# Title can't be blank, Country can't be blank, Signature can't be blank, ... 

But it does show the notice

Signed in successfully. 

And I do have a session and can navigate elsewhere. My validations are on: :update.

  validates :email, :name, :title, :phone, :address1, :city, :state, :zip, :country, :type, :signature, presence: true, on: :update 

This should not cause log in behavior errors.


I commented all validations on the model and it does work, but this is highly unusual! Validations should not affect login behavior. There has to be a workaround.

Started POST "/users/sign_in" for 127.0.0.1 at 2018-03-05 23:11:43 -0500   SQL (15.0ms)  UPDATE "users" SET "current_sign_in_at" = $1, "last_sign_in_at" = $2, "current_sign_in_ip" = $3, "sign_in_count" = $4, "updated_at" = $5 WHERE "users"."id" = $6  [["current_sign_in_at", "2018-03-06 04:11:44.225501"], ["last_sign_in_at", "2017-11-09 01:22:28.245231"], ["current_sign_in_ip", "127.0.0.1/32"], ["sign_in_count", 6], ["updated_at", "2018-03-06 04:11:44.230506"], ["id", 23]] Redirected to http://localhost:3000/users/23/edit Completed 302 Found in 2183ms (ActiveRecord: 48.0ms) 

3 Answers

Answers 1

As you only want your validations on update, I guess that you only need them for a specific form, since your users are still valid even without this validations. In that case I would use a so called form object, that does the on update validations for you and remove the on update validations on your user model. In that case your validations don't affect other parts of your app.

Here is a good guide on how to do that with just using ActiveModel.

An alternative could be to add a virtual attribute to the model and run your validations conditionally in the user controller.

Answers 2

You might need conditional validation on your model. Something like this:

 validates :email, :name, :title, :phone, :address1, :city, :state, :zip, :country, :type, :signature, presence: true, on: :update, unless: Proc.new {|user| user.sign_in_at.present? } 

Devise will update sign_in_at whenever sign_in happens. Which will trigger update action and related validations.

Also Documentation said the allow_nil: true instruct the model to validate the fields ONLY if it exists on the submitted form.

Answers 3

Check this documentation https://github.com/plataformatec/devise/wiki/How-To:-redirect-to-a-specific-page-on-successful-sign-in. They have clearly mentioned when you will go in loop and solution for it. Check Preventing redirect loops section in above doc.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment