Permalink
Browse files

This commit merges most of the work done by Piotr Sarnacki in his Rub…

…y Summer of Code project.

His work brings several capabilities from app to engines, as routes, middleware stack, asset handling and much more. Please check Rails::Engine documentation for more refenrences.

Merge remote branch 'drogus/engines'
  • Loading branch information...
2 parents 63032c1 + c3c1a1e commit 23a9455962f0362cf242ffa96db7a9e7fdb0804b @josevalim josevalim committed Sep 3, 2010
Showing with 2,479 additions and 468 deletions.
  1. +0 −23 actionmailer/lib/action_mailer/base.rb
  2. +5 −2 actionmailer/lib/action_mailer/railtie.rb
  3. +1 −0 actionpack/lib/abstract_controller.rb
  4. +18 −0 actionpack/lib/abstract_controller/railties/routes_helpers.rb
  5. +1 −0 actionpack/lib/abstract_controller/rendering.rb
  6. +28 −0 actionpack/lib/abstract_controller/url_for.rb
  7. +1 −6 actionpack/lib/action_controller/base.rb
  8. +5 −1 actionpack/lib/action_controller/metal.rb
  9. +5 −1 actionpack/lib/action_controller/metal/helpers.rb
  10. +8 −16 actionpack/lib/action_controller/metal/url_for.rb
  11. +6 −3 actionpack/lib/action_controller/railtie.rb
  12. +20 −0 actionpack/lib/action_controller/railties/paths.rb
  13. +1 −0 actionpack/lib/action_dispatch/middleware/stack.rb
  14. +46 −18 actionpack/lib/action_dispatch/middleware/static.rb
  15. +1 −0 actionpack/lib/action_dispatch/routing.rb
  16. +38 −0 actionpack/lib/action_dispatch/routing/mapper.rb
  17. +25 −3 actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
  18. +55 −21 actionpack/lib/action_dispatch/routing/route_set.rb
  19. +35 −0 actionpack/lib/action_dispatch/routing/routes_proxy.rb
  20. +12 −0 actionpack/lib/action_dispatch/routing/url_for.rb
  21. +1 −1 actionpack/lib/action_dispatch/testing/test_request.rb
  22. +3 −0 actionpack/lib/action_view/helpers/asset_tag_helper.rb
  23. +5 −5 actionpack/lib/action_view/helpers/form_helper.rb
  24. +4 −0 actionpack/lib/action_view/helpers/url_helper.rb
  25. +64 −0 actionpack/test/activerecord/polymorphic_routes_test.rb
  26. +256 −0 actionpack/test/dispatch/prefix_generation_test.rb
  27. +29 −0 actionpack/test/dispatch/routing_test.rb
  28. +50 −11 actionpack/test/dispatch/static_test.rb
  29. +2 −1 actionpack/test/dispatch/url_generation_test.rb
  30. +1 −0 actionpack/test/fixtures/blog_public/.gitignore
  31. +1 −0 actionpack/test/fixtures/blog_public/blog.html
  32. +1 −0 actionpack/test/fixtures/blog_public/index.html
  33. +1 −0 actionpack/test/fixtures/blog_public/subdir/index.html
  34. +16 −1 actionpack/test/lib/controller/fake_models.rb
  35. +23 −0 actionpack/test/template/asset_tag_helper_test.rb
  36. +57 −50 actionpack/test/template/form_helper_test.rb
  37. +1 −1 actionpack/test/template/test_test.rb
  38. +38 −4 activemodel/lib/active_model/naming.rb
  39. +99 −0 activemodel/test/cases/naming_test.rb
  40. +13 −0 activemodel/test/models/blog_post.rb
  41. +67 −29 activerecord/lib/active_record/migration.rb
  42. +29 −6 activerecord/lib/active_record/railties/databases.rake
  43. +6 −0 activerecord/lib/rails/generators/active_record.rb
  44. +18 −0 activerecord/test/cases/helper.rb
  45. +125 −0 activerecord/test/cases/migration_test.rb
  46. 0 activerecord/test/migrations/empty/.gitkeep
  47. +9 −0 activerecord/test/migrations/to_copy/1_people_have_hobbies.rb
  48. +9 −0 activerecord/test/migrations/to_copy/2_people_have_descriptions.rb
  49. +9 −0 activerecord/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb
  50. +9 −0 activerecord/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb
  51. +9 −0 activerecord/test/migrations/valid_with_timestamps/20100101010101_people_have_last_names.rb
  52. +12 −0 activerecord/test/migrations/valid_with_timestamps/20100201010101_we_need_reminders.rb
  53. +12 −0 activerecord/test/migrations/valid_with_timestamps/20100301010101_innocent_jointable.rb
  54. +0 −5 railties/lib/rails.rb
  55. +13 −53 railties/lib/rails/application.rb
  56. +2 −5 railties/lib/rails/application/bootstrap.rb
  57. +0 −19 railties/lib/rails/application/configurable.rb
  58. +18 −14 railties/lib/rails/application/configuration.rb
  59. +8 −18 railties/lib/rails/application/railties.rb
  60. +0 −81 railties/lib/rails/configuration.rb
  61. +274 −4 railties/lib/rails/engine.rb
  62. +0 −25 railties/lib/rails/engine/configurable.rb
  63. +12 −0 railties/lib/rails/engine/configuration.rb
  64. +23 −0 railties/lib/rails/engine/railties.rb
  65. +15 −0 railties/lib/rails/plugin.rb
  66. +19 −10 railties/lib/rails/railtie.rb
  67. +19 −7 railties/lib/rails/railtie/configurable.rb
  68. +9 −1 railties/lib/rails/railtie/configuration.rb
  69. +21 −23 railties/test/application/configuration_test.rb
  70. +1 −0 railties/test/application/initializers/frameworks_test.rb
  71. +22 −0 railties/test/application/loading_test.rb
  72. +494 −0 railties/test/railties/engine_test.rb
  73. +174 −0 railties/test/railties/mounted_engine_test.rb
  74. +16 −0 railties/test/railties/railtie_test.rb
  75. +49 −0 railties/test/railties/shared_tests.rb
