hidden_field_tag 如何在重置密码表单中工作

How does hidden_field_tag works in an reset password form

很难理解表单在特定情况下如何与 hidden_field_tag 一起工作。我希望有人能向我解释发生了什么。

这是来自railstutorial重置密码的表格。

我的观点是:

<% provide(:title, 'Reset password') %>
<h1>Reset password</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user, url: password_reset_path(params[:id])) do |f| %>
      <%= render 'shared/error_messages', object: f.object %>

      <%= hidden_field_tag :email, @user.email %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Update password", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

我的更新操作和强参数方法:

  def update
    if params[:user][:password].empty?
      @user.errors.add(:password, "can't be empty")
      render 'edit'
    elsif @user.update_attributes(user_params)
      log_in @user
      @user.update_attribute(:reset_digest, nil)
      flash[:success] = "Password has been reset."
      redirect_to @user
    else
      render 'edit'
    end
  end

  private

  def user_params
    params.require(:user).permit(:password, :password_confirmation)
  end

访问编辑操作时,用户输入一封电子邮件,应用会向该电子邮件发送一个 link,并带有激活令牌,如下所示:

/password_resets/9Ij91DFChTeWTitNDVJfYw/edit?email=example%40railstutorial.org

用户打开此 link 并更改密码。这是完美的功能。我的问题是:如果我已经从编辑操作中获得用户并且没有在我的更新操作中明确使用 params[:email](随 hidden_field_tag 提供),为什么我需要隐藏标签?

动作是相互独立的。当您首次在 edit 操作范围内呈现密码重置表单时,您的 @user 实例变量(之前以某种方式初始化)用于为隐藏的电子邮件字段提供值。

当稍后用户提交表单时,其数据会在完全独立的请求中由 update 操作处理。这个请求不知道之前发生了什么,具体来说,表单最初是由 edit 动作渲染的。它也无权访问 edit 操作范围内的任何对象。

为了处理请求,您的 update 操作代码需要重新初始化它需要的所有对象,主要是 @user 对象。

如果当前操作不知道之前发生了什么,它怎么知道应该将哪个用户记录转到 @user 变量?它可以通过电子邮件找到用户,这就是您在参数中提供它的原因。您的 edit 操作代码使其可用于下一个请求。

从您的 edit 动作来看,您的控制器中应该已经有一些方法可以在执行动作代码之前初始化 @user 对象。寻找 before_action 回调。

该方法可能通过 params 中传递的电子邮件查找用户。当动作本身被执行时,@user 对象已经存在,因此它似乎 Rails 不知何故知道如何获取它。它不会,您的控制器代码使它发生。

因此您需要隐藏标签来在操作之间传递上下文。还有其他方法可以做到这一点,比如使用 sessioncookies,但这种方法可能是最简单的。