用于路由的通用 solution/pattern 和具有丰富多对多关联的 views/forms (Rails)

Generic solution/pattern for routing and views/forms with rich many to many associations (Rails)

从 Rails 4 开始,目前我正在为常见的 CRUD 模式而苦苦挣扎。找到了一些资源,但就是不明白。

让我们假设一个产品模型、一个供应商模型和丰富的多对多价格关联。许多供应商以不同的价格出售给定的产品。每个供应商销售许多产品。丰富的多对多连接模型的名称是"costprices"。这最终出现在以下三个模型中。

型号

class Product < ActiveRecord::Base
    has_many :costprices
    has_many :suppliers, through: :costprices
end

class Supplier < ActiveRecord::Base
    has_many :costprices
    has_many :products, through: :costprices
end

class Costprice < ActiveRecord::Base
    belongs_to :product
    belongs_to :supplier
end

供应商提供成百上千种产品。一种产品由一个或一些(两个、三个、四个)供应商提供。对我来说,自然的方式似乎是将 "add a supplier with his cost price" 功能添加到某些产品形式,或者像我在这里所做的那样,添加到产品展示页面。此页面可能如下所示:

products/show 查看

<p>
  <strong>Name:</strong>
  <%= @product.name %>
</p>

<%= link_to 'Edit', edit_product_path(@product) %> |
<%= link_to 'Back', products_path %>

<!-- List all suppiers offering this product -->
<table>
  <% @product.costprices.each do |cp| %>
    <tr>
      <td>
        <%= link_to edit_product_costprice_path(cp, @product) do %>
          EDIT
        <% end %>
      </td>
      <td>
        <%= link_to product_costprice_path(cp, @product) do %>
          SHOW
        <% end %>
      </td>
      <td><%= cp.supplier.name %></td>
      <td><%= number_to_currency(cp.price) %></td>
    </tr>
  <% end %>
</table>

<%= link_to new_product_costprice_path(@product) do %>
  NEW
<% end %>

costprices/new 视图 (_form.html.erb)

new和edit使用。对于新的,这仍然行不通。必须添加一些逻辑来添加供应商 ID。这适用于编辑并正确更新价格。

<%= form_for [@product, @costprice] do |f| %>
  <div class="field">
    <%= f.label :price %><br>
    <%= f.text_field 'price', :value => number_to_currency(@costprice.price) %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

link_to 助手假定此嵌套资源:

routes.rb

  resources :suppliers
  resources :products do
    resources :costprices
  end

此时,一切正常,除了 "NEW" 操作。可以单击 SHOW 操作和 EDIT 操作。单击新操作会导致 "undefined method costprices_path" 错误。

错误描述

Showing /home/ubuntu/workspace/app/views/costprices/_form.html.erb where line #1 raised: undefined method `costprices_path' for #<#:0x007f763dca5160>

Extracted source (around line #1):

<%= form_for [@product, @costprice] do |f| %>

我明白,这个资源不会生成方法 costprices_path。但是他们生成了一个方法 new_product_costprice_path (product_id) 不应该调用这个方法点击新建? URL 对我来说似乎还可以 /products/1/costprices/new

主要是对这个错误的解释和正确的解决方法感兴趣。我以 "generic solution/pattern" 为首 post。除了这个错误,我仍然不确定如何设计一个舒适的用户界面(表单)来处理丰富的多对多关联/嵌套表单。如果有人有解决此类模式的好链接,请分享。

里面有新动作costprice_controller

def new
  @costprice = Costprice.new
end

此错误可能是由 new.html.erb 或控制器的新操作引起的,请检查您是否将 costprices_path 添加到新操作的 new.html.erbredirect_to @costprices 中。

如果您不熟悉 m-to-m 表单,可以尝试 simple_form,它非常易于使用,因为它会为您处理 m-to-m,请查看 f.association 来自 simple_form.

韦恩带我去了正确的方向。应该 post 编辑了我所有的源代码。

costprices_controller我忘记为新动作设置产品了。

错误:before_action :set_product, only: [:show, :edit, :update, :destroy]

正确:before_action :set_product, only: [:new, :show, :edit, :update, :destroy]

我(Rails 的新手)从这个练习中学到了什么?

不要盲目依赖"rails magic",直到你真正了解幕后的一切。那是学习的重头戏rails。希望(我仍然不是他们)之后依靠这个 "magic" 来节省大量时间一次又一次地编写样板代码行会很有趣。

首先,我什至不知道哪些信息对确定问题很重要。所以我不得不编辑三四次这个 post 以提供缺失的信息。也就是说,我对 rails 路由有一些误解。我在幕后假设了太多"magic"。我认为 url 会被分析,并且会神奇地调用正确的命名路由。这只对了一半。 <%= form_for [@product, @costprice] do |f| %> 并不是真正的魔法,它主要负责调用正确的命名路由(它不是 url)。如果未设置 @product(没有人为我设置 @product,我必须在控制器中执行此操作)此构造等于 <%= form_for [@costprice do] |f| %>,这会导致对命名路由的无效调用 costprices_path,这当然不存在。