Mišel Ademi
Mišel Ademi

Reputation: 183

Rspec no route matches polymorphic

I am trying to test my polymorphic comments create action but I always get no route matches error in rspec.

class CommentsController < ApplicationController
  before_action :authenticate_user!

  def create
    @comment = @commentable.comments.new(comment_params)
    @comment.user_id = current_user.id
    @comment.save
    redirect_to :back, notice: "Your comment was successfully posted."
  end

  private
  def comment_params
    params.require(:comment).permit(:body)
  end
end

Rspec

describe "POST #create" do
    context "with valid attributes" do
      before do
        @project = FactoryGirl.create(:project)
        @comment_attr = FactoryGirl.build(:comment).attributes
      end

      it "creates a new comment" do
        expect{
          post :create, params: { project_id: @project, comment: @comment_attr }
        }.to change(Comment, :count).by(1)
      end
    end
  end

I am using this approach for testing create action in my another controllers and there is everything good, but here from some reason is throws error. I think my error is in line where I pass params to post create action but I do not see error.

UPDATE

 resources :projects do
    resources :comments, module: :projects
    resources :tasks do
      resources :comments, module: :tasks
    end
  end

UPDATE 2

Failure/Error: post :create, params: { project_id: @project, commentable: @project, comment: @comment_attr }

ActionController::UrlGenerationError: No route matches {:action=>"create", :comment=>{"id"=>nil, "commentable_type"=>nil, "commentable_id"=>nil, "user_id"=>nil, "body"=>"MyText", "created_at"=>nil, "updated_at"=>nil, "attachment"=>nil}, :commentable=>#, :controller=>"comments", :project_id=>#}

Upvotes: 0

Views: 187

Answers (1)

ulferts
ulferts

Reputation: 2242

I think that your controller namespace does not match the routes you define. The controller is defined to not be nested (CommentsController) whereas the corresponding routes are nested and inside a module projects as well. Nesting the routes will have no influence on the controller ActionDispatch is looking for. But defining a module for the route will lead to rails expecting a controller inside the module namespace. In your case that would be Projects::CommentsController and Tasks::CommentsController. Please see "2.6 Controller Namespaces and Routing" of "Rails Routing from the Outside In" for further details.

I added your routes to a brand new rails project and ran rails routes. The output is:

                             Prefix Verb   URI Pattern                 Controller#Action
     project_comments GET    /projects/:project_id/comments(.:format)  projects/comments#index
                      POST   /projects/:project_id/comments(.:format)  projects/comments#create
                      ...

You can therefor either remove the module definition from your routes

resources :projects do
  resources :comments
  resources :tasks do
    resources :comments
  end
end

or nest the controllers inside in a project/task namespace. Given that you want polymorphism for your comments, I would advise using the first option.

Upvotes: 0

Related Questions