RSpec:具有多态资源的控制器规范,"No route matches" 错误

RSpec: Controller spec with polymorphic resource, "No route matches" error

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

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

# config/routes.rb
...

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

  ...

  resources :customers do
    resources :notes
  end

  resources :products do
    resources :notes
  end
end

这会导致 :new 操作的路由与此类似

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"}

我明白问题出在哪里了,但我就是想不出如何解决 URL 的动态部分,例如 /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 上初始化一个新的 Note,就像这样?:

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

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

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

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

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

如果有帮助,请告诉我。