Rails’ method of sharing data between controllers and views via instance variables bothers many developers. For the uninitiated, a Rails controller method like this one…

class EventsController < ApplicationController
  def index
    @events = Event.scoped
  end
end

… makes the @events instance variable accessible to the rendered view.

This bugs me, too. My beefs with it are:

Better would be explicitly exposing the events collection to views via a reader and helper method, like this:

class EventsController < ApplicationController
  def index
    @events = Event.scoped
  end

  attr_reader :events
  helper_method :events
end

Now all views can just call the events method and not worry about the ivar.

This becomes cumbersome when you do it across many controllers and actions, so I use this handy method to “automate” the process to expose certain ivars to views:

class ApplicationController < ActionController::Base
  # short hand for exposing a list of ivars to view objects
  def self.exposes(*ivars)
    ivars.each do |ivar|
      attr_reader ivar.to_sym
      helper_method ivar.to_sym
    end
  end
end

The method takes an arbitrary list of ivar names. Using it, the example controller class looks like this:

class EventsController < ApplicationController
  exposes :events

  def index
    @events = Event.scoped
  end
end

Unfortunately, the view can still access @events, but it’s a step in the right direction.

I’m sure there are ways to stop direct access of instance variables from views, but I haven’t gotten that drastic yet.

I’ve gotten a lot of mileage out of this method. Perhaps you will too.