Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
SmartUrlHelper - configurable replacement for url_for. See
SmartUrlHelper.configure do |url|
url.for ->model{ model.is_a?(Comment) } do |helpers, model|
helpers.post_comment_path(, model)
# TODO: Add a convenience method for matching on type:
# url.for(Comment) do |helpers, model|
# helpers.post_comment_path(, model)
# end
module SmartUrlHelper
# A smarter replacement for #url_for. First checks to see if a
# special-case handler has been registered for the given model. If so,
# use that to generate the URL. If not, fall back to Rails' #url_for helper.
# Special-case handlers should be registered in a config/initializer that
# calls SmartUrlHelper.configure.
# Returns the default URL for the given model.
def smart_url_for(model, *args)
url = ::SmartUrlHelper::SmartUrlConfiguration.lookup_smart_url(self, model, *args)
return url if url.present?
url_for(model, *args)
# Call in config/initializer to register model handlers.
# Takes a block for an instance of SmartUlrConfiguration.
def self.configure
Rails.application.config.smart_url_handlers = []
# Provides the DSL for registering model handlers in SmartUrlHelper.configure
class SmartUrlConfiguration
# Registers a handler to generate a URL for a model that matches the predicate
# predicate - A lambda that takes in a model instance and returns true
# if the handler can generate a URL for the given model.
# url_generator - A block that builds a url for the given model.
# The block will receive a helper object and the model
# as parameters.
def for(predicate, &url_generator)
self.class.handlers << [predicate, url_generator]
def self.handlers
def self.lookup_smart_url(context, model, *args)
handler = self.handlers.detect{|h| h[0].call(model)}
return nil unless handler.present?
handler[1].call(context, model)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment