我正在尝试创建一个帐户管理页面,您可以在其中更新您的显示名称,电子邮件,密码和其他内容。我想允许用户仅更新其部分信息,而如果未更改的信息无效,则模型拒绝更改。我只需要更新模型的一部分,特别是无需输入密码和确认即可更新帐户详细信息。
使用单个表格要求用户在更新详细信息时更改其密码。我尝试将帐户详细信息分为“个人资料”和“安全”表格,希望在更新某人的姓名时不会发送空密码,但是该模型拒绝更改,并指出密码丢失。但是,使用两种形式的设置仅更新密码似乎可以正常工作。
我正在寻找一个通用的解决方案,该解决方案可以让我将来扩展以仅更新特定的字段子集(将2FA添加到安全性部分将要求用户更改其密码以按原样更新其2FA密钥)。
我正在使用的唯一外部宝石是Have I Been Pwned gem和更新的email_check gem。
我当前的代码是:
routes.rb
Rails.application.routes.draw do
# ...
get '/account', to: 'account#index'
post '/account', to: 'account#update'
root 'application#home'
end
帐户模型
class Account < ApplicationRecord
self.primary_key = :id
before_validation do
self.id.to_s.downcase! # lowercase the id
self.email.to_s.downcase! # lowercase the email
end
validates :id,
presence: true,
length: { minimum: 5, maximum: 32 },
uniqueness: true,
format: { with: /\A[a-z0-9-]*\z/, message: 'Only lowercase alphabet, numbers and dash allowed.' }
validates :name,
presence: true,
length: { minimum: 2, maximum: 50 }
validates_email_strictness :email,
message: 'Something about that email doesn\'t look right... Make sure the spelling is right or try another?'
has_secure_password
validates :password,
presence: true,
not_pwned: true,
format: { with: /\d/ },
length: { minimum: 8 }
attr_accessor :password_confirmation
attr_accessor :remember_token
end
account_controller.rb
class AccountController < ApplicationController
def index
if logged_in?
@account = current_account
else
flash[:danger] = "You must be logged in to do that!"
redirect_to '/account/login'
end
end
def update
@account = current_account
# TODO security concerns or otherwise when receiving only profile, security, etc fields
if @account.update_attributes(account_params)
flash.now[:success] = 'Update success!'
else
flash.now[:danger] = 'Something went wrong!'
end
render 'index'
end
private def account_params
params.require(:account).permit(:id,:name,:email,:password,:password_confirmation)
end
end
和account / index.html.erb
<% provide(:title,'Manage Account') %>
<h1>Manage Account</h1>
<%= render 'shared/error_messages' %>
<h3>Profile & Contact Info</h3>
<div>
<p>Account ID</p>
<input disabled value="<%= @account.id %>">
<form action="/account" method="post">
<input name="utf8" type="hidden" value="✓" />
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
<p>Name</p>
<input name="account[name]" value="<%= @account.name %>">
<p>Email</p>
<input name="account[email]" value="<%= @account.email %>" type="email">
<button type="submit">Submit</button>
</form>
</div>
<h3>Password & Security</h3>
<form action="/account" method="post">
<input name="utf8" type="hidden" value="✓" />
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
<p>New Password</p>
<input name="account[password]" type="password">
<p>Confirm New Password</p>
<input name="account[password_confirmation]" type="password">
<button type="submit">Submit</button>
</form>
答案 0 :(得分:2)
如果仅在输入密码后才想验证密码字段,则按条件使用proc对象,如下所示。这将允许其他字段更新,而与密码字段无关
validates :password,
presence: true,
not_pwned: true,
format: { with: /\d/ },
length: { minimum: 8 }, unless: Proc.new { |account| account.password.blank? }