我正在创建一个简单的餐厅订购系统,菜单与其项目之间存在一对多的关系。一个菜单有很多项目。为简单起见,它不是很多。
我可以很好地创建菜单,但希望能够在菜单显示操作中添加和显示该菜单的菜单项。
菜单显示操作显示正常但是当我尝试添加新菜单项时,我收到以下错误:
ActiveRecord::RecordNotFound in ItemsController#create
Couldn't find Menu with 'id'=
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
以下是来自终端的查询:
Started POST "/items" for ::1 at 2015-01-11 16:09:44 +0000
Processing by ItemsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"***", "item"=>{"name"=>"Test", "price"=>"23", "course"=>"Main", "vegetarian"=>"1", "allergy"=>""}, "commit"=>"Add item"}
Menu Load (0.3ms) SELECT `menus`.* FROM `menus` WHERE `menus`.`id` = NULL LIMIT 1
Completed 404 Not Found in 8ms
编辑:我遵循了doon的建议并研究了嵌套资源,这确实是一种更好的方法。更新后的代码如下:
resources :menus do
resources :items
end
def show
@menu = Menu.find(params[:id])
@items = @menu.items
end
def create
@menu = Menu.find(params[:menu_id])
@item = @menu.items.create!(item_params)
if @item.save
flash[:success] = "Item added!"
redirect_to @menu
else
flash[:danger] = "Errors found!"
redirect_to @menu
end
end
private
def item_params
params.require(:item).permit(:name, :price, :course, :vegetarian, :allergy, :menu_id)
end
和菜单
<%= link_to "<< Back", menus_path, data: { confirm: back_message } %>
<h1><%= @menu.name %> menu</h1>
<center><button id="toggleButton" class="btn btn-sm btn-info">Show/Hide Add Item Form</button></center>
<br>
<div class="row">
<div class="col-xs-offset-3 col-xs-6 toggleDiv hideDiv">
<%= form_for [@menu, Item.new] do |f| %>
<table class="table table-condensed table-no-border">
<tr>
<th scope="row" class="col-xs-2">Name:</th>
<td class="col-xs-10"><%= f.text_field :name %></td>
</tr>
<tr>
<th scope="row">Price:</th>
<td><%= f.text_field :price %></td>
</tr>
<tr>
<th scope="row">Course:</th>
<td><%= f.select(:course, options_for_select([['Starter', 'Starter'], ['Main', 'Main'], ['Dessert', 'Dessert'], ['Drink', 'Drink']]), prompt: "Please select...", class: 'form-control') %></td>
</tr>
<tr>
<th scope="row">Vegetarian:</th>
<td><%= f.check_box :vegetarian %></td>
</tr>
<tr>
<th scope="row">Allergy:</th>
<td><%= f.text_field :allergy %></td>
</tr>
<tr><td colspan="2"><%= f.submit "Add item", class: "btn btn-sm btn-success col-xs-offset-4 col-xs-4" %></td></tr>
</table>
<% end %>
</div>
</div>
<table class="table table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Course</th>
<th>Vegetarian</th>
<th>Allergy</th>
</tr>
</thead>
<tbody>
<% @items.each do |item| %>
<tr>
<td><%= item.name %></td>
<td><%= number_to_currency(item.price, unit: "£") %></td>
<td><%= item.course %></td>
<td><%= item.vegetarian %></td>
<td><%= item.allergy %></td>
</tr>
<% end %>
</tbody>
</table>
答案 0 :(得分:0)
您是否发布到“/ post”或“post / [:id]”?
@menu = Menu.find(params[:id])
如果你没有传递id,就找不到任何东西。 id可以来自URL参数,但这意味着您应该将您的请求发送到“/ post / [:menuid]。
您可以使用gem https://github.com/charliesome/better_errors在控制器级调试程序并在那里执行rails console。只需在您的控制器中输入“fail”,然后您将拥有一个命令行界面,您可以在其中检查您的params值并确保它包含id并在那里使用控制台。
答案 1 :(得分:0)
我现在已经解决了。感谢better_errors,我能够更好地了解发生了什么。
我在aaron的menus_controller.rb中实现了show动作。
def show
@item = Item.new
@menu = Menu.includes(:items).find(params[:id])
end
我需要一种方法将菜单ID传递给menu_id字段,因此我在表格中添加了一个隐藏字段,或者将show.html.erb中的当前@ menu.id传递到:menu_id字段。
<%= f.hidden_field :menu_id, :value => @menu.id %>
我在网上看到,通过隐藏字段传递值并不是一个好主意。
然后在项目控制器的创建操作中,我能够像往常一样使用项目对象中的菜单ID重定向到现有的节目视图。
def create
@item = Item.new(item_params)
if @item.save
redirect_to menu_path(@item.menu_id)
else
redirect_to menu_path(@menu.menu_id)
end
end
对于如何改进的建议,感觉有点像黑客。
答案 2 :(得分:0)
在这种情况下我可能会做的事情(特别是如果您的项目不存在于菜单之外)是使用嵌套资源:
http://guides.rubyonrails.org/routing.html#nested-resources
http://railscasts.com/episodes/139-nested-resources(有点陈旧,但仍然是一个不错的基础)
以下是一些让您指向此方向的更改。
config / routes.rb
resources :menu do
resources :items
end
现在我们的网址看起来像
/menu/:menu_id/items/
所以我们需要通过查看:menu_id
来调整items_controller来获取菜单,我们不再需要隐藏字段了。我将它放在before_action
中,因为控制器中的每个方法都将通过关联构建。
<强> items_controller.rb 强>
class ItemsController < ApplicationController
before_action :find_menu
...
def create
@item = @menu.items.new(item_params)
if @item.save
redirect_to @menu, notice: 'item added'
else
redirect_to @menu, warning: 'item failed'
end
end
...
private
def find_menu
@menu = Menu.find(params[:menu_id])
end
end
如果要在菜单上显示,我们需要显示一个新项目。
<强> menus_controller.rb 强>
def show
@menu = Menu.find(params[:id])
@item = @menu.items.new
end
然后我们需要在menus/show
视图中使用嵌套资源。通过传入菜单和项目的数组,rails将生成正确的路径。
<强>菜单/ show.html.erb 强>
<%= form_for [@menu,@item] do |f| %>