Skip to content

Instantly share code, notes, and snippets.

@hopsoft
Created November 30, 2011 21:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hopsoft/1410915 to your computer and use it in GitHub Desktop.
Save hopsoft/1410915 to your computer and use it in GitHub Desktop.
Resourceful Rails actions for free with a Sinatra like DSL for action callbacks
module Resourceful
def self.actions
[:index, :show, :new, :edit, :create, :update, :destroy]
end
def self.callbacks
[:before, :after, :respond_to]
end
module ControllerClassMethods
def set_resourceful_model(arg)
@resourceful_model = arg
end
alias :resourceful_model= :set_resourceful_model
def resourceful_model
return @resourceful_model if @resourceful_model
# try to determine the model based on convention
name = self.name.gsub(/Controller$/i, "").classify
# require the file to ensure the constant will be defined
require "#{RAILS_ROOT}/app/models/#{name.underscore}" rescue nil
@resourceful_model = Object.const_get(name)
end
def resourceful_callbacks
@resourceful_callbacks ||= HashWithIndifferentAccess.new
end
# define callback setters
Resourceful.callbacks.each do |callback|
Resourceful.actions.each do |action|
eval <<-DEF
def #{callback}_#{action}(value=nil, &block)
callback = value if value
if block_given?
define_method(:#{callback}_#{action}, block)
callback = :#{callback}_#{action}
end
resourceful_callbacks[:#{callback}_#{action}] = callback
end
DEF
end
end
end
# extend the controller class definition
def self.included(controller)
controller.extend(ControllerClassMethods)
end
# -----------------------------------------------------------------------------------------------
# begin restful actions
def index
invoke_callback(:before, :index)
@resourceful_list ||= resourceful_model.all
init_instance_variables
invoke_callback(:respond_to, :index)
unless performed?
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @resourceful_list }
format.js { render :json => @resourceful_list }
end
end
invoke_callback(:after, :index)
end
def show
invoke_callback(:before, :show)
@resourceful_item ||= resourceful_model.find(params[:id])
init_instance_variables
invoke_callback(:respond_to, :show)
unless performed?
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @resourceful_item }
format.js { render :json => @resourceful_item }
end
end
invoke_callback(:after, :show)
end
def new
invoke_callback(:before, :new)
@resourceful_item ||= resourceful_model.new
init_instance_variables
invoke_callback(:respond_to, :new)
unless performed?
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @resourceful_item }
format.js { render :json => @resourceful_item }
end
end
invoke_callback(:after, :new)
end
def edit
invoke_callback(:before, :edit)
@resourceful_item ||= resourceful_model.find(params[:id])
init_instance_variables
invoke_callback(:respond_to, :edit)
invoke_callback(:after, :edit)
end
def create
invoke_callback(:before, :create)
@resourceful_item ||= resourceful_model.new(params[resourceful_model.name.underscore])
init_instance_variables
success = @resourceful_item.save
invoke_callback(:respond_to, :create)
unless performed?
respond_to do |format|
if success
flash[:notice] = "#{resourceful_model.name} was successfully created."
format.html { redirect_to(@resourceful_item) }
format.xml { render :xml => @resourceful_item, :status => :created, :location => @resourceful_item }
format.js { render :json => @resourceful_item, :status => :created, :location => @resourceful_item }
else
format.html { render :action => "new" }
format.xml { render :xml => @resourceful_item.errors, :status => :unprocessable_entity }
format.js { render :json => @resourceful_item.errors, :status => :unprocessable_entity }
end
end
end
invoke_callback(:after, :create)
end
def update
invoke_callback(:before, :update)
@resourceful_item ||= resourceful_model.find(params[:id])
init_instance_variables
success = @resourceful_item.update_attributes(params[resourceful_model.name.underscore])
invoke_callback(:respond_to, :update)
unless performed?
respond_to do |format|
if success
flash[:notice] = "#{resourceful_model.name} was successfully updated."
format.html { redirect_to(@resourceful_item) }
format.xml { head :ok }
format.js { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @resourceful_item.errors, :status => :unprocessable_entity }
format.js { render :json => @resourceful_item.errors, :status => :unprocessable_entity }
end
end
end
invoke_callback(:after, :update)
end
def destroy
invoke_callback(:before, :destroy)
@resourceful_item ||= resourceful_model.find(params[:id])
init_instance_variables
@resourceful_item.destroy
invoke_callback(:respond_to, :destroy)
unless performed?
respond_to do |format|
format.html { redirect_to(send("#{resourceful_model.table_name}_url")) }
format.xml { head :ok }
format.js { head :ok }
end
end
invoke_callback(:after, :destroy)
end
# end restful actions
# -----------------------------------------------------------------------------------------------
protected
def resourceful_model
self.class.resourceful_model
end
def resourceful_callbacks
self.class.resourceful_callbacks
end
def init_instance_variables
item_name = resourceful_model.name.underscore
eval "@#{item_name} ||= @resourceful_item"
eval "@#{item_name.pluralize} ||= @resourceful_list"
end
private
def invoke_callback(callback, action)
method = resourceful_callbacks["#{callback}_#{action}"]
send(method) if method.is_a?(Symbol) || method.is_a?(String)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment