When developing a Rails application that also exposes an API your routes.rb contains the configuration of the available actions for each controller. Often you have a controller for your backend that support all actions for a route where the api controller should support a limited set of actions

A small example:

Rails.application.routes.draw do
  namespace 'api' , :defaults => {:format => :json} do
    namespace 'v1' do
      post 'login', to: 'authentication#login', as: 'login'
      resources :countries , :only => [:index, :show]
      resources :states , :only => [:index, :show]
      resources :orders, :only => [:index, :show]
    end
  end
  resources :countries
end

In the above example you will see that the intend we have is that the route /api/v1/countries only support the index and show actions, while the countries route should support all actions.

Since I couldn’t find an implementation of minitest to assert and test my routes, I’ve written a simple function which you can add to your test_helper.rb

def assert_actions_for_controller(controller_path, included_actions = nil, excluded_actions= nil)
  route_defaults = Rails.application.routes.routes.map(&:defaults)
  route_defaults = route_defaults.select {|x| x[:controller] == controller_path}
  found_actions = route_defaults.map {|x| x[:action]}.uniq.sort
  assert found_actions == included_actions.sort if included_actions != nil
  if excluded_actions != nil
    excluded_actions.each do |excluded_action|
      assert_not found_actions.include? excluded_action
    end
  end
end

This function accepts a controller_path, and an array with included_actions and excluded_actions.

The included_actions are the actions the controller should support where the excluded actions are the ones that shouldn’t exist in your route configuration.

So how to use this in your test? Let’s do a simple example, for which I’ve used an IntegrationTest.

require 'test_helper'

class RouteControllerTest < ActionDispatch::IntegrationTest

  setup do
    @all = %w[index show create update edit new destroy]
    @read_only = %w[index show]
    @update = %w[create update destroy]
  end

  test "api/v1/countries route" do
    assert_actions_for_controller('api/v1/countries', @read_only, @update)
  end


  test "countries route" do
    assert_actions_for_controller('countries', @all )
  end
end

In the setup we define the various action scenario’s that we use in our configuration.

The api/v1/countries route should support the @read_only actions (index and show) and it shouldn’t support the @update actions (create update destroy).

This simple helper will increase the quality of your testing.

Feel free to use it at your convenience.

First published on my medium page https://medium.com/@petervandeput/how-to-test-rails-routes-are-configured-correctly-1c5b48ebff39

Tags

Comments are closed