Jan 13

This is more of a quick rant on AliasMethodChain in Rails than a tutorial… Metaprogramming in Rails is powerful. It is a wonderful way to build onto a framework which itself is built on top of Ruby via metaprogramming. I’ve seen and heard many arguments describing metaprogramming as the root of all evil. The chaos that it can cause when not structured is a terrible thing to behold, certainly.

I won’t say much about how we handle our system extensions at Groupon, except, that it is very structured with a centralized place to discover all of the extensions to Rails internals in a single place (expect a more formal description of our process later from our Team!). Also, the extension points that we chose to use have been the parts of Rails which are the least subject to change (and have demonstrated the greatest resiliency and consistency over the last 3-4 years of active development).

Anyway, this morning, I ran into one of the (very few) cases where testing truly required assertions at various points in an alias_method_chain stack. As you can imagine, if you are alias_method_chaining ActiveRecord::Base#find, for example, you’ll most likely have architected your system in such a way, that every link in the chain is standard, unalterable behavior (we absolutely do not muck with #find, btw. It is already an atrocious method). For these cases, I employ this little hack…

ActiveSupport::CoreExtensions::Module.class_eval do
  def alias_method_chain_unlink(target, feature) 
 
    # Strip out punctuation on predicates or bang methods since
    # e.g. target?_without_feature is not a valid method name.
    aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
    yield(aliased_target, punctuation) if block_given?
 
    with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
 
    alias_method target, without_method
 
    case
    when public_method_defined?(without_method)
      public target
    when protected_method_defined?(without_method)
      protected target
    when private_method_defined?(without_method)
      private target
    end
  end
end

Notice its a natural inversion of ‘alias_method_chain’ implemention. This method would probably never fly with the core team, so it is merely a re-implementation/repurposing rather than an attempt to DRY the aliasing code.

As an example of what I’m talking about, imagine that you have this chain..

class User
  def cry
    puts "cry"
  end
end
 
User.new.cry
User.class_eval do
  def cry_with_emotion
    puts "WAH WAH WAH"
 
    cry_without_emotion
  end
 
  alias_method_chain :cry, :emotion
end
 
User.new.cry

Let us say that you want to alter the emotive nature of that extension in the same ruby session

User.class_eval do
  def cry_with_emotion # slightly less emotive
    puts "Wah Wah Wah"
 
    cry_without_emotion
  end
end
 
User.new.cry
 
User.class_eval do
  define_method :cry_with_emotion do
    puts "Wah Wah Wah"
  end
end
User.new.cry # no luck again eh??

As you can see, redefining an interstitial method does not automatically make it part of the chain! Try this on for size (after redefining your method).

User.class_eval do
  alias_method_chain_unlink :cry, :emotion
 
  alias_method_chain :cry, :emotion
end
User.new.cry

That works! If you can imagine it, this hack can serve to either allow you to remove something out of a long alias_method_chain, or, allow redefinition of chain link (for lack of a better term)! I might have more to say about metaprogramming in Ruby later, but for now, may this approach save someone as much time as it saved me!

Tagged with:
Jun 10

If you have ever had to support multiple subdomains in Rails, you’ve probably had the same questions that we all have.

  • Where do we place the switching mechanism and how does it work?
  • Does it affect controllers, or just views?
  • How do helpers factor into it our strategy?

There are tons of examples out there on the net. I’ve chosen (like many others) to do basic view path manipulation based on some sort of runtime switching. With Rails 2.3, however, the view-caching that happens when you set view_paths with the typical view_path methods (prepend_view_path, view_path=, etc…) is crazy expensive and a bit mysterious (unless you frequently hack around in the framework, but the majority of us don’t). The guys at Unspace seem to have arrived at a great solution for their switching needs. I did it a bit differently!

The Problem

ActionController::Base.view_paths looks like an array of file paths. It is NOT an array of file paths! It is a subclass of Array known as ActionView::PathSet containing instances of ActionView::Template::Path. The following examples, for this reason, are prohibitively nonperformant under heavy load with deep view hierarchies.

ActionController::Base.view_paths = ["app/views", "app/views/my_app", "app/views/your_app"]
or
ActionController::Base.prepend_view_path "app/views/my_app"

If you dynamically set the view paths with a bunch of strings, they will be typecast into ActionView::Template::Path objects which cache everything in the view path recursively… on EVERY REQUEST. Totally expensive!

The first obvious optimization (assuming you already have things wired up and are just trying to optimize the view path loading) would be to pre-process those String filepaths and store them so that view_path manipulation doesn’t incur that insane expense during a request.

My issue with this approach is that the internals of PathSet caching and its typecasting become implemented in runtime request code. The class definitions of the controllers is the last place that I’d put framework hackery of that complexity. In most of my applications, I have a pretty good division between bootstrap/runtime extensions to the framework and actual run-on-every-request application initialization code. I’d just monkey patch those path classes directly, and set the view paths once at bootstrap time.

