我的方法正在执行,但Devise根本没有使用返回值。在登录页面上,它只是通过“成功登录”通知重新加载页面。它不会重定向到从方法返回的值。
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)
请注意,它正在渲染users/sessions/new.haml
而不是编辑页面?
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
我完全注释掉了该方法,但仍然重新加载了登录页面。
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
设计4.4.0
文档:
我添加了
def after_sign_in_path_for(resource)
logger.debug '############# ' + resource.errors.full_messages.join(', ')
确实发现了验证错误,例如
############# Title can't be blank, Country can't be blank, Signature can't be blank, ...
但确实显示了通知
Signed in successfully.
我确实有一个会话,可以在其他地方导航。我的验证是on: :update
。
validates :email, :name, :title, :phone, :address1, :city, :state, :zip, :country, :type, :signature, presence: true, on: :update
这不应导致登录行为错误。
我评论了模型上的所有验证,它确实有效,但这非常不寻常!验证不应影响登录行为。必须有一个解决方法。
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)
答案 0 :(得分:2)
由于您只需要更新验证,我猜您只需要特定表单,因为即使没有此验证,您的用户仍然有效。 在这种情况下,我将使用一个所谓的表单对象,它为您执行更新验证并删除用户模型的更新验证。在这种情况下,您的验证不会影响您应用的其他部分。
只需使用ActiveModel,Here就如何做到这一点是一个很好的指南。
示例:
应用程序/模型/ user.rb
class User < ApplicationRecord
# remove the validations here
end
应用程序/形式/ user_edit_form.rb
class UserEditForm
include ActiveModel::Model
ATTRIBUTES = :email, :name, :title, :phone,
:address1, :city, :state, :zip,
:country, :type, :signature
attr_accessor *ATTRIBUTES
validates *ATTRIBUTES, presence: true
def update(user)
if valid?
user.update(self.attributes)
end
end
def self.for_user(user)
new(user.slice(*ATTRIBUTES)
end
end
users_controller.rb
class UsersController
def edit
@user = User.find(params[:id])
@user_edit_form = UserEditForm.for_user(@user)
end
def update
@user = User.find(params[:id])
@user_edit_form = UserEditForm.new(user_update_params).update(@user)
if @user_edit_form.errors?
render :edit
else
redirect_to user_path(@user)
end
end
def user_update_params
# ...
end
end
edit.html.erb
<%= form_for @user_edit_form, url: user_path(@user), method: :patch do |f| %>
# ...
<%= f.submit %>
<% end %>
<强>替代强>
另一种方法是将虚拟属性添加到模型中,并在用户控制器中有条件地运行验证。
class User < ApplicationRecord
attr_accessor :profile_complete
with_options if: -> { profile_complete } do
validates :email, :name, :title, :phone, :address1, :city, :state, :zip, :country, :type, :signature, presence: true
end
end
users_controller.rb
class UsersController < ApplicationController
def update
@user = User.find(params[:id])
@user.profile_complete = true
if @user.update(user_update_params)
redirect_to @user
else
render :edit
end
# ...
end
end
注意:您也可以使用真实数据库属性,而不是使用虚拟属性(attr_accessor),这样您实际上也可以知道哪些用户完全填写了他们的个人资料。
备选方案2
在其他一些项目中,我还使用了状态机宝石(有一对,例如aasm或statemachines-activerecord)来做类似的事情。一些状态机宝石甚至支持仅针对某些状态或转换进行验证。
答案 1 :(得分:-1)
请查看此文档https://github.com/plataformatec/devise/wiki/How-To:-redirect-to-a-specific-page-on-successful-sign-in。他们已经明确提到你什么时候进入循环和解决方案。检查上述文档中的防止重定向循环部分。
答案 2 :(得分:-1)
您可能需要在模型上进行条件验证。像这样:
validates :email, :name, :title, :phone, :address1, :city, :state, :zip, :country, :type, :signature, presence: true, on: :update, unless: Proc.new {|user| user.current_sign_in_at.present? }
每当sign_in发生时,设计都会更新sign_in_at
。这将触发更新操作和相关验证。
此外,文档说allow_nil: true
指示模型仅在提交的表单上存在字段时验证字段。