Skip to content

Instantly share code, notes, and snippets.

@ntl
Last active August 29, 2015 13:56
Show Gist options
  • Save ntl/8904880 to your computer and use it in GitHub Desktop.
Save ntl/8904880 to your computer and use it in GitHub Desktop.
The idea here is to give you a simple method that can define your ivar for you, protecting against `nil` proactively, and record the location where the ivar was defined. Best part is, if someone looks for where `#expose` is defined, they'll be happy to find out it's not in a gem. Easy to modify/understand.
# Instead of ditching ivars, just make them easier to discover:
class ApplicationController < ActionController::Base
private
# Expose an object as an ivar to your views. Explodes if you try to assign nil.
#
# Use:
#
# admin = Admin.find_by(email: "[email protected]")
#
# expose(admin) # Defines @admin, because admin.class is Admin
# expose(admin, as: "@user") # Overrides default ivar name
# expose(admin, permit_nil: true) # Does *not* blow up if admin is nil
#
def expose(object, as: "@#{object.class.name.underscore}", permit_nil: false)
if instance_variable_defined?(as)
raise "Instance variable #{as} already defined!"
end
if object.nil? && permit_nil
raise "Tried to expose #{as} as nil!"
end
unless Rails.env.production?
exposed_variables[as] = OpenStruct.new(object: object, source: caller_locations[1])
end
instance_variable_set as, object
end
def exposed_variables
# Add the underscores before and after to indicate that this variable is srs bsns.
@__exposed_variables__ ||= {}
end
def source_for_ivar(ivar)
exposed_variables.find { |k,v| v.object == ivar }.try(:source)
end
end
# Usage
class OrdersController < ApplicationController
def show
order = Order.find(params[:id])
expose order
end
end
# When you want to override the name:
class OrdersController < ApplicationController
def show
order = PaypalOrder.find(params[:id])
expose order, as: "@order"
end
end
# Now, your view can go back to using ivars, knowing that @order will never be nil,
# and that if you ever need to know where it came from, you can find it.
# app/views/orders/show.html.erb
#
# <dl>
# <dt>Order Number</dt>
# <dt><%= @order.id %></dt>
# </dl>
@ntl
Copy link
Author

ntl commented Feb 9, 2014

Of course, this should really be a Concern :trollface:

Also, nothing is stopping anyone on your project from not using #expose, but my aim was for the least invasive solution keeping to the "rails way."

@rpond-pa
Copy link

expose(self) is probably a bad practice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment