undefined method `password_confirmation=' rails 5

4

我有一个基于Ruby on Rails的API。目前的逻辑是设计密码重置功能。以下是查找用户并重置密码的代码块:

def update_password_by_token
  @user = User.find_by_reset_password_token!(params[:id])
  if @user.reset_password_sent_at < 2.hours.ago
    render status: 422, json: {}
  else
    @user.password = params[:password]
    @user.password_confirmation = params[:confirm_password]
    if @user.save
      render status: 200, json: {}
    else
      render status: 422, json: {}
   end
 end
end

这里是Android向API发送参数的过程

{
 "password":"newpassword",
 "confirm_password":"newpassword", 
 "id":"Upn0QHKNy858yMK1J8x1KA"

}

进一步深入研究后,我拿到了令牌并启动了Rails控制台。

@user = User.find_by_reset_password_token!("Upn0QHKNy858yMK1J8x1KA")
User Load (1.5ms)  SELECT  "users".* FROM "users" WHERE 
"users"."deleted_at" IS NULL AND "users"."reset_password_token" = $1 
LIMIT $2  [["reset_password_token", "CtW8XFYUdX3d9J7H1rtfUQ"], ["LIMIT", 
1]]

=> #<User id: 57, first_name: "abc", last_name: "def", email: 
"kalamasher@gmail.com", deleted_at: nil, authentication_token: 
"uTWmP41bgihmSW-Thsog", created_at: "2019-01-10 09:56:30", updated_at: 
"2019-01-10 10:33:07", is_confirmed: true, firebase_token: 
"caQkNMlpp2s:APA91bEr4NKSKsMJ-VCJaXLd8mxadb7...", tenant_id: 6, 
is_admin: false, mobile_device: "android", user_level: "partner">
irb(main):006:0> @user.password ="new@password"
=> "new@password"
irb(main):007:0> @user.password_confirmation ="new@password"
=> "new@password"
irb(main):008:0> @user.save
(2.7ms)  BEGIN
User Exists (1.6ms)  SELECT  1 AS one FROM "users" WHERE "users"."email"         
= $1 AND "users"."deleted_at" IS NULL AND ("users"."id" != $2) AND 
"users"."tenant_id" = $3 LIMIT $4  [["email", "kalamasher@gmail.com"], 
["id", 57], ["tenant_id", 6], ["LIMIT", 1]]

SQL (1.6ms)  UPDATE "users" SET "encrypted_password" = $1, 
"reset_password_token" = $2, "reset_password_sent_at" = $3, "updated_at" 
= $4 WHERE "users"."id" = $5  [["encrypted_password", 
"$2a$10$pRhNupGtOiCeCafNsdiVYuqTNYNZqI.xa2oyGmkRIybmDiYOR.f0i"], 
["reset_password_token", nil], ["reset_password_sent_at", nil], 
["updated_at", "2019-01-10 11:08:46.354276"], ["id", 57]]

(2.4ms)  COMMIT

=> true

更新
    A NoMethodError occurred in members#update_password_by_token:

  undefined method `password_confirmation=' for nil:NilClass
  app/controllers/api/v1/members_controller.rb:85:in `update_password_by_token'


-------------------------------
Request:
-------------------------------

  * URL        : http:#####/api/members/update_password_by_token
  * HTTP Method: POST
  * IP address : X.X.X.X
  * Parameters : {"password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]", "id"=>"CtW8XFYUdX3d9J7H1rtfUQ", "format"=>"json", "controller"=>"api/v1/members", "action"=>"update_password_by_token"}
  * Timestamp  : 2019-01-10 10:33:55 UTC
  * Server : oacsrv01
  * Rails root : releases/20180531092251
  * Process: 3967

-------------------------------
Session:
-------------------------------

  * session id: nil
  * data: {}

-------------------------------
Environment:
-------------------------------

* CONTENT_LENGTH                                 : 75
* CONTENT_TYPE                                   : application/x-www-form-urlencoded
* HTTP_ACCEPT                                    : application/json, text/plain, */*
* HTTP_ACCEPT_ENCODING                           : gzip, deflate
* HTTP_ACCEPT_LANGUAGE                           : en-US,en;q=0.9,la;q=0.8
* HTTP_CONNECTION                                : close
* HTTP_DNT                                       : 1
* HTTP_HOST                                      : host
* HTTP_ORIGIN                                    : http:
* HTTP_REFERER                                   : http:
* HTTP_USER_AGENT                                : Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
* HTTP_VERSION                                   : HTTP/1.0
* HTTP_X_FORWARDED_FOR                           : X.X.X.X
* ORIGINAL_FULLPATH                              : /api/members/update_password_by_token
* ORIGINAL_SCRIPT_NAME                           : 
* PATH_INFO                                      : /api/members/update_password_by_token
* QUERY_STRING                                   : 
* REMOTE_ADDR                                    : 127.0.0.1
* REQUEST_METHOD                                 : POST
* REQUEST_PATH                                   : /api/members/update_password_by_token
* REQUEST_URI                                    : /api/members/update_password_by_token
* ROUTES_47174199350780_SCRIPT_NAME              : 
* SCRIPT_NAME                                    : 
* SERVER_NAME                                    : server*****
* SERVER_PORT                                    : 80
* SERVER_PROTOCOL                                : HTTP/1.0
* SERVER_SOFTWARE                                : Unicorn 5.3.1
* action_controller.instance                     : #<Api::V1::MembersController:0x0055cf355102c0>
* action_dispatch.backtrace_cleaner              : #<Rails::BacktraceCleaner:0x0055cf347bec20>
* action_dispatch.cookies                        : #<ActionController::RequestForgeryProtection::ProtectionMethods::NullSession::NullCookieJar:0x0055cf3553aea8>
* action_dispatch.cookies_digest                 : 
* action_dispatch.cookies_serializer             : json
* action_dispatch.encrypted_cookie_salt          : encrypted cookie
* action_dispatch.encrypted_signed_cookie_salt   : signed encrypted cookie
* action_dispatch.http_auth_salt                 : http authentication
* action_dispatch.key_generator                  : #<ActiveSupport::CachingKeyGenerator:0x0055cf32a45810>
* action_dispatch.logger                         : #<ActiveSupport::Logger:0x0055cf32b27e68>
* action_dispatch.parameter_filter               : [:password]
* action_dispatch.redirect_filter                : []
* action_dispatch.remote_ip                      : X.X.X.X
* action_dispatch.request.content_type           : application/x-www-form-urlencoded
* action_dispatch.request.flash_hash             : 
* action_dispatch.request.formats                : [#<Mime::Type:0x0055cf31200390 @synonyms=["text/x-json", "application/jsonrequest"], @symbol=:json, @string="application/json", @hash=-2441761977289553219>]
* action_dispatch.request.parameters             : {"password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]", "id"=>"CtW8XFYUdX3d9J7H1rtfUQ", "format"=>"json", "controller"=>"api/v1/members", "action"=>"update_password_by_token"}
* action_dispatch.request.path_parameters        : {:format=>"json", :controller=>"api/v1/members", :action=>"update_password_by_token"}
* action_dispatch.request.query_parameters       : {}
* action_dispatch.request.request_parameters     : {"password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]", "id"=>"CtW8XFYUdX3d9J7H1rtfUQ"}
* action_dispatch.request.unsigned_session_cookie: {}
* action_dispatch.request_id                     : efb6377f-4437-46c5-8e13-5cc40b79692f
* action_dispatch.routes                         : #<ActionDispatch::Routing::RouteSet:0x0055cf32ca2bf8>
* action_dispatch.secret_key_base                : 0a1d165e12a2bc249fdd588b275f670198835b689324af3b36e8b9ab4fe246ec80c97c1cb6d3ba495c7d214a06eb3285f25081ce6d307d520a9c0a6bdd892872
* action_dispatch.secret_token                   : 
* action_dispatch.show_detailed_exceptions       : false
* action_dispatch.show_exceptions                : true
* action_dispatch.signed_cookie_salt             : signed cookie
* devise.skip_storage                            : true
* rack.cors                                      : #<Rack::Cors::Result:0x0055cf35476f08>
* rack.errors                                    : #<File:0x0055cf2f25d538>
* rack.hijack                                    : #<Unicorn::HttpParser:0x0055cf3003b3d0>
* rack.hijack?                                   : true
* rack.input                                     : #<Unicorn::TeeInput:0x0055cf35421b98>
* rack.logger                                    : #<Logger:0x0055cf2fd86810>
* rack.multiprocess                              : true
* rack.multithread                               : false
* rack.request.cookie_hash                       : {}
* rack.request.form_hash                         : {"password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]", "id"=>"CtW8XFYUdX3d9J7H1rtfUQ"}
* rack.request.form_input                        : #<Unicorn::TeeInput:0x0055cf35421b98>
* rack.request.form_vars                         : [FILTERED]
* rack.request.query_hash                        : {}
* rack.request.query_string                      : 
* rack.run_once                                  : false
* rack.session                                   : #<ActionController::RequestForgeryProtection::ProtectionMethods::NullSession::NullSessionHash:0x0055cf3553af48>
* rack.session.options                           : {:skip=>true}
* rack.tempfiles                                 : []
* rack.url_scheme                                : http
* rack.version                                   : [1, 2]
* unicorn.socket                                 : #<Kgio::Socket:0x0055cf35421e90>
* warden                                         : Warden::Proxy:47174220233180 @config={:default_scope=>:user, :scope_defaults=>{}, :default_strategies=>{:user=>[:rememberable, :database_authenticatable]}, :intercept_401=>false, :failure_app=>#<Devise::Delegator:0x0055cf2fedcd18>}
-------------------------------
Backtrace:
-------------------------------

  app/controllers/api/v1/members_controller.rb:85:in `update_password_by_token'



