1

As many times that I've tried to do rails testing, you'd think I had figured it out by now - I haven't.

The latest approach is using minitest - at least it's mainly Ruby and not a bunch of DSL that is learning yet another language with what seems like hundreds of methods. Now I may have dug myself into a hole with my latest experiment, but I kind of like what I tried to accomplish. It's a combination of nested resources, including some polymorphic resources. It is also using Pundit for authorization.

The models define a hierarchical entity (think of a corporation or government agency such as the forest service, or in my case the VFW hierarchy)

Basic Models
class Department < ActiveRecord::Base
  has_many :districts, dependent: :destroy
  has_many :posts, through: :districts
  has_many :reports, through: :posts
  has_many :officers, as: :fillable, dependent: :destroy
  has_many :markups, as: :markupable, dependent: :destroy
  has_many :users, as: :loginable, dependent: :destroy
end

class District < ActiveRecord::Base
  belongs_to :department
  has_many :posts, dependent: :destroy
  has_many :reports, through: :posts
  has_many :officers, as: :fillable, dependent: :destroy
  has_many :markups, as: :markupable, dependent: :destroy
  has_many :users, as: :loginable, dependent: :destroy
end

class Post < ActiveRecord::Base
  belongs_to :district
  has_one :department, through: :district
  has_many :members, dependent: :destroy
  has_many :officers, as: :fillable, dependent: :destroy
  has_many :reports, dependent: :destroy
  has_many :markups, as: :markupable, dependent: :destroy
  has_many :users, as: :loginable, dependent: :destroy
end

class User < ActiveRecord::Base
  belongs_to :loginable, polymorphic: true
end

class Officer < ActiveRecord::Base
  belongs_to :fillable, polymorphic: true
end

class Report < ActiveRecord::Base
  belongs_to :post
end

As in most entities like this, the bottom does all the work (submit reports, etc) and the upper levels just manages, summarizes and reports.

This is a semi closed system in that you have to login as at least a 'Guest' where you can look, but not touch. Each level has Officers (employees), and Markups (news, post, etc). The User is a polymorphic relation belonging to one of the entities (Department, District, or Post).

My main routes are basically shallow routing except I use Pundit for scoping:

  resources :departments do
    resources :officers,only: [:new, :create]
    resources :markups,only: [:new, :create]
    member do
      get :reports_summary
    end
  end

  resources :districts do
    resources :officers,only: [:new, :create]
    resources :markups,only: [:new, :create]
    member do
      get :reports_summary
    end
  end

  resources :posts do
    resources :officers,only: [:new, :create]
    resources :markups,only: [:new, :create]
    resources :reports,only: [:new, :create]
    resources :members,only: [:new, :create]
    member do
      get :reports_menu
      get :reports_summary
    end
  end
  resources :officers, only: [:index, :show, :edit, :update, :destroy]
  resources :markups, only: [:index, :show, :edit, :update, :destroy]
  resources :reports, only: [:index, :show, :edit, :update, :destroy]
  resources :members, only: [:index, :show, :edit, :update, :destroy]

Just looking at Post Officers, the generated routes are:

post_officers_path  POST  /posts/:post_id/officers(.:format)  officers#create
new_post_officer_path GET /posts/:post_id/officers/new(.:format)  officers#new

My problem is getting controller tests to work without taking the rest of my life to figure it out! I did use scaffold the generate the models and tests. I'm beginning to go to the side that says controller tests are a repetitive waste of time and concentrate on integration tests. My major problem is :new and :create tests for polymorphic associations like Officers. My old blunt force testing works fine (knowing that it is not the best approach) and routes all work. The controller new and create tests will fail with ActionController::UrlGenerationError: No route matches {:action=>"/posts/980190962/officers/new", :controller=>"officers"} or No route matches {:action=>"new", :controller=>"officers"}

Even hardwiring the route for a new Post Officers with:

def test_new_post
  get "/posts/#{@resource.id}/officers/new"
  assert_response :success
end

fails.

I was mainly looking at the controller test to do the basic CRUD stuff and Authorization, but I think its easier to test Authorization in a integration test, especially if there are different roles to do different stuff - but I should be able to figure this out. I've looked at what seems like hundreds of posts on stackoverflow, but none seem to address polymorphic nested resources.

appleII717
  • 328
  • 3
  • 12
  • This is a cop-out, but I recommend not testing controllers and extracting complex logic to easily tested services. Specifically, I recommend using the [interactor gem](https://github.com/collectiveidea/interactor) to extract logic into a simple service call that returns a context. Continue to test the happy path through integration tests, and unit test complex controller behavior through its service. If that doesn't work for you -- good luck! – steel Apr 24 '16 at 03:04

0 Answers0