【问题标题】:how to update two different attributes on two different pages?如何更新两个不同页面上的两个不同属性?
【发布时间】:2013-03-03 02:15:01
【问题描述】:

我有一个带有名称和密码属性的用户模型。当用户单击“编辑”时,我只希望名称字段可编辑和验证,而不是密码字段。当用户单击“重置密码”时,反之亦然。 我认为我的主要问题是如何在名称字段编辑期间关闭密码验证以及如何在密码编辑期间关闭名称验证?

edit.html.erb

<%= form_for @user, html: { class: "form_settings" } do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <p><span><%= f.label :name %></span>
    <%= f.text_field :name %>
  </p>

  <p style="padding-top: 15px"><span>&nbsp;</span>
    <%= f.submit "Submit", class: "submit" %>
  </p>
<% end %>

reset_password.html.erb

<%= form_for @user, html: { class: "form_settings" } do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <p><span><%= label_tag :old_password, "Current Password" %></span>
    <%= password_field_tag :old_password %>
  </p>

  <p><span><%= f.label :password %></span>
    <%= f.password_field :password %>
  </p>

  <p><span><%= f.label :password_confirmation %></span>
    <%= f.password_field :password_confirmation %>
  </p>

  <p style="padding-top: 15px"><span>&nbsp;</span>
    <%= f.submit "Submit", class: "submit" %>
  </p>
<% end %>

users_controller.rb

def update
  @user = User.find(params[:id])
  if params[:old_password]
    if @user.authenticate(params[:old_password])
      @user.update_attributes(password: params[:user][:password])
      flash[:success] = "Password has been updated"
      redirect_to @user
    else
      flash.now[:error] = "Current password is incorrect"
      render :reset_password
    end
  elsif @user.update_attributes(params[:user])
    flash[:success] = "User name updated"
    redirect_to @user
  else
    render :edit
  end
end

我的另一个问题是密码和密码确认验证不起作用。这就是我在模型中的内容:

validates :password, presence: true, confirmation: true

更新 获得了重置密码并使用此代码进行验证:

def update
  @user = User.find(params[:id])
  if params[:old_password]
    if @user.authenticate(params[:old_password])
      if params[:user][:password] == params[:user][:password_confirmation]
        @user.update_attributes(password: params[:user][:password])
        flash[:success] = "Password has been updated"
        redirect_to @user
      else
        flash.now[:error] = "Passwords don't match"
        render :reset_password
      end
    else
      flash.now[:error] = "Current password is incorrect"
      render :reset_password
    end
  elsif @user.update_attributes(params[:user])
    flash[:success] = "User name updated"
    redirect_to @user
  else
    render :edit
  end
end

但这对我来说似乎太复杂了。有人看到更简单的解决方案吗?

但我仍然有编辑名称字段的问题。就是说密码不能为空。

【问题讨论】:

    标签: ruby-on-rails-3


    【解决方案1】:

    您不应在同一个操作中混用名称编辑和密码重置。

    创建一个将更新用户属性的操作,password 字段不应与attr_accessible 一起列入白名单

    创建另一个处理密码重置的操作。

    def update
      @user = User.find(params[:id])
      if @user.update_attributes(params[:user])
        flash[:success] = "User name updated"
        redirect_to @user
      else
        render :edit
      end
    end
    
    def reset_password
      if params[:old_password] && @user.authenticate(params[:old_password])
        if params[:user][:password] == params[:user][:password_confirmation]
          @user.password = params[:user][:password]
          flash[:success] = "Password has been updated"
          redirect_to @user
        else
          flash.now[:error] = "Passwords don't match"
          render :reset_password
        end
      else
        flash.now[:error] = "Current password is incorrect"
        render :reset_password
      end
    end
    

    这样,每个动作都有其语义角色。

    顺便说一句,我希望你使用 bcrypt 之类的东西来存储密码。

    【讨论】:

    • 由于某种原因,当我尝试像这样重置密码时,会调用更新操作。
    • 你使用表格吗?您应该将每个按钮指向不同的操作
    • 是的,就是这样。不知道你可以把一个动作变成一个form_for。我终于可以理解其他 Rails 程序员的答案了。谢谢
    【解决方案2】:

    将验证逻辑移至模型并保持控制器清洁。

    validates :password, presence: true, confirmation: true, if: password?, on: :update
    validates :name, presence: true, if: name?, on: :update
    

    创建记录时这是必需的。只需添加on: :create

    validates :password, presence: true, confirmation: true, on: :create
    validates :name, presence: true, on: :create
    

    然后像这样修改你的控制器,

    def update
      @user = User.find(params[:id])
      @user.authenticate(params[:old_password]) if params[:old_password]
      return redirect_to @user, notice: "Sucessfully updated" if @user.update_attributes(params[:user])
      render Rails.application.routes.recognize_path(request.referer)[:action]
    end
    

    来自此链接的使用渲染想法: Render the action that initiated update

    【讨论】:

    • 对不起,我不明白如果:密码?如果:名字?做。它们是我需要构建的方法吗?
    • 嗯。它们是 rails 方法,如果密码有一些值,它将返回 true,否则返回 false,同样适用于 name。当您通过重置密码更新时,第一次验证将运行,当您仅在这种情况下更新名称时,第二次验证将运行。
    • 我认为它需要一个冒号:密码?
    【解决方案3】:

    想通了……但看起来有点丑:

    def update
      @user = User.find(params[:id])
      if params[:old_password]
        if @user.authenticate(params[:old_password])
          if params[:user][:password] == params[:user][:password_confirmation]
            @user.update_attributes(password: params[:user][:password])
            flash[:success] = "Password has been updated"
            redirect_to @user
          else
            flash.now[:error] = "Passwords don't match"
            render :reset_password
          end
        else
          flash.now[:error] = "Current password is incorrect"
          render :reset_password
        end
      elsif params[:user][:name].blank?
        flash[:error] = "Name can't be blank"
        render :edit
      else
        @user.update_attribute(:name, params[:user][:name])
        flash[:success] = "User name updated"
        redirect_to @user
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-05
      • 1970-01-01
      • 1970-01-01
      • 2019-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-27
      相关资源
      最近更新 更多