text: On Fridays, we enjoy getting together for lunch and reviewing code. This week, our liveliest discussion surrounded responsibility for authorization logic.
  The problem ~ where does the authorization logic go
  You’ve come across it before: you have a
  User model and a second model for
  which users must be authorized to perform certain tasks:
  def show @event = Event.find(params[:id]) unless( logged_in? && ( @event.members.include?(current_user) || @event.organizer.include?(current_user) ) || current_user.admin? ) flash[:failure] = "You are not authorized to view this event." redirect_to home_url and return end end
  In discussion, we decided there is too much logic in the controller. We want to move the authorization into the correct place in our domain model. Butwhere?
  unless current_user.authorized_for_event?(@event)`
  That reads nicely in English as “Unless the current user is authorized for the
  event” but logically, a
  User should not be responsible for its own
  authorization.
  Solution: non-User model authorizes User
  The authorization logic should be on
  Event, not
  User.
  For example, I have a ticket to a Red Sox game. When I arrive on Yawkey Way, the ticket-taker will authorize me to enter the event. He or she is the Controller in our MVC pattern. The ticket-taker doesn’t need to know that I paid with a MasterCard on September 20th or that my seat is in right field or any other details. All that matters is: is this guy authorized?
  def attend @game = RedSoxGame.find_by_id params[:id] unless @game.authorized?(current_user) flash[:failure] = "You have no ticket for this game. Watch it over a pint of Sam Adams at the Cask n' Flagon." redirect_to home_url and return end end class RedSoxGame < ActiveRecord::Base def authorized?(user) return false if user.nil? doors_open? && not_rained_out? && user.ticket?(self) && user.not_drunk? end end
  The
  authorized method is noteworthy for two reasons. First, it uses the
  Composed
  Method:
  Divide your program into methods that perform one identifiable task. Keep all of the operations in a method at the same level of abstraction. This will naturally result in programs with many small methods, each a few lines long.
  The
  authorized? method is very easy to read because it focuses on simply
  authorizing the user for the game. It relies on a number of other methods whose
  purpose is clear and are similarly of narrow focus.
  The second thing to note is that
  authorized? actually calls methods on the
  User model. It may seem contradictory to call
  User after saying that
  authorization logic does not belongs there. However, it isn’t authorization
  logic; it’s another level of abstraction.
  Most importantly, the ticket-taker will let me into the Sox game.