@@ -361,7 +361,6 @@ class Base < AbstractController::Base
}.freeze
class << self
-
def mailer_name
@mailer_name ||= name.underscore
end
@@ -725,28 +724,6 @@ def insert_part(container, response, charset) #:nodoc:
container.add_part(part)
end
- module DeprecatedUrlOptions
- def default_url_options
- deprecated_url_options
- end
-
- def default_url_options=(val)
- deprecated_url_options
- end
-
- def deprecated_url_options
- raise "You can no longer call ActionMailer::Base.default_url_options " \
- "directly. You need to set config.action_mailer.default_url_options. " \
- "If you are using ActionMailer standalone, you need to include the " \
- "routing url_helpers directly."
- end
- end
-
- # This module will complain if the user tries to set default_url_options
- # directly instead of through the config object. In Action Mailer's Railtie,
- # we include the router's url_helpers, which will override this module.
- extend DeprecatedUrlOptions
-
ActiveSupport.run_load_hooks(:action_mailer, self)
end
end
@@ -1,5 +1,6 @@
require "action_mailer"
require "rails"
+require "abstract_controller/railties/routes_helpers"
module ActionMailer
class Railtie < Rails::Railtie
@@ -18,9 +19,11 @@ class Railtie < Rails::Railtie
options.stylesheets_dir ||= paths.public.stylesheets.to_a.first
ActiveSupport.on_load(:action_mailer) do
- include app.routes.url_helpers
+ include AbstractController::UrlFor
+ extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
+ include app.routes.mounted_helpers(:app)
options.each { |k,v| send("#{k}=", v) }
end
end
end
-end
+end
@@ -24,4 +24,5 @@ module AbstractController
autoload :Translation
autoload :AssetPaths
autoload :ViewPaths
+ autoload :UrlFor
end
@@ -0,0 +1,18 @@
+module AbstractController
+ module Railties
+ module RoutesHelpers
+ def self.with(routes)
+ Module.new do
+ define_method(:inherited) do |klass|
+ super(klass)
+ if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) }
+ klass.send(:include, namespace._railtie.routes.url_helpers)
+ else
+ klass.send(:include, routes.url_helpers)
+ end
+ end
+ end
+ end
+ end
+ end
+end
@@ -52,6 +52,7 @@ def view_context_class
if controller.respond_to?(:_routes)
include controller._routes.url_helpers
+ include controller._routes.mounted_helpers
end
# TODO: Fix RJS to not require this
@@ -0,0 +1,28 @@
+module AbstractController
+ module UrlFor
+ extend ActiveSupport::Concern
+
+ include ActionDispatch::Routing::UrlFor
+
+ def _routes
+ raise "In order to use #url_for, you must include routing helpers explicitly. " \
+ "For instance, `include Rails.application.routes.url_helpers"
+ end
+
+ module ClassMethods
+ def _routes
+ nil
+ end
+
+ def action_methods
+ @action_methods ||= begin
+ if _routes
+ super - _routes.named_routes.helper_names
+ else
+ super
+ end
+ end
+ end
+ end
+ end
+end
@@ -221,11 +221,6 @@ def self.without_modules(*modules)
# Rails 2.x compatibility
include ActionController::Compatibility
- def self.inherited(klass)
- super
- klass.helper :all if klass.superclass == ActionController::Base
- end
-
ActiveSupport.run_load_hooks(:action_controller, self)
end
-end
+end
@@ -52,7 +52,11 @@ def build(action, app=nil, &block)
class Metal < AbstractController::Base
abstract!
- attr_internal :env
+ attr_internal_writer :env
+
+ def env
+ @_env ||= {}
+ end
# Returns the last part of the controller's name, underscored, without the ending
# <tt>Controller</tt>. For instance, PostsController returns <tt>posts</tt>.
@@ -101,8 +101,12 @@ def modules_for_helpers(args)
# Extract helper names from files in <tt>app/helpers/**/*_helper.rb</tt>
def all_application_helpers
+ all_helpers_from_path(helpers_path)
+ end
+
+ def all_helpers_from_path(path)
helpers = []
- Array.wrap(helpers_path).each do |path|
+ Array.wrap(path).each do |path|
extract = /^#{Regexp.quote(path.to_s)}\/?(.*)_helper.rb$/
helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
end
@@ -2,27 +2,19 @@ module ActionController
module UrlFor
extend ActiveSupport::Concern
- include ActionDispatch::Routing::UrlFor
+ include AbstractController::UrlFor
def url_options
- super.reverse_merge(
+ options = {}
+ if _routes.equal?(env["action_dispatch.routes"])
+ options[:script_name] = request.script_name.dup
+ end
+
+ super.merge(options).reverse_merge(
:host => request.host_with_port,
:protocol => request.protocol,
:_path_segments => request.symbolized_path_parameters
- ).merge(:script_name => request.script_name)
- end
-
- def _routes
- raise "In order to use #url_for, you must include routing helpers explicitly. " \
- "For instance, `include Rails.application.routes.url_helpers"
- end
-
- module ClassMethods
- def action_methods
- @action_methods ||= begin
- super - _routes.named_routes.helper_names
- end
- end
+ )
end
end
end
@@ -4,6 +4,8 @@
require "action_view/railtie"
require "active_support/deprecation/proxy_wrappers"
require "active_support/deprecation"
+require "abstract_controller/railties/routes_helpers"
+require "action_controller/railties/paths"
module ActionController
class Railtie < Rails::Railtie
@@ -47,10 +49,11 @@ class Railtie < Rails::Railtie
options.javascripts_dir ||= paths.public.javascripts.to_a.first
options.stylesheets_dir ||= paths.public.stylesheets.to_a.first
options.page_cache_directory ||= paths.public.to_a.first
- options.helpers_path ||= paths.app.helpers.to_a
ActiveSupport.on_load(:action_controller) do
- include app.routes.url_helpers
+ include app.routes.mounted_helpers(:app)
+ extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
+ extend ::ActionController::Railties::Paths.with(app)
options.each { |k,v| send("#{k}=", v) }
end
end
@@ -63,4 +66,4 @@ class Railtie < Rails::Railtie
ActionController::Routing::Routes = proxy
end
end
-end
+end
@@ -0,0 +1,20 @@
+module ActionController
+ module Railties
+ module Paths
+ def self.with(app)
+ Module.new do
+ define_method(:inherited) do |klass|
+ super(klass)
+ if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) }
+ klass.helpers_path = namespace._railtie.config.paths.app.helpers.to_a
+ else
+ klass.helpers_path = app.config.helpers_paths
+ end
+
+ klass.helper :all if klass.superclass == ActionController::Base
+ end
+ end
+ end
+ end
+ end
+end
@@ -1,4 +1,5 @@
require "active_support/inflector/methods"
+require "active_support/dependencies"
module ActionDispatch
class MiddlewareStack < Array
@@ -1,28 +1,58 @@
require 'rack/utils'
module ActionDispatch
+ class FileHandler
+ def initialize(at, root)
+ @at, @root = at.chomp('/'), root.chomp('/')
+ @compiled_at = Regexp.compile(/^#{Regexp.escape(at)}/) unless @at.blank?
+ @compiled_root = Regexp.compile(/^#{Regexp.escape(root)}/)
+ @file_server = ::Rack::File.new(root)
+ end
+
+ def match?(path)
+ path = path.dup
+ if @compiled_at.blank? || path.sub!(@compiled_at, '')
+ full_path = File.join(@root, ::Rack::Utils.unescape(path))
+ paths = "#{full_path}#{ext}"
+
+ matches = Dir[paths]
+ match = matches.detect { |m| File.file?(m) }
+ if match
+ match.sub!(@compiled_root, '')
+ match
+ end
+ end
+ end
+
+ def call(env)
+ @file_server.call(env)
+ end
+
+ def ext
+ @ext ||= begin
+ ext = ::ActionController::Base.page_cache_extension
+ "{,#{ext},/index#{ext}}"
+ end
+ end
+ end
+
class Static
FILE_METHODS = %w(GET HEAD).freeze
- def initialize(app, root)
+ def initialize(app, roots)
@app = app
- @file_server = ::Rack::File.new(root)
+ @file_handlers = create_file_handlers(roots)
end
def call(env)
path = env['PATH_INFO'].chomp('/')
method = env['REQUEST_METHOD']
if FILE_METHODS.include?(method)
- if file_exist?(path)
- return @file_server.call(env)
- else
- cached_path = directory_exist?(path) ? "#{path}/index" : path
- cached_path += ::ActionController::Base.page_cache_extension
-
- if file_exist?(cached_path)
- env['PATH_INFO'] = cached_path
- return @file_server.call(env)
+ @file_handlers.each do |file_handler|
+ if match = file_handler.match?(path)
+ env["PATH_INFO"] = match
+ return file_handler.call(env)
end
end
end
@@ -31,14 +61,12 @@ def call(env)
end
private
- def file_exist?(path)
- full_path = File.join(@file_server.root, ::Rack::Utils.unescape(path))
- File.file?(full_path) && File.readable?(full_path)
- end
+ def create_file_handlers(roots)
+ roots = { '' => roots } unless roots.is_a?(Hash)
- def directory_exist?(path)
- full_path = File.join(@file_server.root, ::Rack::Utils.unescape(path))
- File.directory?(full_path) && File.readable?(full_path)
+ roots.map do |at, root|
+ FileHandler.new(at, root) if File.exist?(root)
+ end.compact
end
end
end
@@ -268,6 +268,7 @@ module Routing
autoload :Mapper, 'action_dispatch/routing/mapper'
autoload :Route, 'action_dispatch/routing/route'
autoload :RouteSet, 'action_dispatch/routing/route_set'
+ autoload :RoutesProxy, 'action_dispatch/routing/routes_proxy'
autoload :UrlFor, 'action_dispatch/routing/url_for'
autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes'
Oops, something went wrong.

7 comments on commit 23a9455

Contributor

rubiii replied Sep 3, 2010

this is quite a lot of work. thanks piotr!

Contributor

ncr replied Sep 4, 2010

Massive merge. Respect @drogus :)

Drogus is da man!

Contributor

dmathieu replied Sep 6, 2010

Awesome !
For those who'd be wondering, Piotr has posted a detailed explanation here :
http://piotrsarnacki.com/2010/09/06/rsoc-status-namespacing-engines/

Member

drogus replied Sep 6, 2010

Actually there are 3 posts on that topic (but... beware, these are rather technical posts explaining what problems have I tried to solve and reasons behind decisions):
http://piotrsarnacki.com/2010/07/06/rsoc-status-briging-engine-closer-to-application/
http://piotrsarnacki.com/2010/07/20/rsoc-status-routes-aka-omg-it-s-hard/
http://piotrsarnacki.com/2010/09/06/rsoc-status-namespacing-engines/

I will prepare wrap up of all the changes with tutorial on how to use that soon :)

Member

drogus replied Sep 6, 2010

Also, thank you for your comments! :D Each of them makes me more and more motivated to continue such work.

Contributor

iain replied Sep 6, 2010

@drogus you deserve it! Thanks for your time and effort! :)

Please sign in to comment.