My needs for switching in an application are basically…

  1. app/views would be your fallback path, application view paths would be mutually exclusive
  2. application views would be of the form…
    views, views/app1, views/app2, …, views/appN-1, views/appN
  3. Prioritization of a single app would lead to a view path set of the form…
    views/appX, views, views/app1, …. views/appX-1,views/appX+1,…. views/appN
  4. a per-request based switching mechanism (completely ignoring per-Controller view_paths)

A Solution

# Place these in a bootstrap-only file, like a config/initializers script.
ActionController::Base.class_eval
  # Assumes a per-application/request view prioritization, not per-controller
  cattr_accessor :application_view_path
  self.view_paths = %w(app/views
                       app/views/application_one
                       app/views/application_two).map do |path| Rails.root.join(path).to_s end
end
 
ActionView::PathSet.class_eval do
  def each_with_application_view_path(&block)
    application_view_path = ActionController::Base.application_view_path
 
    if application_view_path
      # remove and prepend the view path in question to the array BEFORE proceeding with the 'each' operation
      (select do |item|
        item.to_s == application_view_path
      end + reject do |item|
        item.to_s == application_view_path
      end).each(&block)
    else
      each_without_application_view_path(&block)
    end
  end
 
  # as usual, lets play nice with anything else in the call chain.
  alias_method_chain :each, :application_view_path
end
# Place this in application_controller
class ApplicationController < ActionController::Base
  before_filter :set_application_view_path
 
  def set_application_view_path
    ActionController::Base.application_view_path = request.subdomains.first # IF you happen to use subdomains to switch (i.e. store.app.com, inventory.app.com)
  end
end

To understand this completely, you MUST look at PathSet#find_template and understand how it works. After that, try imagining the cheapest way to influence the search order of the view paths. This method is one of those classic Rails-internals methods that does WAY too much in a single method. The only way to hack it is to override it completely or metaprogram a sneaky hack like this. I prefer the sneaky hack because influencing the iteration of the PathSet object introduces FAR less complexity than overriding or having a set of filters to constantly manage this stuff from the controllers.

Now, I have a personal rule to NEVER be immediately satisfied with with my first solution to a complex problem. Unlike music, where a first take for a guitar solo is usually imbued with an irreproducible spontaneity, my sweet spot for software is usually the second or third immediate refactoring!

I’ve been hearing about AOP from Ken Pelletier, my highly esteemed colleage (a dude that smiles fondly when he hears mention of Smalltalk) for years now. A sudden idea for a refactoring of this code gave me all impetus that I needed to dig into AOP and Rails. I wanted to see if using the AOP methodology would cleanup the pseudo-AOP-through-Ruby-metaprogramming junk that I typically code. Here’s the quick refactoring with Aquarium (AOP for Ruby).

A Better Solution

# Put all of this in a bootstrap-only initializer
ActionController::Base.class_eval do
  APP_ONE_VIEW_PATH = "app/views/application_one"
  APP_TWO_VIEW_PATH = "app/views/application_two"
 
  cattr_accessor  :application_view_path
  self.view_paths = ["app/views", APP_ONE_VIEW_PATH, APP_TWO_VIEW_PATH]
 
  # This is where you determine the switching mechanism for your application. Here, it is a simple GET parameter.
  # You can probably argue that this specific piece SHOULD be in your actual app_controller class definition, as it is the only piece
  # of info pertinent to the rest of your application.
  before_filter   do |controller|
    ActionController::Base.application_view_path = controller.params[:application_two] ? APP_TWO_VIEW_PATH : APP_ONE_VIEW_PATH
  end
end
 
require 'aquarium'
ActionView::PathSet.class_eval do
  include Aquarium::DSL
  before :find_template do |join_point, object, *args|
    object.each_with_index do |path,i|
      object.unshift(object.delete_at(i)) if path.to_s == ActionController::Base.application_view_path
    end
  end
end
# I'll leave the exercise of testing this or implementing it for your particular app up to you.

As you can see, AOP allows the operation to be expressed very cleanly and succinctly. I love the feeling of swiping in some functionality horizontally through the framework code, in a way that doesn’t rely on too much internal knowledge of its workings.  AOP seems really powerful but it will probably require quite a bit of discipline to use it properly on a very large Rails system in a performant way. Hopefully more resources on AOP best-practices emerge soon (I mean specifically for Ruby, we are sort of handicapped by the performance hit of using this wonderful framework).

I should apologize for moving through this stuff without as much explanation as it deserves. AOP is pretty badass. I’m going to be digesting all of the literature on this topic for a while! Next time, I’ll blog about something Music-related. I think that you’ll start seeing the parallels in Music Composition and Software Engineering pretty clearly. On that topic, Jonathan Dahl gave a pretty good presentation on the parallels between music and software at RailsConf this year. It was a great presentation, and everything he had to say was right on the money. For the first time, however, I got the feeling that it was a topic upon which I could expound prolifically. I’m going to try and formulate some interesting content along those lines!

Tagged with:
preload preload preload