0

第一次在stackoverflow上发帖,事先为任何类似菜鸟的事情道歉。

我在一项功能测试中收到错误,几个小时后,我似乎无法弄清楚如何通过它。

简而言之,一个invoice_schedulewhich has_many invoice_milestones。然后,invoice_milestones有一个属性,estimate_percentage(一个整数)。我的模型models/invoice_schedule.rb有一个验证,要求所有的总和estimate_percentages必须等于 100。

create 操作的功能测试invoice_schedule每次都失败。在下面我当前的代码中,它一直在出错。我看不出我传递的参数会如何出错。

我还要注意estimate has_one :invoice_schedule

任何帮助或建议表示赞赏:)

模型/invoice_schedule.rb:

class InvoiceSchedule < ActiveRecord::Base
    belongs_to :estimate
    has_many :invoice_milestones, :dependent => :destroy

    accepts_nested_attributes_for :invoice_milestones, :allow_destroy => true

    validate :total_must_equal_one_hundred_percent

    def total_must_equal_one_hundred_percent
        if total_percent != 100
            errors.add(:invoice_milestones, "Total must equal 100%")
        end
    end

    def total_percent
        invoice_milestones.to_a.sum { |item| item.estimate_percentage || 0 }
    end
end

模型/invoice_milestone.rb:

class InvoiceMilestone < ActiveRecord::Base
    belongs_to :invoice_schedule
    belongs_to :invoice

    validates :estimate_percentage, :numericality => {:only_integer => true, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 100}
end

控制器/invoice_schedules_controller.rb

  def create
    @invoice_schedule = InvoiceSchedule.new(params[:invoice_schedule])
    @estimate = Estimate.find_by_id(params[:estimate_id])

    respond_to do |format|
      if @invoice_schedule.save
        format.html { redirect_to invoice_schedule_path(@invoice_schedule), :flash => {:notice => 'Invoice schedule was successfully created.', :status => 'success'} }
        format.json { render json: @invoice_schedule, status: :created, location: @invoice_schedule }
      else
        format.html { render action: "new" }
        format.json { render json: @invoice_schedule.errors, status: :unprocessable_entity }
      end
    end
  end

测试/功能/invoice_schedules_controller_test.rb

  setup do
    @account = accounts(:lorem)
    @estimate = estimates(:lorem_one)
    @user = users(:lorem_vendor)
    @request.host = "#{@account.subdomain}.myapp.local"
    session[:user_id] = @user.id
    @invoice_schedule = invoice_schedules(:lorem_one)
    @invoice_milestone = invoice_milestones(:lorem_one)
    @data_estimate = estimates(:lorem_two)
    @data_invoice_schedule = @invoice_schedule.attributes.merge({estimate_id: @data_estimate.id})
  end

  test "should create invoice_schedule" do
    assert_difference('InvoiceSchedule.count') do
        post :create, :invoice_schedule => { estimate_id: @data_estimate, :invoice_milestone => {estimate_percentage: 100}}
    end

    assert_redirected_to estimate_invoice_schedule_path(@estimate, assigns(:invoice_schedule))
  end

配置/路由.rb

require 'subdomain'

    Accountimize::Application.routes.draw do

      resources :invoices do
        member do
          get 'generateInvoiceFromMilestone'
        end
      end

      resources :users
      resources :sessions

      get "sign_up" => "accounts#new", :as => "sign_up"

      resources :accounts

      resources :clients do
        get :client_address, on: :member
      end

      resources :estimates do
        resources :invoice_schedules, :shallow => true
      end

      resources :line_items

      constraints(Subdomain) do
        match '/' => 'accounts#show'
        get "log_in" => "sessions#new", :as => "log_in"
        get "log_out" => "sessions#destroy", :as => "log_out"
        get "register" => "users#new", :as => "register"
      end
      root :to => 'site#index', :as => 'site'
    end

我得到的错误痕迹:

InvoiceSchedulesControllerTest
     test_should_create_invoice_schedule                                 ERROR
        No route matches {:invoice_schedule=>{:estimate_id=>"706507935", :invoice_milestones_attributes=>{"0"=>{:description=>"test", :estimate_percentage=>"100"}}}, :controller=>"invoice_schedules", :action=>"create"}
        STDERR:
        Exception `ActionController::RoutingError' at /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_dispatch/routing/route_set.rb:465:in `raise_routing_error'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_dispatch/routing/route_set.rb:461:in `rescue in generate'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_dispatch/routing/route_set.rb:453:in `generate'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_dispatch/routing/route_set.rb:494:in `generate'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_dispatch/routing/route_set.rb:490:in `generate_extras'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_dispatch/routing/route_set.rb:486:in `extra_keys'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_controller/test_case.rb:145:in `assign_parameters'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_controller/test_case.rb:438:in `process'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_controller/test_case.rb:49:in `process'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/actionpack-3.1.1/lib/action_controller/test_case.rb:370:in `post'
        test/functional/invoice_schedules_controller_test.rb:35:in `block (2 levels) in <class:InvoiceSchedulesControllerTest>'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activesupport-3.1.1/lib/active_support/testing/assertions.rb:55:in `assert_difference'
        test/functional/invoice_schedules_controller_test.rb:30:in `block in <class:InvoiceSchedulesControllerTest>'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activesupport-3.1.1/lib/active_support/testing/setup_and_teardown.rb:35:in `block in run'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activesupport-3.1.1/lib/active_support/callbacks.rb:444:in `_run_setup_callbacks'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activesupport-3.1.1/lib/active_support/callbacks.rb:81:in `run_callbacks'
        /Users/Matt/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activesupport-3.1.1/lib/active_support/testing/setup_and_teardown.rb:34:in `run'

我已经尝试了很多其他方法来完成在功能测试中将 invoice_milestone 添加到新创建的 invoice_schedule 中,但似乎没有什么对我有用。如果添加了accepts_nested_attributes_for,为什么会收到上述路由错误?

4

1 回答 1

3

这有两个部分。首先,您需要正确设置路由端。因为您已将发票计划嵌套在您需要estimate_id在顶层(而不是内部params[:invoice_schedules])提供的估计中,即

post :create, :estimate_id => @data_estimate.id, :invoice_schedule => {...}

然后期望您的控制器按照以下方式执行某些操作

estimate = Estimate.find(params[:estimate_id])
@invoice_schedule = estimate.invoice_schedules.build params[:invoice_schedule]

第二部分与嵌套属性有关——您需要提供与 Rails 期望相匹配的 params 哈希。第一部分是哈希中的键应该是:invoice_milestones_attributes. 由于这是 a has_many,因此相应的值需要是一个哈希数组,或者一个哈希哈希(键被忽略 - 这主要是因为在 rails 的参数传递中数组和哈希之间的交互),例如

post :create, :estimate_id => @data_estimate.id, 
              :invoice_schedule => {
                :invoice_milestones_attributes => [
                  {:estimate_percentage => 100}
                ]
              } 
于 2012-07-08T15:37:43.993 回答