【问题标题】:How do you create a form without a new template that is submitted from the /show.html.erb page如何在没有从 /show.html.erb 页面提交的新模板的情况下创建表单
【发布时间】:2015-11-12 01:47:08
【问题描述】:

我有这个应用程序,我正在尝试使用谱系表添加狗家庭关系(狗 A 是狗 B 的兄弟姐妹)。但是,我在制作能够实现这一目标的表单时遇到问题。 This is how my form looks like at the moment.

您可以在狗的个人资料页面中看到表单加载,用户可以选择他的一只狗并创建关系。这是从views/pedigrees/_form.html.erb 在views/dog/show.html.erb 页面中呈现的表单代码:

<%= form_for(@pedigree, url: new_pedigree_path, html: {method: :post}) do |d| %>
    Select your dog:
    <%= d.collection_select(:dog_id, @dogs,:id, :dname, :prompt => "Select your dog") %>
    <br>
    Select your dog relation to the dog from this profile:
    <%= select_tag(:relation_name, options_for_select([['Sibling', 1], ['Parent', 2], ['Grandparent', 3],
                                                       ['Great-grandparent', 4], ['Child', 5], ['Grandchild', 6], ['Great-grandchild', 7]])) %>
    <br>
    <%= d.submit 'Add Relation' %>
<% end %>

我在生成的源代码中得到以下内容:

 <form class="new_pedigree" id="new_pedigree" action="/pedigree/new" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="authenticity_token" value="RYOjO10gUvVUQkRaqyum8wB0VJrTwm8MQ6WxIJ3eM4ukP2zHHDECFaT8UUYytSv2OGBUGhvK4k3fwOt+xDfabA==" />

当我单击按钮提交表单时,我收到以下错误:

Missing template pedigree/new, application/new with...

如何操作 form_for 以便在不需要新的表单模板的情况下呈现谱系关系?以及如何在按下提交按钮时调用#create 方法?谢谢。

【问题讨论】:

    标签: ruby-on-rails forms ruby-on-rails-4


    【解决方案1】:

    为了避免硬编码"/pedigrees" url,表单部分的第一行应该是

    <%= form_for(@pedigree, url: pedigrees_path, html: {method: :post}) do |d| %>
    

    您需要了解newcreate 操作(及其关联的路由/路径/url)之间的区别。 new_pedigree_path 不是您想要实际创建新记录时使用的路径。 (new_pedigree_path 仅用于获取表单。)实际上,创建新谱系是通过对pedigrees_path 的 POST 请求完成的。

                       Controller Action   HTTP Verb       Path Helper          Path
    Get a form
    for making a              new            GET          new_pedigree_path     /new_pedigree
    new relationship 
    
    Send data about
    the new relationship     create          POST          pedigrees_path       /pedigrees
    to the server; create
    the new record. 
    

    【讨论】:

    • 谢谢。我已将硬编码的 /pedigrees 更改为您在上面的路径。
    【解决方案2】:

    既然你是新人,让我添加一些上下文。


    您当前在dogs#show 页面上调用表单。这确实意味着您必须硬编码url - 传递@pedigree 变量应该为Rails 提供将表单提交到pedigrees#create 所需的信息:

    <%= form_for @pedigree do |d| %>
        Select your dog:
        <%= d.collection_select :dog_id, @dogs,:id, :dname, prompt: "Select your dog" %>
    
        Select your dog relation to the dog from this profile:
        <%= select_tag(:relation_name, options_for_select [['Sibling', 1], ['Parent', 2], ['Grandparent', 3],
                                                           ['Great-grandparent', 4], ['Child', 5], ['Grandchild', 6], ['Great-grandchild', 7]]) %>
        <%= d.submit 'Add Relation' %>
    <% end %>
    

    如果您设置了 @pedigree 变量,则应该将表单发送到 pedigrees#createpedigrees#update(取决于您是使用 Pedigree.new 还是 Pedigree.find 设置变量)。

    由于您通过部分调用表单,我会强烈建议在其中仅使用 本地 变量:

    #app/controllers/dogs_controller.rb
    class DogsController < ApplicationController
       def show
          @dog = Dog.find params[:id]
          @pedigree = ...
       end
    end
    
    #app/views/dogs/show.html.erb
    <%= render "pedigrees/form", locals: {pedigree: @pedigree} %>
    
    #app/views/pedigrees/_form.html.erb
    <%= form_for pedigree ...
    

    一开始这可能看起来效率低下,但是您必须记住,partials 应该在您的应用程序的任何位置都可用。在其中使用@instance_variables 实际上是antipattern 的一半!


    其他一些注意事项:

    1.永远不要使用 HTML 进行“样式化”

    我看到人们使用 &lt;br&gt;&lt;p&gt; 在 HTML 中创建换行符。

    虽然这“有效”,但它是不正确的。事实上,它是彻头彻尾的破坏性的(尤其是当您处理更大的应用程序时)。

    HTML应该被视为标记(格式); CSS 是你需要的样式:

    <%= form_for @pedigree do |d| %>
       <%= d.text_field :name %>
       <%= d.text_field :type %>
    <% end %>
    

    这就是您的 HTML 的外观,然后您可以使用 following CSS to style it:

    #app/assets/stylesheets/application.css
    form input {
       display: block;
       margin: 3px 0;
    }
    

    如果您出于正当原因需要换行符(也许您正在使用列表或其他东西),那么请务必使用&lt;br&gt; - 但切勿使用它来制造边距/填充的错觉。

    仅此而已,它会用响应式界面等搞乱您的样式。

    -

    2。多对多

    我不知道你的 Rails 水平,如果这对你来说太简单了,请见谅。

    如果您使用many-to-many 关系,特别是has_many :through,我相信您可以大大改善这一点:

    #app/models/dog.rb
    class Dog < ActiveRecord::Base
       has_many :pedigrees
       has_many :relations, through: :pedigrees
    end
    
    #app/models/pedigree.rb
    class Pedigree < ActiveRecord::Base
       belongs_to :dog
       belongs_to :relation
    end
    
    #app/models/relation.rb
    class Relation < ActiveRecord::Base
       has_many :pedigrees
       has_many :dogs, through: :pedigrees
    end
    

    这将允许您通过单个调用填充 @dog.pedigrees@dog.relations。因此,您不必使用create / edit 新的“谱系”记录,而只需使用dog

    #app/controllers/dogs_controller.rb
    class DogsController < ApplicationController
       def show
          @dog = Dog.find params[:id]
       end
    
       def update
    
       end
    
       private
    
       def dog_params
          params.require(:dog).permit(:name, :relation_ids)
       end
    end
    

    这将允许您使用以下内容:

    #app/views/dogs/show.html.erb
    <%= form_for @dog do |f| %>
       <%= f.text_field :name %>
       <%= f.collection_select :relation_ids, Relation.all, :id, :name %>
       <%= f.submit %>
    <% end %>
    

    这应该允许您选择您的狗拥有的各种“关系”,自动创建 Pedigree 记录。

    【讨论】:

      【解决方案3】:

      我可以通过以下方式解决这个问题:

      我不得不对 form_for 进行硬编码

      <%= form_for(@pedigree, url: "/pedigrees", html: {method: :post}) do |d| %>
      

      我的路线文件也有错误。而不是资源 :pedigree y 有资源 :pedigree。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-12
        • 2018-11-10
        • 2017-08-03
        • 2016-07-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多