Skip to content
/ macro Public

Macro controller method (Metaprogramming) from Chad Fowler Rails Recipes

Notifications You must be signed in to change notification settings

sploiber/macro

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Macro

This is a very cool idea, from Chad Fowler, Rails Recipes, 2012. (Chapter 28) You write a macro in the ApplicationController class, which adds a method to any controller that you write. That method can then be called by any action, provided you add it to routes. There are several interesting aspects of it, discussed below.

The example includes Cars and Drivers, and puts the macro for search into CarsController. (Drivers isn’t really needed) The following things are then needed to make this work:

1) Add a route for search, inside Car, like this:

resources :cars do
  get 'search', :on => :collection
end

I do not yet understand the meaning of :on. (Question #1)

2) A view needs to be added to shared/search_results to display the located objects; it is nothing more than a simple table of send calls.

3) The Cars controller gets this:

class CarsController < ApplicationController

search_action_for :cars, :title => 'Your cars', :search_column => 'serial',:dsplay_as => :model_name

which executes the macro and causes the macro to add the search method to that controller.

4) You can then execute it like this: whatever/cars/search?term=g

The code for the macro looks like this:

def self.search_action_for(table, options={})
  table = table.to_s
  # Look up the constant by name, somehow
  model_class = table.classify.constantize
  # Pass a block to define_method, to set up the method in the controller
  define_method(:search) do
    @title = options[:title] || "Your #{table.humanize}"
    # Allow overriding of the search column
    search_column = options[:search_column] || 'model_name'
    @display_as = options[:display_as] || :model_name
    @display_path = options[:display_path] || "#{table.singularize}_path"
    @results = model_class.where("#{search_column} like ?", "%#{params[:term]}%")
    render 'shared/search_results'
  end
end

where model_name is an attribute in the Car model. I am curious about the ‘classify’, ‘constantize’, ‘humanize’, and ‘singularize’ methods.

‘classify’ is in ActiveSupport::Inflector. It creates a class name from a plural table name. If you give it “posts”, you will get “Post”. Then, calling ‘constantize’ tries to find a constant with the name specified in the string. So, if we do Cars.classify, we get a string “Car”, and then it will become a constant. (which can then be used as a class name)

‘humanize’ capitalizes the first word and turns underscores into spaces and strips off a trailing _id. So, ‘member_id’ would be turned into ‘Member’.

‘singularize’ is the reverse of ‘pluralize’.

Fowler also has an interesting comment: “Note that we are calling where() on the where variable. This was set outside the scope of our dynamic method definition to the model class for which we’re creating a search action. That class, via Ruby’s support for closures, gets embedded in the action and won’t be looked up again when the action is invoked.” I don’t understand this statement. ‘model_name’ must be a valid attribute of the model; but I don’t see how it is outside the scope of the dynamic method definition.

About

Macro controller method (Metaprogramming) from Chad Fowler Rails Recipes

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published