Query actions in Rails controllers

Recently some of my controller actions have taken on a definite new shape. Particularly when the action is a read-only query of the app’s state. Such actions tend to make up the bulk of my apps, and they can be simple because they are unlikely to “fail” in any predictable way. Here’s an example from my wiki app:

class CardsController < ApplicationController
def recently_changed
render 'recently_changed', locals: {
cards: RecentlyChanged.new(wiki).cards,
}
end
end
view raw cards_controller.rb hosted with ❤ by GitHub

This has a couple of significant plus points: First, no instance variables, so both the controller action and the view are more readable and easier to refactor. Second, no instance variables! So there’s a clear, documented, named interface between the controller and the view. And third, this is so transparently readable that I never bother to test it.

The wiki used in the above action is a repository, built in a memoizing helper method that most of the controllers use:

class ApplicationController < ActionController
def wiki
@wiki ||= if (current_user.admin?)
AdminWiki.new
else
ReadonlyWiki.new
end
end
end

In this case the correct kind of repository is created for the current user, and all of the other code in this request sits on top of that. So the controller action, helped by the memoized repository builder, effectively constructs an entire hexagonal architecture for each request, and the domain logic is thus blissfully unaware of its context.

Here’s a slightly bigger example. This is for a page that shows a variety of informative graphs about the wiki; and because I may want to re-organise my admin pages in the future, each graph’s data is built independently of the others:

class StatisticsController < ApplicationController
def traffic
hits_by_date = statistics.page_hits_by_date
render 'traffic', locals: {
weekly_page_hits: statistics.weekly_page_hits(hits_by_date),
weekday_hits: statistics.hits_by_weekday(hits_by_date),
time_of_day_hits: statistics.hits_by_time_of_day,
}
end
end

That’s the most complex query controller action I have, and I maintain that it’s so simple I don’t need to test it. Would you?

One thought on “Query actions in Rails controllers

  1. In both examples I agree, what is there to test?

    I try and treat controllers like main – just instantiate something and fire a method off. Unit testing would have very little benefit here – this is just an exercise of “wiring stuff up”. If you cock this up the your stats won’t work when you check manually.

    I personally find a lot of resistance against this – using your first example people want to know that “cards” is invoked – all I find is this makes refactoring difficult. My argument is I don’t test main, why would I test controllers?

Leave a Reply to Shaun Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s