Eoraptor Extracts - "Prepares.rb"

Just a simple one to start off today - This is a piece of code I've reused quite a few times and it's really saved me a lot of coding time retyping the same thing. In essence, prepares is a single drop in file for rails that adds a few niceties - basically preparing a model instance (via find) and storing it in an instance variable.

For example, if you want to prepare the model Post in the current controller on a certain set of actions, you may use this -

prepares :post, :only => [:show, :edit, :update, :destroy, :publish]

You have :only and :except options which can be passed straight into the before filter it builds. Other options include:

  • :instance_var - the alternative instance variable name to use
  • :params_key - what params attribute to use
  • :if - a string (same as ruby code) which will be called if passed in e.g. a method (:action_name) - it's eval'ed
  • :model - An alternate model to use; can either be a class (on which to_s is called for the name) or a symbol e.g. :blog_post -> BlogPost

There are no tests / documentation for it other than this (it's something I need to work on) but it in use on this blog. Oh, if you pick up an error, let me know - I chopped out some parts of it at the last minute.

Using it

Just add prepares.rb to your lib subdirectory of rails with this code; then add:

include Prepares::ControllerMixin

to your application controller / whichever controllers you want to use it.

The Source

Use it, even if your name isn't Luke and it isn't "The Force".

# prepares.rb - Copyright Darcy R. Laycock, 2008 # http://blog.ninjahideout.com # Use as you want but please keep this header up top. module Prepares module ControllerMixin def self.included(parent) parent.class_eval do extend Prepares::ClassMethods include Prepares::InstanceMethods end end end module ClassMethods def prepares(name, opts = {}) raise ArgumentError unless opts.is_a?(Hash) opts.assert_valid_keys(:instance_var, :model, :except, :only, :params_key, :if) params_key = opts[:params_key] || :id instance_var_name = "@#{(opts[:instance_var] || name).to_s.gsub(/^[@]+/, "")}" conditionals = opts.delete(:if) || nil pmodel = get_prepares_model(opts[:model] || name) method_name = :"prepares_#{name.to_s.underscore}" method = "def #{method_name}\n" method << "if #{conditionals}\n" if conditionals method << " #{instance_var_name} = #{pmodel}.find(params[:#{params_key}])\n" method << " end\n" if conditionals method << "end\n" before_filter_opts = {} before_filter_opts[:except] = opts[:except].to_a unless opts[:except].blank? || opts[:except].to_a.empty? before_filter_opts[:only] = opts[:only].to_a unless opts[:only].blank? || opts[:only].to_a.empty? class_eval do before_filter method_name, before_filter_opts end self.class_eval method end private def get_prepares_model(pmodel) if pmodel.is_a?(Symbol) return pmodel.to_s.classify else return pmodel.to_s end end end module InstanceMethods # if it needs to be included. end end
Posted by in Programming and it's been tagged as ruby on rails, eoraptor, code & provides. There are currently 2 comments.

Comments

This is a great piece of code; I have something very similar in all of my Rails projects. The problem I have come up against is that I sometimes have several routes map to the same action. Specifically, having both an un-nested and a nested resource for the same controller means that one of them has routes like: <pre><code> /people/:id/tickets/:ticket_id/ </code></pre> and the other has routes like: <pre><code> /tickets/:id/ </code></pre> Now :ticket_id is always a Ticket (valid or not), but :id could be a Person or a Ticket. I've solved this problem by changing the default route creation for resources: <pre><code> module ActionController module Resources class Resource def member_path @member_path ||= "#{path}/:#{singular}_id" end end end end </code></pre> That way, all route segments look like :person_id or :ticket_id, never just :id. -James
Posted by James (http://100essays.blogspot.com) at 11:08 AM Feb 9th.
Interesting problem James - I might try and integrate that into the next update I do.
Posted by Sutto at 10:03 AM Feb 12th.

Your Comment