Rails 6、允许用户通过验证后转到期望的页面

Rails 6, allow user to go to expected page after authentication

当用户登录 Devise 时,根据 after_sign_in_path_for() 方法进入 new_car_path。但是,在某些情况下,用户会尝试转到需要进行身份验证的特定页面。

我的示例,注销用户直接进入“域。com/compliance-form”,此页面要求用户在访问之前进行身份验证,因此正如预期的那样,它重定向到登录表单。当用户登录时,它会将他们带到“after_sign_in_path_for”路径,在本例中是“new_car_path”。

但是,由于用户确切地知道他们想去的页面,我希望他们去“compliance_form_path”“域。com/compliance-form”。

我该如何完成?

  def after_sign_in_path_for(_resource=nil)
    new_car_path
  end

如果我添加stored_location_for(resource) as user11350468 推荐:

def after_sign_in_path_for(resource = nil)
  stored_location_for(resource) || new_car_path
end

我收到以下错误,

NoMethodError in SessionsController#create undefined method `user_url' for #SessionsController:0x00007fc9f9bd1148 Did you mean? search_url

然后添加:

class ApplicationController < ActionController::Base
  before_action :store_user_location!, if: :storable_location?
  
  def storable_location?
    request.get? && is_navigational_format? && !devise_controller? && !request.xhr? 
  end

  def store_user_location!
    store_location_for(:user, request.fullpath)
  end
end

即使在控制器中添加了 before action 之后,我仍然得到同样的错误,这是日志..

Started GET "/compliance_form for 127.0.0.1 at 2020-12-17 11:26:14 -0600
Processing by ComplianceController#new as HTML
Completed 401 Unauthorized in 4ms (ActiveRecord: 0.0ms | Allocations: 411)

Started GET "/users/sign_in" for 127.0.0.1 at 2020-12-17 11:26:14 -0600
Processing by SessionsController#new as HTML
  Rendering devise/sessions/new.html.erb within layouts/devise
  Rendered devise/sessions/new.html.erb within layouts/devise (Duration: 20.3ms | Allocations: 9174)
  Rendered layouts/_head.html.erb (Duration: 361.5ms | Allocations: 235189)
  Rendered layouts/_devise_navbar.html.erb (Duration: 3.7ms | Allocations: 901)
  Rendered layouts/_footer.html.erb (Duration: 0.1ms | Allocations: 5)
Completed 200 OK in 399ms (Views: 395.8ms | ActiveRecord: 0.0ms | Allocations: 249472)

Started POST "/users/sign_in" for 127.0.0.1 at 2020-12-17 11:26:21 -0600
Processing by SessionsController#create as HTML
  Parameters: {"authenticity_token"=>"IDqVSy1swedds22AEqMEzQQnamz7I+gysdfbNlPPhsRTMJGZkWCgWFYq1vg/3Af2Af5xjchnzdfgoH6m7wHXEA==", "user"=>{"email"=>"name@domain.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Continue"}
  User Load (1.8ms)  SELECT "users".* FROM "users" WHERE "users"."email" =  LIMIT   [["email", "name@domain.com"], ["LIMIT", 1]]
  ↳ app/controllers/sessions_controller.rb:6:in `create'
  User Load (0.9ms)  SELECT "users".* FROM "users" WHERE "users"."email" =  ORDER BY "users"."id" ASC LIMIT   [["email", "name@domain.com"], ["LIMIT", 1]]
  ↳ app/controllers/sessions_controller.rb:11:in `create'
   (0.6ms)  BEGIN
  ↳ app/controllers/sessions_controller.rb:11:in `create'
  User Update (1.0ms)  UPDATE "users" SET "current_sign_in_at" = , "last_sign_in_at" = , "sign_in_count" = , "updated_at" =  WHERE "users"."id" =   [["current_sign_in_at", "2020-12-17 17:26:21.278696"], ["last_sign_in_at", "2020-12-17 17:24:43.660819"], ["sign_in_count", 31], ["updated_at", "2020-12-17 17:26:21.279770"], ["id", 2]]
  ↳ app/controllers/sessions_controller.rb:11:in `create'
   (4.6ms)  COMMIT
  ↳ app/controllers/sessions_controller.rb:11:in `create'
Redirected to 
Completed 500 Internal Server Error in 610ms (ActiveRecord: 9.9ms | Allocations: 188187)
NoMethodError (undefined method `user_url' for #<SessionsController:0x00007fae28d6a438>
Did you mean?  search_url):
  
app/controllers/sessions_controller.rb:11:in `create'

更新:

我的语法有点不对,我应该发布准确的代码(吸取教训):

  def after_sign_in_path_for(_resource=nil)
    return stored_location_for(resource) if stored_location_for(resource).present?
    return car_index_path if current_user.car?
    new_car_path
  end

stored_location_for(resource) 被调用时,它变成了 nil,因此 If 语句 returns true,但是 stored_location_for(资源)值returnsnil.

因此导致错误。 Stored_location_for() 下面的解决方案非常有效!

使用助手 stored_location_for

尝试以下操作

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:

根据设计 wiki,请在您的 application_controller 中添加以下 before_action:

class ApplicationController < ActionController::Base
  before_action :store_user_location!, if: :storable_location?
  
  def storable_location?
    request.get? && is_navigational_format? && !devise_controller? && !request.xhr? 
  end

  def store_user_location!
    store_location_for(:user, request.fullpath)
  end
end

然后在 after_sign_in_path_for:

def after_sign_in_path_for(resource = nil)
  stored_location_for(resource) || new_car_path
end