简体   繁体   English

仅更新Rails模型中的某些属性

[英]Updating only some attributes in a rails model

I am trying to create an account management page in which you can update your display name, email, password, and other stuff. 我正在尝试创建一个帐户管理页面,您可以在其中更新您的显示名称,电子邮件,密码和其他内容。 I want to allow the user to update only part of their information without the model rejecting the changes if unchanged info is invalid. 我想允许用户仅更新其部分信息,而如果未更改的信息无效,则模型拒绝更改。 I need to update only part of a model, specifically updating account details without having to enter a password and confirmation. 我只需要更新模型的一部分,特别是无需输入密码和确认即可更新帐户详细信息。

Using a single form requires the user to change their password when updating details. 使用单个表格要求用户在更新详细信息时更改其密码。 I tried splitting the account details into a "profile" and "security" form hopefully to not send an empty password when updating somebody's name, but the model rejects the change noting the password is missing. 我尝试将帐户详细信息分为“个人资料”和“安全”表格,希望在更新某人的姓名时不会发送空密码,但是该模型拒绝更改,并指出密码丢失。 However, updating only the password with the two form setup seems to work just fine. 但是,使用两种形式的设置仅更新密码似乎可以正常工作。

I am looking for a general solution that would let me expand to only update a specific subset of fields in the future (adding 2FA to the security section would require the user to change their password to update their 2FA key as is). 我正在寻找一种通用的解决方案,该解决方案可以让我将来扩展以仅更新特定的字段子集(将2FA添加到安全性部分将要求用户更改其密码以按原样更新其2FA密钥)。

The only outside gems I am using are the Have I Been Pwned gem and an updated email_check gem . 我正在使用的唯一外部宝石是“ 我曾经拥有”宝石和更新的email_check宝石

My current code is: 我当前的代码是:
routes.rb routes.rb

Rails.application.routes.draw do
  # ...
  get '/account', to: 'account#index'
  post '/account', to: 'account#update'

  root 'application#home'
end

the account model 账户模型

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 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

and the account/index.html.erb 和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="&#x2713;" />
    <%= 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="&#x2713;" />
  <%= 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>

If you want to validate password field only when it is entered then use proc object conditionally as below. 如果仅在输入密码后才想验证密码字段,请按以下条件使用proc对象。 This will allow other fields to update irrespective of the password field 这将允许其他字段更新,而与密码字段无关

  validates :password,
            presence: true,
            not_pwned: true,
            format: { with: /\d/ },
            length: { minimum: 8 }, unless: Proc.new { |account| account.password.blank? }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM