Unable to use Active Record's update method on a single attribute. Is it due to callbacks or validations?

huangapple go评论78阅读模式
英文:

Unable to use Active Record's update method on a single attribute. Is it due to callbacks or validations?

问题

在我的users_controller.rb文件中,我有一个方法,我只想更新一个字段:confirmation_token。在这个模式下,这完全正常工作:

ActiveRecord::Schema[7.0].define(version: 2023_08_04_115747) do
  create_table "users", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
    t.string "email"
    t.string "role"
    t.string "confirmation_token"
    t.boolean "confirmed"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "password_digest"
  end
end

以及这个方法:

def request_reset_password
    email = params[:email]
    @user_email = User.find_by(email: params[:email])
    @user = User.find(@user_email.id)
    if @user && @user.confirmed == true && @user.confirmation_token == nil
      @user.confirmation_token = SecureRandom.hex(4)
      @user.update(confirmation_token: @user.confirmation_token)
      UserMailer.with(user: @user).request_password_reset.deliver_now
      redirect_to root_path, notice: "Email sent successfully."
    else
      redirect_to root_path, alert: "Email doesn't exist or is not confirmed yet."
    end
end

一旦我创建了一个迁移来添加User模型的username字段,我就无法更新这个记录,数据库将在同一请求中回滚。唯一的解决方法是使用update_columns来绕过验证。我的天啊,我不明白哪些验证会阻止更新方法。更奇怪的是,即使记录没有更新,UserMailer也会发送邮件。

为了更好地理解,这是我的验证:

validates :email, presence: true, uniqueness: true, format: { with: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i, message: "is not a valid email address"}
validates :password, presence: true, length: { minimum: 8}
validates :username, presence: true, uniqueness: true, length: { minimum: 3, maximum: 20, message: "must be between 3 and 20 characters"}
英文:

In my users_controller.rb, I have a method where I want to update just one field: confirmation_token. This worked perfectly fine with this schema:

ActiveRecord::Schema[7.0].define(version: 2023_08_04_115747) do
  create_table "users", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
    t.string "email"
    t.string "role"
    t.string "confirmation_token"
    t.boolean "confirmed"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "password_digest"
  end

end

And with this method:

def request_reset_password
    email = params[:email]
    @user_email = User.find_by(email: params[:email])
    @user = User.find(@user_email.id)
    if @user && @user.confirmed == true && @user.confirmation_token == nil
      @user.confirmation_token = SecureRandom.hex(4)
      @user.update(confirmation_token: @user.confirmation_token)
      UserMailer.with(user: @user).request_password_reset.deliver_now
      redirect_to root_path, notice: "Email sent successfully."
    else
      redirect_to root_path, alert: "Email doesn't exist or is not confirmed yet."
    end
end

Once I created a migration to add the username field on the User model, I am not able to update this record, the DB will rollback at the same request. The only workaround is to use update_columns, to bypass validation. For the love of God, I can't understand which validations hinder the update method. And what is even stranger is that the UserMailer sends the mail, even if the record wasn't updated.

Would be really grateful to anyone who can enlighten me, as I am pretty sure I am missing something relatively simple.

For context, here are my validations:

validates :email, presence: true, uniqueness: true, format: { with: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i, message: "is not a valid email address"}
validates :password, presence: true, length: { minimum: 8}
validates :username, presence: true, uniqueness: true, length: { minimum: 3, maximum: 20, message: "must be between 3 and 20 characters"}

答案1

得分: 0

密码验证显然失败了。解决方法是如果记录存在,则跳过验证,使用以下方法:

def should_validate_password?
    new_record? || password.present?
end
英文:

Apparently the password validation failed. The solution was to skip the validation if the record exists with the following method:

def should_validate_password?
    new_record? || password.present?
end

huangapple
  • 本文由 发表于 2023年8月5日 04:21:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76838916.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定