Skip to content

Instantly share code, notes, and snippets.

@amiel
Created October 10, 2012 21:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amiel/3868612 to your computer and use it in GitHub Desktop.
Save amiel/3868612 to your computer and use it in GitHub Desktop.
Testing routes with Rails 3.2 mountable engines and RSpec 2
# your-engine/lib/magic/rails/engine.rb
module Magic
module Rails
module Engine
##
# Automatically append all of the current engine's routes to the main
# application's route set. This needs to be done for ALL functional tests that
# use engine routes, since the mounted routes don't work during tests.
#
# @param [Symbol] engine_symbol Optional; if provided, uses this symbol to
# locate the engine class by name, otherwise uses the module of the calling
# test case as the presumed name of the engine.
#
# @author Jason Hamilton (jhamilton@greatherorift.com)
# @author Matthew Ratzloff (matt@urbaninfluence.com)
# @author Xavier Dutreilh (xavier@dutreilh.fr)
def load_engine_routes(engine_symbol = nil)
if engine_symbol
engine_name = engine_symbol.to_s.camelize
else
# No engine provided, so presume the current engine is the one to load
engine_name = self.class.name.split("::").first.split("(").last
end
engine = ("#{engine_name}::Engine").constantize
# Append the routes for this module to the existing routes
::Rails.application.routes.disable_clear_and_finalize = true
::Rails.application.routes.clear!
::Rails.application.routes_reloader.paths.each { |path| load(path) }
::Rails.application.routes.draw do
resourced_routes = []
named_routes = engine.routes.named_routes.routes
engine.routes.routes.each do |route|
# Call the method by hand based on the symbol
path = "/#{engine_name.underscore}#{route.path.spec}"
verb = route.verb.to_s.downcase.gsub(/^.+\^(.+)\$.+$/, '\1').to_sym
requirements = route.requirements
if path_helper = named_routes.key(route)
requirements[:as] = path_helper
elsif route.requirements[:controller].present?
# Presume that all controllers referenced in routes should also be
# resources and append that routing on the end so that *_path helpers
# will still work
resourced_routes << route.requirements[:controller].gsub("#{engine_name.underscore}/", "").to_sym
end
send(verb, path, requirements) if respond_to?(verb)
end
# Add each route, once, to the end under a scope to trick path helpers.
# This will probably break as soon as there is route name overlap, but
# we'll cross that bridge when we get to it.
resourced_routes.uniq!
scope engine_name.underscore do
resourced_routes.each do |resource|
resources resource
end
end
end
# Finalize the routes
::Rails.application.routes.finalize!
::Rails.application.routes.disable_clear_and_finalize = false
end
end
end
end
Rails::Engine.send(:include, Magic::Rails::Engine)
# your-engine/spec/support/routing.rb
require 'magic/rails/engine'
# Replace RspecRouting by the namespace used by your engine
RspecRouting::Engine.load_engine_routes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment