DRY up controllers with params_to_objects

Posted: September 6th, 2008 | Author: Daniel Higginbotham | Filed under: Programming, Rails | 6 Comments »

The following allows you to get rid of the numerous “Model.find(params[:id])” calls in your controllers. I’m pretty sure I’ve seen similar solutions out there, so if anyone wants to link to those in the comments that’d be helpful.

# Example
class BooksController < ApplicationController
  params_to_objects :library, :book 

  def show
    # if this method corresponds to /libraries/{id}/books/{id}
    # then @book and @library are automatically created
  end
end

# Put the following in ApplicationController
class << self
  # you can use the *_filter options of :only, etc
  # also, if you have namespaced model, you can use
  # params_to_objects "namespace/model"
  def params_to_objects(*names)
    options = names.reject{|o|!o.is_a? Hash} || []
    names = names - options

    first_name = names.shift
    params_to_object(first_name, :id, options)

    names.each do |name|
      safe_name = name.to_s.gsub("/", "_")
      params_to_object(name, "#{safe_name}_id", options)
    end
  end

  def params_to_object(name, id, options)
    safe_name = name.to_s.gsub("/", "_")
    module_eval <<-"end;"
      def set_instance_variable_#{safe_name}
        @#{safe_name} = "#{name.to_s}".classify.constantize[params['#{id.to_s}']] if params['#{id.to_s}']
      end
    end;

    before_filter "set_instance_variable_#{safe_name}".to_sym, *options
  end
end

6 Comments on “DRY up controllers with params_to_objects”

  1. 1 nobody said at 12:43 am on September 7th, 2008:

    A question about ruby.

    Why did you put a class << self in application controller? Why not just put the function definition there and let it be inherited?

  2. 2 Mike said at 7:59 am on September 7th, 2008:

    I like the (quite different) approach in
    http://stephencelis.com/archive/2008/9/rails-controllers-views-and-variables

    Like the author, I’ve never liked using instance variables in the way that idiomatic Rails does. I haven’t tried it myself yet but I’d be interested to see what you think.

  3. 3 Daniel Lyons said at 11:52 am on September 7th, 2008:

    make_resourceful will also do this for you, if you use it and put a belongs_to inside the make_resourceful do block.

  4. 4 Daniel Higginbotham said at 2:37 pm on September 7th, 2008:

    Thanks for the tip Daniel. I thought I had seen make_resourceful before but couldn’t remember the name of it.

    @Mike – Stephen’s solution is neat, but personally I think it’s actually better to use instance variables. In my code I mostly use instance variables for active record objects, whereas I use methods galore. The little @ thus helps me find the active record objects quicker. I’m also biased towards using instance variables because I was introduced to Ruby through Rails, so my brain considers that the “right” way to do things.

    There’s one more thing that’s hard for me to explain… instance variables have a more static “feel” to them, even a kind of solidity that free-floating methods don’t. Wish I could explain better than that :)

  5. 5 Daniel Higginbotham said at 2:45 pm on September 7th, 2008:

    @nobody – the short answer is that the params_to_objects method needs to be a class method.

    params_to_objects creates before_filter‘s on the fly. before_filter needs to be able to apply to more than controller action (method), and for it to do so it needs to be a class method. I hope this answers your question – I’m not sure how familiar you are with Ruby, so I’m not sure what level of detail to get into.

  6. 6 nobody said at 4:23 pm on September 7th, 2008:

    Thanks for the explanation. The clears it up. I am a ruby newbie and I get pretty confused with meta programming especially inside of rails.


Leave a Reply