RSpec:具有多态资源的控制器规范,“无路由匹配”错误

时间:2016-09-19 13:28:36

标签: ruby-on-rails rspec multi-tenant polymorphic-associations

我正在通过为现有项目编写规范来学习RSpec。我遇到了多态资源Notes的控制器规范。事实上,任何其他模型都可以与Notes建立关系:has_many :notes, as: :noteable

此外,该应用程序是多租户,每个帐户可以拥有多个用户。每个帐户都可以通过网址:slug而不是:id进行访问。所以我的多租户,多态路由看起来像这样:

# config/routes.rb
...

scope ':slug', module: 'accounts' do

  ...

  resources :customers do
    resources :notes
  end

  resources :products do
    resources :notes
  end
end

这会产生以下路线:新行动

new_customer_note GET    /:slug/customers/:customer_id/notes/new(.:format)      accounts/notes#new
new_product_note GET    /:slug/products/:product_id/notes/new(.:format)        accounts/notes#new

现在谈到测试问题。首先,这是我如何测试其他非多态控制器的示例,例如invitations_controller:

# from spec/controllers/accounts/invitation_controller_spec.rb
require 'rails_helper'

describe Accounts::InvitationsController do
  describe 'creating and sending invitation' do
    before :each do
      @owner = create(:user)
      sign_in @owner
      @account = create(:account, owner: @owner)
    end

    describe 'GET #new' do
      it "assigns a new Invitation to @invitation" do
        get :new, slug: @account.slug
        expect(assigns(:invitation)).to be_a_new(Invitation)
      end
    end
    ...
end

当我尝试使用类似的方法来测试多态性notes_controller时,我感到困惑: - )

# from spec/controllers/accounts/notes_controller_spec.rb

require 'rails_helper'

describe Accounts::NotesController do
  before :each do
    @owner = create(:user)
    sign_in @owner
    @account = create(:account, owner: @owner)
    @noteable = create(:customer, account: @account)
  end

  describe 'GET #new' do
    it 'assigns a new note to @note for the noteable object' do
      get :new, slug: @account.slug, noteable: @noteable     # no idea how to fix this :-)
      expect(:note).to be_a_new(:note)
    end
  end
end

这里我只是在前面的块中创建一个名为@noteable的客户,但它也可以是一个产品。当我运行rspec时,我收到此错误:

No route matches {:action=>"new", :controller=>"accounts/notes", :noteable=>"1", :slug=>"nicolaswisozk"}

我看到问题所在,但我无法弄清楚如何处理网址的动态部分,例如/products//customers/

感谢任何帮助: - )

更新

根据以下要求将get :new行更改为

get :new, slug: @account.slug, customer_id: @noteable

,这会导致错误

Failure/Error: expect(:note).to be_a_new(:note)

 TypeError:
   class or module required
 # ./spec/controllers/accounts/notes_controller_spec.rb:16:in `block (3 levels) in <top (required)>'

规范中的第16行是:

expect(:note).to be_a_new(:note)

这可能是因为我的notes_controller.rb中的:new操作不只是@note = Note.new,而是在@noteable上初始化一个新的注释,就像这样?:

def new
  @noteable = find_noteable
  @note = @noteable.notes.new
end

1 个答案:

答案 0 :(得分:2)

这里的问题应该是在这一行

get :new, slug: @account.slug, noteable: @noteable

你正在:noteable传递参数。但是,您需要传递url的所有动态部分,以帮助rails匹配路由。在这里你需要通过:customer_id参数。像这样,

get :new, slug: @account.slug, customer_id: @noteable.id

如果有帮助,请告诉我。