为什么 Rails 回滚即使模型存在?

Why does Rails rollback even though the model exists?

我想找出为什么我的更新方法在 Rails API 中不起作用。它应该更新生物领域。我将 API 托管在 Heroku 上,并使用 Heroku 日志在生产环境中进行调试。我用了exists?方法来确保用户在数据库中,但是当调用更新方法时,它会在执行此检查后回滚。我不明白这是什么原因?

这是输出的 Heroku 日志

2022-04-15T02:54:34.083586+00:00 app[web.1]: I, [2022-04-15T02:54:34.083515 #4]  INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] Started PATCH "/users/8" for 98.248.0.125 at 2022-04-15 02:54:34 +0000
2022-04-15T02:54:34.084345+00:00 app[web.1]: I, [2022-04-15T02:54:34.084290 #4]  INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] Processing by UsersController#update as HTML
2022-04-15T02:54:34.084376+00:00 app[web.1]: I, [2022-04-15T02:54:34.084350 #4]  INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d]   Parameters: {"bio"=>"test", "id"=>"8", "user"=>{"bio"=>"test"}}
2022-04-15T02:54:34.087450+00:00 app[web.1]: D, [2022-04-15T02:54:34.087403 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d]   User Load (1.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" =  LIMIT   [["id", 8], ["LIMIT", 1]]
2022-04-15T02:54:34.089711+00:00 app[web.1]: D, [2022-04-15T02:54:34.089664 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d]   User Exists? (1.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."id" =  LIMIT   [["id", 8], ["LIMIT", 1]]
2022-04-15T02:54:34.092004+00:00 app[web.1]: D, [2022-04-15T02:54:34.091963 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d]   TRANSACTION (0.9ms)  BEGIN
2022-04-15T02:54:34.093523+00:00 app[web.1]: D, [2022-04-15T02:54:34.093465 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d]   User Exists? (1.4ms)  SELECT 1 AS one FROM "users" WHERE "users"."username" =  AND "users"."id" !=  LIMIT   [["username", "newperson"], ["id", 8], ["LIMIT", 1]]
2022-04-15T02:54:34.095530+00:00 app[web.1]: D, [2022-04-15T02:54:34.095493 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d]   TRANSACTION (0.9ms)  ROLLBACK
2022-04-15T02:54:34.096881+00:00 app[web.1]: I, [2022-04-15T02:54:34.096842 #4]  INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] [active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.07ms)
2022-04-15T02:54:34.097078+00:00 app[web.1]: I, [2022-04-15T02:54:34.097050 #4]  INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] Completed 422 Unprocessable Entity in 13ms (Views: 0.6ms | ActiveRecord: 5.5ms | Allocations: 2816)
2022-04-15T02:54:34.101664+00:00 heroku[router]: at=info method=PATCH path="/users/8" host=anime-axis-api.herokuapp.com request_id=9e5ea776-5b15-420f-8cdc-0601480e0e3d fwd="98.248.0.125" dyno=web.1 connect=0ms service=17ms status=422 bytes=1096 protocol=https

这是我的更新方法:

def update
  if User.exists?(8)
    @current_user.update!(user_params)
    render json: @current_user, status: :ok
  end
end

private

def user_params
  # added require
  params.require(:user).permit(:username, :password, :password_confirmation, :bio, :avatar, :email)
end

我的用户模型:

class User < ApplicationRecord
  has_secure_password
  has_many :anime_lists
  has_many :animes, through: :anime_lists
  has_many :manga_lists
  has_many :mangas, through: :manga_lists

  validates :username, presence: true, confirmation: {case_sensitive: false}, uniqueness: true, length: {in: 6..30}
  validates :password, presence: true, confirmation: true
end

如果不知道你数据库中的数据,我不能完全确定,但我会说你有两个用户 username=newperson

当您尝试保存对任何验证触发器的任何更改时,更改不会提交到数据库。

我认为您的验证是问题所在。每次更新都会验证密码是否存在。由于 User#passwordnil 并且您的参数中没有密码,因此失败。

class User < ApplicationRecord
  has_secure_password
  validates :password, presence: true, confirmation: true
end
>> User.create(email: 'test@user.com', password: '123456');
>> User.first.update!(email: 'test@user.com')
  User Load (0.8ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT   [["LIMIT", 1]]
ActiveRecord::RecordInvalid: Validation failed: Password can't be blank

has_secure_password 还添加了自己的验证。

https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password

如果您想自定义密码验证,请使用

has_secure_password validations: false
# + your password validations

要获得一些想法,您可以看看 devise 如何进行验证:

https://github.com/heartcombo/devise/blob/v4.8.1/lib/devise/models/validatable.rb#L60