Home > Software design >  rspec: ActionController::UrlGenerationError, No route matches
rspec: ActionController::UrlGenerationError, No route matches

Time:02-10

After moving the download_qr link outside of this current_user.admin? from this:

#plots.show.html.haml (excerpt)
- content_for_title("Plot ##{@plot.plot_id}")
- content_for(:subnav) do
  = link_to '« Plots', plots_path, class: 'btn btn-primary', title: 'List of all plots'
  - if current_user&.admin?
    = link_to 'Download QR Code', { action: 'download_qr' }, 'data-turbolinks': false, class: 'btn btn-secondary', title: "QR Code for #{@plot}"
    = link_to 'Edit', edit_plot_path(@plot), class: 'btn btn-primary', title: "Edit #{@plot}"
    = link_to 'Delete', @plot, method: :delete, data: { confirm: "Delete Plot ##{@plot.plot_id}?" }, class: 'btn-tertiary', title: "Delete #{@plot}"

to this:

- content_for_title("Plot ##{@plot.plot_id}")
- content_for(:subnav) do
  = link_to '« Plots', plots_path, class: 'btn btn-primary', title: 'List of all plots'
  = link_to 'Download QR Code', { action: 'download_qr' }, 'data-turbolinks': false, class: 'btn btn-secondary', title: "QR Code for #{@plot}"
  - if current_user&.admin?
    = link_to 'Edit', edit_plot_path(@plot), class: 'btn btn-primary', title: "Edit #{@plot}"
    = link_to 'Delete', @plot, method: :delete, data: { confirm: "Delete Plot ##{@plot.plot_id}?" }, class: 'btn-tertiary', title: "Delete #{@plot}"

I get this error in rspec

plots/show displaying inoculation inoculated displays 'Yes'
     Failure/Error: = link_to 'Download QR Code', { action: 'download_qr' }, 'data-turbolinks': false, class: 'btn btn-secondary', title: "QR Code for #{@plot}"
     
     ActionView::Template::Error:
       No route matches {:action=>"download_qr", :controller=>"plots"}
     # ./app/views/plots/show.html.haml:4:in `block in _app_views_plots_show_html_haml__2393189060377325026_107320'
     # ./app/views/plots/show.html.haml:2:in `_app_views_plots_show_html_haml__2393189060377325026_107320'
     # ./spec/views/plots/show.html.erb_spec.rb:10:in `block (4 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # ActionController::UrlGenerationError:
     #   No route matches {:action=>"download_qr", :controller=>"plots"}
     #   ./app/views/plots/show.html.haml:4:in `block in _app_views_plots_show_html_haml__2393189060377325026_107320'

Here's the output for rails routes:

plots#index
                                         POST     /plots(.:format)                                                                                  plots#create
                                new_plot GET      /plots/new(.:format)                                                                              plots#new
                               edit_plot GET      /plots/:id/edit(.:format)                                                                         plots#edit
                                    plot GET      /plots/:id(.:format)                                                                              plots#show
                                         PATCH    /plots/:id(.:format)                                                                              plots#update
                                         PUT      /plots/:id(.:format)                                                                              plots#update
                                         DELETE   /plots/:id(.:format)                                                                              plots#destroy
                                         GET      /plots/:id/download_qr(.:format)                                                                  plots#download_qr

the test itself:

#show.html.erb_spec(excerpt)
require 'rails_helper'

RSpec.describe "plots/show", type: :view do

  describe "displaying inoculation" do

    context "inoculated" do
      it "displays 'Yes'" do
        assign(:plot, create(:plot))
        render
        expect(rendered).to have_content("Yes")
      end
    end

and the spec controller:

#plots_controller_spec(excerpt)
RSpec.describe PlotsController, type: :controller do
  let(:general_user) { FactoryBot.build(:user) }
  let(:admin_user) { FactoryBot.build(:user, :admin) }
  let(:plot) { FactoryBot.create(:plot) }
  let(:plant) { create(:plant) }
  let(:invalid_plot) { FactoryBot.build(:invalid_plot) }

  before do
    allow(controller).to receive(:current_user).and_return(admin_user)
  end

  describe '#index' do
    it 'returns http success' do
      get :index
      expect(response).to have_http_status(:success)
    end
  end

  describe '#show' do
    it 'returns http success' do
      get :show, params: { id: plot.id }
      expect(response).to have_http_status(:success)
    end
  end

The route works fine on the actual application, and the tests pass when I move the link back within the current_user.admin? block. I think it must have something to do with the way the test is routed but I can't seem to figure it out.

CodePudding user response:

You have the member download_qr action based on your output from rails routes. It means that you need to specify the plot instance :id for which you want to download the QR code /plots/:id/download_qr; see Rails guides for more information about member and collection routes.

Taking this into account, you need to add the :id parameter to your link_to as

= link_to 'Download QR Code', { controller: 'plots', action: 'download_qr', id: @plot }, class: 'btn btn-primary' ... 

You can find more valuable examples on link_to options here

I can suppose that your test passed, and the application worked okay when the link was within the scope of the current_user&.admin? block because you checked this with no current user or the non-admin user. The condition is evaluated as false; the respective part of the view will not be rendered/called at all.

  • Related