英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论