F, [2019-01-10T15:33:56.326625 #3967] FATAL -- : [efb6377f-4437-46c5-8e13-5cc40b79692f]   
F, [2019-01-10T15:33:56.326751 #3967] FATAL -- : [efb6377f-4437-46c5-8e13-5cc40b79692f] NoMethodError (undefined method `password_confirmation=' for nil:NilClass):
F, [2019-01-10T15:33:56.326796 #3967] FATAL -- : [efb6377f-4437-46c5-8e13-5cc40b79692f]   
F, [2019-01-10T15:33:56.327032 #3967] FATAL -- : [efb6377f-4437-46c5-8e13-5cc40b79692f] app/controllers/api/v1/members_controller.rb:85:in `update_password_by_token'

我在部署的代码中是否有做错的地方?请问有人能给予建议吗?提前感谢。


1
请发布错误日志以便更好地解释。 - ray
请查看问题的更新版本。 - Ali Ammaar
所以它说你的 @user 是空值,而你正在对空值调用 password_confirmation 设置器。如果 @user 是空值,为什么它不会在 @user.password = 上中断,我就无法理解了。 - ray
我再次使用控制台逐步操作,@user找到了并重置了密码。 - Ali Ammaar
2个回答

1
检查您的User模型是否具有password_digest属性。 password_confirmation方法要求您的User模型具有password_digest属性。
为了使用此方法,在您的User模型中,添加以下has_secure_password方法:
class User < ApplicationRecord
    has_secure_password
end

has_secure_password方法将会在你的User模型中添加password_digest属性,如果该模型已经存在password_digest属性。

顺便说一下,在ActiveModel中的secure_password.rb文件中包含以下部分。

 module ClassMethods
  # Adds methods to set and authenticate against a BCrypt password.
  # This mechanism requires you to have a +password_digest+ attribute.
  #
  # The following validations are added automatically:
  # * Password must be present on creation
  # * Password length should be less than or equal to 72 bytes
  # * Confirmation of password (using a +password_confirmation+ attribute)
  #
  # If password confirmation validation is not needed, simply leave out the
  # value for +password_confirmation+ (i.e. don't provide a form field for
  # it). When this attribute has a +nil+ value, the validation will not be
  # triggered.

1

最终,经过一天的努力,我解决了问题,现在它可以正常工作。

唯一的解决方案是从函数中“排除password_confirmation”。 现在更新的密码更新函数update_password_by_token的代码如下。

def update_password_by_token
  @user = User.find_by_reset_password_token!(params[:id])
  if @user.present?
    if @user.reset_password_sent_at < 2.hours.ago
      render status: 422, json: {}
    else
      @user.password = params[:password]
      if @user.save
        render status: 200, json: {}
      else
        render status: 422, json: {}
      end
    end
  end
end

再次感谢所有在此上下文中尝试帮助我的人。 我发布了答案,以便将来有人可以受益。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接