Skip to content

Instantly share code, notes, and snippets.

@nicolasblanco
Last active November 9, 2016 16:09
Show Gist options
  • Select an option

  • Save nicolasblanco/acf03b34599a2e765f244a73f3223414 to your computer and use it in GitHub Desktop.

Select an option

Save nicolasblanco/acf03b34599a2e765f244a73f3223414 to your computer and use it in GitHub Desktop.
Exposure Pattern
# Exposure pattern to use declarative interfaces in controller (which is the basic feature of the library decent_exposure).
#
# Using this pattern you can dramatically reduce or remove completely the need for instance variables in controllers and views.
#
# Example :
#
# BEFORE (traditional way in Ruby on Rails)
#
# class ArticlesController < ApplicationController
# before_action :load_current_blog
# before_action :load_articles
#
# ...
#
# private
#
# def load_current_blog
# @current_blog = Blog.find(params[:id])
# end
#
# def load_articles
# @articles_sorted = @current_blog.articles.order(:created_at, :desc)
# end
#
# ...
# then in views you access data using the instance variables (@foo for example). If for any reason you don't have some variables defined, and call @foo.each for example on one of them you get a NoMethodError: undefined method `each' for nil:NilClass and you don't know which variable is not defined if you don't look at the view.
# In controller tests it's difficult to test instance variables, you have to use helpers like "assigns"...
#
#
# AFTER
#
# class ArticlesController < ApplicationController
# expose(:current_blog) { Blog.find(params[:id]) }
# expose(:articles_sorted) { current_blog.articles.order(:created_at, :desc) }
#
# ...
# then in views you access data using current_blog and articles_sorted which are methods. If this time you call foo.each and the foo method is not defined you simply get a 'undefined local variable or method foo', you get the name of the undefined variable in the exception (foo).
# It's also way more easy to test those methods in controller tests because you can call them direcly with 'controller.foo' to get the result. You don't need to rely on helpers like assigns.
#
module SimpleExposure
extend ActiveSupport::Concern
class_methods do
def expose(exposure_name, &block)
class_variable_set(:"@@#{exposure_name}_proc", Proc.new)
class_eval <<-EVAL
helper_method :#{exposure_name}
def #{exposure_name}
@#{exposure_name} ||= @@#{exposure_name}_proc.call
end
EVAL
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment