本文介绍了has_many:通过创建子元素after_save-> ActionView :: Template :: Error的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有三个模型:清单,食物和数量.列表和食物通过has_many:through通过数量关联.模型关联正在执行我想要的操作,但是当我进行测试时,会出现错误.

I have three models: List, Food, and Quantity. List and Food are associated through Quantity via has_many :through. The model association is doing what I want, but when I test, there is an error.

test_valid_list_creation_information#ListsCreateTest (1434538267.92s)
ActionView::Template::Error:         ActionView::Template::Error: Couldn't find Food with 'id'=14
app/views/lists/show.html.erb:11:in `block in _app_views_lists_show_html_erb__3286583530286700438_40342200'
app/views/lists/show.html.erb:10:in `_app_views_lists_show_html_erb__3286583530286700438_40342200'
test/integration/lists_create_test.rb:17:in `block (2 levels) in <class:ListsCreateTest>'
test/integration/lists_create_test.rb:16:in `block in <class:ListsCreateTest>'
app/views/lists/show.html.erb:11:in `block in _app_views_lists_show_html_erb__3286583530286700438_40342200'
app/views/lists/show.html.erb:10:in `_app_views_lists_show_html_erb__3286583530286700438_40342200'
test/integration/lists_create_test.rb:17:in `block (2 levels) in <class:ListsCreateTest>'
test/integration/lists_create_test.rb:16:in `block in <class:ListsCreateTest>'

我的目标是每次创建列表时都创建一个新的数量(与该列表相关联).每个数量都有数量,food_id和list_id.

My aim is to create a new Quantity (associated with that list) each time a list is created. Each Quantity has amount, food_id, and list_id.

  • list_id应该等于刚刚创建的列表的ID.
  • food_id应该等于已经存在的随机食物的ID.
  • 金额应为随机整数.

在错误中,通过从1到Food.count中随机选择一个数字来生成数字14(具有'id'= 14的食物).Food.count等于测试/灯具/食物中食物对象的数量. yml,所以至少在我运行Food.count时,这些食物是绝对可以识别的,那么为什么不存在'id'= 14的食物呢?

In the error, the number 14 ("Food with 'id'=14) is generated by randomly selecting a number from 1 to Food.count. Food.count equals the number of food objects in test/fixtures/foods.yml, so the foods are definitely recognized, at least when I run Food.count. So why wouldn't food with 'id'=14 exist?

我认为Lists控制器,固定装置或集成测试有问题.导致测试失败的任何因素似乎都不会影响性能(一切都可以在控制台和服务器/用户界面中使用),但是我试图理解TDD并编写良好的测试,因此,我将不胜感激.

I believe there is something wrong with either the Lists controller, the fixtures, or the integration test. Whatever is causing the test to fail doesn't seem to affect performance (everything works in the console and server/user interface), but I am trying to understand TDD and write good tests, so I will appreciate any guidance.

列表模型:

class List < ActiveRecord::Base
  has_many :quantities
  has_many :foods, :through => :quantities
  validates :days, presence: true
  validates :name, uniqueness: { case_sensitive: false }

  after_save do   
    Quantity.create(food_id: rand(Food.count), list_id: self.id, amount: rand(6)) 
  end
end

数量固定装置:

one:
  food: grape
  list: weekend
  amount: 1
two:
  food: banana
  list: weekend
  amount: 1

注意:数量固定装置以前的组织方式如下...

Note: the Quantities fixture was previously organized as follows ...

one:
  food_id: 1
  list_id: 1
  amount: 1

...似乎没什么区别.

... and it seems to make no difference.

lists_create集成测试:

lists_create integration test:

require 'test_helper'
class ListsCreateTest < ActionDispatch::IntegrationTest
  test "invalid list creation information" do
    get addlist_path
    assert_no_difference 'List.count' do
      post lists_path, list: { days:  "a",
                               name: "a" * 141 }
    end
    assert_template 'lists/new'
  end

  test "valid list creation information" do
    get addlist_path
    assert_difference 'List.count', 1 do
      post_via_redirect lists_path, list: {
                                            days: 2,
                                            name: "example list"
                                          }
      end
      assert_template 'lists/show'
  end
end

错误中引用了app/views/lists/show.html.erb:

And app/views/lists/show.html.erb referenced in the error:

<% provide(:title, @list.name) %>
<div class="row"><aside class="col-md-4"><section class="user_info">
      <h1> <%= @list.name %></h1>
      <p><%= @list.days %> day(s)</p><p>
       <% Quantity.where(:list_id => @list.id).each do |f| %>
       <%= "#{f.amount} #{Food.find(f.food_id).name}" %>
       <% end %>
      </p></section></aside></div><%= link_to "edit the properties of this list", edit_list_path %>

感谢您提供任何建议或参考.如果您需要其他您认为相关的代码或信息,请告诉我.我希望使用固定装置而不是诸如FactoryGirl之类的其他方法来完成所有这一切,即使这意味着需要一些额外的代码.

Thank you for any advice or references. Please let me know if you need other code or information that you consider relevant. I am hoping to accomplish this all using fixtures and not another method such as FactoryGirl, even if it means a little extra code.

Rails 4.2.3,Cloud9.开发数据库= SQLite3,生产数据库= postgres heroku.

Rails 4.2.3, Cloud9. Development database = SQLite3, production database = postgres heroku.

推荐答案

除了很奇怪地在after_save回调中创建随机值(我认为您是在练习,但无论如何最好使用从一开始的良好做法),则永远不要使用rand(Model.count)来获取示例记录.主要有两个问题:

Besides being very weird to create a random value in the after_save callback (which I think you're doing as an exercise, but anyway it's better to use good practices from the start), you should never use rand(Model.count) to get a sample record. There's two main problems:

  1. rand(upper_bound)方法返回一个介于零和upper_bound参数之间的数字,但不能保证第一个创建的ID为零.我使用的是PostgreSQL,第一个模型的ID为1.您可以指定一个范围(rand(1..upper_bound)),但是无论如何,您都在赌博当前数据库的工作方式.
  2. 您假设所有记录在任何给定时间都按顺序存在,但这并不总是正确的.如果删除一条记录,并且它的ID是随机选择的,则会出现错误.该库还可以使用任何策略来创建固定装置,因此最好不要假设其工作原理.
  1. The rand(upper_bound) method returns a number between zero and the upper_bound argument, but there's no guarantee that zero is the first created id. I'm using PostgreSQL and the first model has the id 1. You can specify a range (rand(1..upper_bound)), but anyway you're gambling on the way the current database works.
  2. You're assuming that all the records exist in a sequential order at any given time, which is not always true. If you delete a record and it's id is randomly chosen, you'll get an error. The library also can use any strategy to create the fixtures, so it's better not to assume anything about how it works.

如果您确实需要随机选择一条记录,我建议您仅使用数组的sample方法:Food.all.sample.它很慢,但是可以用.如果需要优化,还有其他选择.

If you really need to choose randomly a record, I'd recommend simply using the array's sample method: Food.all.sample. It's slow, but it works. If you need to optimize, there's other options.

现在,我真的建议您不惜一切代价避免使用随机值,仅在必要时使用它们.它很难测试,也很难跟踪错误.另外,我会避免在回调内部创建关系,它会迅速发展为难以处理的混乱局面.

Now, I'd really recommend to avoid random values at all costs, using them only when necessary. It's difficult to test, and difficult to track bugs. Also, I'd avoid creating a relation inside a callback, it grows rapidly into a unmanageable mess.

这篇关于has_many:通过创建子元素after_save-&gt; ActionView :: Template :: Error的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-19 21:28