【问题标题】:RSpec: Controller spec with polymorphic resource, "No route matches" errorRSpec:具有多态资源的控制器规范,“无路由匹配”错误
【发布时间】:2016-09-20 21:31:54
【问题描述】:

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

此外,该应用程序是多租户的,每个帐户可以有多个用户。每个帐户由:slug 访问,而不是 URL 中的: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

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    如果这有帮助,请告诉我。

    【讨论】:

    • 谢谢,看来您正在做某事。路由错误消失了,但现在显示TypeError: class or module required。我猜它指的是 Customer 类。我如何将其包含在测试中?
    • 你能给错误的一些堆栈跟踪吗?这应该会有所帮助。
    • 我假设您正在尝试检查在您的操作中分配的实例变量 @note 的类型。为此,您必须写 expect(assigns(:note)).to be_a Noteexpect(assigns(:note)).to be_a_new Note
    • 您需要将类或模块名称传递给be_a_new 匹配器,但您只传递了一个符号。这就是它引发错误的原因。
    • 为了您的帮助,这些是非常好的文档:relishapp.com/rspec/rspec-rails/docs。只需检查您使用的 rspec 版本即可。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-04
    • 2013-01-23
    • 2012-08-18
    • 1970-01-01
    相关资源
    最近更新 更多