【问题标题】:Form_For New Related ModelForm_For 新的相关模型
【发布时间】:2011-08-06 09:00:41
【问题描述】:

所以在我的应用程序中,我有一个 Person 模型,其中 has_many 描述。我现在需要在每个人的显示页面上创建一个表格,以便为该人添加新的描述。到目前为止,我有以下表格。但是,它不会将人的 ID 传递给描述创建操作。

表格

<%= form_for @person.descriptions.new do |f| %>

    <fieldset class="input">
        <%= f.label :name %>
        <%= f.text_field :name %>
    </fieldset>

    <fieldset class="input">
        <%= f.label :description %>
        <%= f.text_area :description %>
    </fieldset>

    <fieldset class="button">
        <%= f.submit "Post" %>
    </fieldset>

<% end %>

参数通过

{"utf8"=>"✓",
 "authenticity_token"=>"OQY8Xcfm6wtWHXp9GjFfM4ICX79smPwyvfVcaDn+C2s=",
 "description"=>{"name"=>"Test",
 "description"=>"This is a test"},
 "commit"=>"Post"}

【问题讨论】:

    标签: ruby-on-rails forms associations belongs-to


    【解决方案1】:

    在人员控制器的显示操作中创建描述对象,方法是将其构建到人员对象而不是表单中

    所以在显示动作中你会有

      #You probably have something like this already
      @person = Person.find(params[:id])
      #Now do this
      @description = @person.descriptions.build
    

    然后更改您的 form_for 以使用 @description

    这是一个不太理想的解决方案,因为您会发现此帖子返回到描述控制器,但您可以更改 form_for 中的 url

    此外,依靠 ID 来查找控制器操作中的记录是错误的。有人可以轻松更改浏览器中的代码以在 person 对象上使用不同的 ID。你应该非常仔细地考虑这一点。很多时候你会发现一个人只被允许编辑他们自己的描述,因此在处理这种情况时,基于当前登录用户的 current_user 对象经常用于显示和编辑操作。

    更新

    忘了提一下,当表单被发送回控制器时,您会在以与上述相同的方式保存之前为该人构建描述。因此,您将需要找到不应该再次依赖 ID 的人,只使用当前登录的用户。 希望有帮助

    ++ 更新 2 ++

    除此之外,我认为您确实需要使用 form_for @person 然后使用 fields_for :description 并将 Accept_nested_attributes_for :description 添加到您的 Person 模型中,这样您最终会得到这样的结果。

    <%= form_for @person do |f| %>
      <%= f.fields_for :description do |desc_builder|
        <fieldset class="input">
            <%= desc_builder.label :name %>
            <%= desc_builder.text_field :name %>
        </fieldset>
    
        <fieldset class="input">
            <%= desc_builder.label :description %>
            <%= desc_builder.text_area :description %>
        </fieldset>
      <%end%>
      <fieldset class="button">
          <%= f.submit "Post" %>
      </fieldset>
    
    <% end %>
    

    在您的 Person 模型中添加以下内容

    class Person < ActiveRecord::Base
    #... Add this line
        accepts_nested_attributes_for :descriptions, :reject_if => proc { |attributes| attributes['name'].blank? && attributes['description'].blank? }
    #... ---
    

    然后在人员控制器的显示操作中,只需按照上述说明构建描述

      #You probably have something like this already
      @person = Person.find(params[:id])
      #Now do this
      @description = @person.descriptions.build # add an if @person.descriptions.empty? here if you only ever want one description per person.
    

    上述代码将安排您的表单回传到人员控制器更新操作,该操作将自动创建描述记录。根本不需要更改任何其他控制器代码。

    这是因为 form_for @person 将安排 url 去更新操作,因为它已经是一个现有的人

    fields_for 将安排描述字段嵌套在更新操作获取的 params 哈希中的人员字段中。

    最后,accepts_nested_attributes_for 将安排根据需要自动创建或更新描述记录。 :reject_if => proc 对其进行排列,以便如果名称和描述均为空白,则不会创建新记录。您显然可以包含更多字段、更改条件或不包含所有字段。任何适合您的要求。

    希望这会让你感动。 如果您觉得有需要,您可以在此处找到有关 Accepts_nested_attributes 的更多信息 http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

    【讨论】:

    • 同意,这是一个更好的方法。
    • 只是为了澄清,这不是当前用户描述他们的自我。任何访客都可以描述这个人。所以我不确定这是否会影响您发布的解决方案
    • 不,它不会影响答案。你试过了吗?但是您确定要允许 Joe 更改对 Fred 的描述吗?
    • 没有。将描述视为 cmets,将人员视为帖子。每个人都可以有任意数量的描述,任何人都可以添加。
    • 好吧,什么没用?如果您可以进一步解释,那么我可以给您解决方案
    【解决方案2】:

    确保您在 params 哈希中获得 @person 对象的 ID 的最简单方法是将其添加为表单上的隐藏字段,例如:

    hidden_field(:person, :id)
    

    另外,与其在视图中创建新描述,不如在 Persons 控制器中创建模板描述。

    【讨论】:

    • 你永远不应该在视图中依赖 id。它们很容易被恶意用户更改
    • @jamesw 为什么这很重要?是否可以创建新的“描述”并将其分配给“人”的身份验证将由控制器在服务器端处理......还是我错过了什么?
    • 隐藏字段和可见字段同样容易受到浏览器中用户操作的影响。您不能期望将与最初提供的相同的用户 ID 发送回控制器。试想一下,如果恶意用户在发回表单之前更改浏览器中的 id 会造成多大的破坏,甚至只是一个玩弄的人
    • @AJP - 以上内容包含在使用 Rails 进行敏捷 Web 开发中,如果您想了解更多信息,您会发现这是一个很好的资源
    • @jamesw 啊,那么这就是垃圾:stackoverflow.com/questions/10832748/… 我有 ed.4,所以我会在那里看看,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多