【问题标题】:how form_for works in Ruby on Railsform_for 如何在 Ruby on Rails 中工作
【发布时间】:2013-12-10 16:57:17
【问题描述】:

我是新手。我已阅读 API 文档。但是还是不明白 form_for 是怎么工作的。

首先,来自 Ruby on Rails 教程,关注按钮的表单:

<%= form_for(current_user.relationships.build(followed_id: @user.id)) do |f| %>
  <div><%= f.hidden_field :followed_id %></div>
  <%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>

我理解current_user.relationships.build(followed_id: @user.id) 表示新记录。但是为什么我们不能只提交和触发控制器来保存没有hidden_​​field的记录呢?为什么我们还需要将followed_id 发布到控制器?

其次,在 hidden_​​field 中,:followed_id 是什么意思?我相信这是一个符号,即它仅等于“followed_id”而不是 id 的变量。如果这只是输入字段的名称,那么它的值是多少?

第三,form_for 怎么知道提交应该发到哪里? form_for 将发布到哪个控制器和操作?

第四,params 如何与form_for 一起工作?在这种跟随按钮的情况下,params[:relationship][:followed_id] 将在控制器中返回@user.id。它怎么知道第一个哈希属性是:relationship?我们既没有提到form_for :relationship,也没有提到form_for @relationship。

我知道这些问题可能很愚蠢,但我真的被困住了。任何帮助将不胜感激。

【问题讨论】:

    标签: ruby-on-rails rails-activerecord params form-for form-helpers


    【解决方案1】:

    我没有做那个教程,所以如果我不直接回答你的问题,请注意。

    看看rails guide about form helpers,它详细解释了你的问题,可能比我更清楚。

    form_for(path/to/your/controller/action) 是一种辅助方法,用于创建带有 POST 或 GET 请求的 url 路径的 HTML 表单元素。根据您在控制器操作中要求执行的操作,帮助程序知道它应该是新记录还是更新记录。

    例如 在你的控制器中

    def new
      @my_instance_variable = Myobject.new
    end
    

    在你看来 new.html.erb

    <%= form_for @my_instance_variable do |f| %>
    ...
    <% end %>
    

    在你的情况下,逻辑是直接写在助手中的,你也可以直接写

    <%= form_for Myobject.new %>
    

    两者都会产生以下 html

    <form action="/myobjects/new" method="post">
    # in this case rails knows its a `POST` request because the route new action
    # is by default a POST request. You can check these routes and their request 
    # by using `rake routes` in terminal.
    

    然后hidden_field 是另一个包含值的助手,在您的情况下,@user.id 将作为参数传递,然后保存为给定对象的创建或更新操作。它没有在隐藏字段标记中添加值的原因是因为您已经有一个知道用户 id 的模型关联,因为表单的链接使用带有用户 id 的构建方法。

    最后一部分你需要了解form_for链接逻辑

    current_user.relationships 
    # implies the association of the current_user has many relationships 
    current_user.relationships.build 
    # .build is a method to populate a new object that can be save as a new record
    # means you will create a new relationship record by populating the user_id 
    # column with the current_user.id and the followed_id with the target @user.id
    

    【讨论】:

    • 非常感谢。这是一个很好的答案。但我仍然很困惑。首先,如果“form_for”之后的输入是路径。那么 form_for Myobject.new 和 Myobject.build 应该指导我们行动“new”和“build”吗?但相反,它引导我采取行动“创造”。只要我了解它现在如何将我重定向到正确的控制器,这无论如何都不是什么大问题。
    • 在form_for current_user.relationships.build(followed_id: @user.id)中,form_for只需要第一部分current_user.relationships.build。这意味着最后一部分(followed_id: @user.id) 不是必需的,对吗?或者它是否起到一些帮助 hidden_​​field 价值的作用?我想我仍然没有得到第一个和第二个问题的答案。也许我应该花更多时间阅读您首先建议的 Rails 指南。谢谢
    • 你需要告诉rails你想用适当的信息构建什么,所以是的,你需要最后一部分。存在模型关联时使用 build 方法。您可以查看 [api] (api.rubyonrails.org/classes/ActiveRecord/Associations/…)。如果您不添加@user.id,那么followed_id 将返回nil。
    • 是的,它们最终会导致创建操作,这就是您想要的;) .build 方法已经使用信息构建了对象,您只需要保存它,这就是创建操作的用途.新操作只是一个页面,您可以在其中拥有一个表单并让用户编写信息,然后在提交时将重定向到他创建操作并保存,除非验证失败。
    【解决方案2】:

    阅读 The Rails 4 Way 一书后,我现在对 form_for 有了更好的理解。

    11.9.1.5 显示现有值。 如果您正在编辑 Person 的现有实例,则该对象的属性值将被填充到 表格。

    这样,当我们使用current_user.relationships.build(followed_id: @user.id)建立关系时,就会创建关系实例并获得属性followed_id。因此,我们实际上不是“创建”关系,而是通过表单编辑关系。

    Rails 将知道您正在编辑并将现有属性“followed_id”加载到该字段。因此,我们不需要像使用f.hidden_field :followed_id, value: @user.id 那样为字段赋值。

    我们必须使用字段将followed_id传递给params的原因是因为HTTP服务器是无状态的,它不记得你正在与哪个用户创建关系。

    编写form_for current_user.relationships.build(followed_id: @user.id) 而不是标准的form_for @relationship 的优点之一是我们不需要像这样在控制器中编写“if-condition”:

    unless current_user.nil?
      if current_user.following?(@user)
        @relationship=current_user.relationships.find_by(followed_id: @user.id)
      else
        @relationship=current_user.relationships.new
      end
    end
    

    params 将被发送到属于实例模型的控制器。 "post" 方法将执行创建操作,"delete" 将执行销毁,"patch" 将执行更新等。

    params 将是一个散列,其中包含另一个散列,例如 { instace_name: { field_1: value1, field_2:value2 } } 或以下完整参数

       Parameters: {"utf8"=>"✓",
         "authenticity_token"=>"afl+6u3J/2meoHtve69q+tD9gPc3/QUsHCqPh85Z4WU=",
         "person"=>{"first_name"=>"William", "last_name"=>"Smith"},
         "commit"=>"Create"}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-19
      相关资源
      最近更新 更多