Rails 4 餐厅订单系统 ActiveRecord::RecordNotFound 在 ItemsController#create
Rails 4 Restaurant order system ActiveRecord::RecordNotFound in ItemsController#create
我正在创建一个简单的餐厅点餐系统,菜单和它的项目之间有一对多的关系。一个菜单有很多项目。为了简单起见,它不是多对多。
我可以很好地创建菜单,但希望能够在菜单显示操作中添加和显示该菜单的菜单项。
菜单显示操作显示正常,但当我尝试添加新菜单项时出现以下错误:
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
编辑:我听从了杜恩的建议并研究了嵌套资源,这确实是一种更好的方法。更新后的代码如下:
routes.rb
resources :menus do
resources :items
end
menus_controller.rb
def show
@menu = Menu.find(params[:id])
@items = @menu.items
end
items_controller.rb
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
还有菜单
show.html.erb
<%= 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>
您 post 是要“/post”还是 "post/[:id]"?
@menu = Menu.find(params[:id])
如果不传递 id,将找不到任何东西。 id 可以来自 URL 参数,但这意味着您应该将请求发送到 "/post/[:menuid].
您可以使用 gem https://github.com/charliesome/better_errors 在控制器级别调试您的程序并在那里执行 rails 控制台。只需在你的控制器中输入 "fail" 然后你就会有一个命令行界面,你可以在其中检查你的参数值并确保它包含 id 并在那里玩控制台。
我现在已经解决了。感谢 better_errors 我能够更好地理解发生了什么。
我在 menus_controller.rb 中实现了 aaron 的表演动作。
def show
@item = Item.new
@menu = Menu.includes(:items).find(params[:id])
end
我需要一种将菜单 ID 传递到 menu_id 字段的方法,因此我在传递当前 @[=27= 的 table 或 show.html.erb 中添加了一个隐藏字段] 进入 :menu_id 字段。
<%= f.hidden_field :menu_id, :value => @menu.id %>
我在网上了解到,通过隐藏字段传递值并不是一个好主意。
然后在 Items Controller 的创建操作中,我能够像往常一样使用项目对象中的菜单 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
感觉有点像黑客,所以愿意接受有关如何改进的建议。
在这种情况下(特别是如果您的项目不存在于菜单之外)我可能会做的是使用嵌套资源:
http://guides.rubyonrails.org/routing.html#nested-resources
http://railscasts.com/episodes/139-nested-resources(有点过时,但仍然是一个不错的基础)
以下是一些可以帮助您朝这个方向指出的更改。
config/routes.rb
resources :menu do
resources :items
end
现在我们的 url 看起来像
/menu/:menu_id/items/
所以我们需要调整items_controller通过查看:menu_id
来获取菜单,我们不再需要隐藏字段了。我把它放在 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 将生成正确的路径。
menus/show.html.erb
<%= form_for [@menu,@item] do |f| %>
我正在创建一个简单的餐厅点餐系统,菜单和它的项目之间有一对多的关系。一个菜单有很多项目。为了简单起见,它不是多对多。
我可以很好地创建菜单,但希望能够在菜单显示操作中添加和显示该菜单的菜单项。
菜单显示操作显示正常,但当我尝试添加新菜单项时出现以下错误:
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
编辑:我听从了杜恩的建议并研究了嵌套资源,这确实是一种更好的方法。更新后的代码如下:
routes.rb
resources :menus do
resources :items
end
menus_controller.rb
def show
@menu = Menu.find(params[:id])
@items = @menu.items
end
items_controller.rb
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
还有菜单
show.html.erb
<%= 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>
您 post 是要“/post”还是 "post/[:id]"?
@menu = Menu.find(params[:id])
如果不传递 id,将找不到任何东西。 id 可以来自 URL 参数,但这意味着您应该将请求发送到 "/post/[:menuid].
您可以使用 gem https://github.com/charliesome/better_errors 在控制器级别调试您的程序并在那里执行 rails 控制台。只需在你的控制器中输入 "fail" 然后你就会有一个命令行界面,你可以在其中检查你的参数值并确保它包含 id 并在那里玩控制台。
我现在已经解决了。感谢 better_errors 我能够更好地理解发生了什么。
我在 menus_controller.rb 中实现了 aaron 的表演动作。
def show
@item = Item.new
@menu = Menu.includes(:items).find(params[:id])
end
我需要一种将菜单 ID 传递到 menu_id 字段的方法,因此我在传递当前 @[=27= 的 table 或 show.html.erb 中添加了一个隐藏字段] 进入 :menu_id 字段。
<%= f.hidden_field :menu_id, :value => @menu.id %>
我在网上了解到,通过隐藏字段传递值并不是一个好主意。
然后在 Items Controller 的创建操作中,我能够像往常一样使用项目对象中的菜单 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
感觉有点像黑客,所以愿意接受有关如何改进的建议。
在这种情况下(特别是如果您的项目不存在于菜单之外)我可能会做的是使用嵌套资源:
http://guides.rubyonrails.org/routing.html#nested-resources
http://railscasts.com/episodes/139-nested-resources(有点过时,但仍然是一个不错的基础)
以下是一些可以帮助您朝这个方向指出的更改。
config/routes.rb
resources :menu do
resources :items
end
现在我们的 url 看起来像
/menu/:menu_id/items/
所以我们需要调整items_controller通过查看:menu_id
来获取菜单,我们不再需要隐藏字段了。我把它放在 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 将生成正确的路径。
menus/show.html.erb
<%= form_for [@menu,@item] do |f| %>