aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
Diffstat (limited to 'railties')
-rw-r--r--railties/lib/rails.rb5
-rw-r--r--railties/lib/rails/application.rb66
-rw-r--r--railties/lib/rails/application/bootstrap.rb7
-rw-r--r--railties/lib/rails/application/configurable.rb19
-rw-r--r--railties/lib/rails/application/configuration.rb32
-rw-r--r--railties/lib/rails/application/railties.rb26
-rw-r--r--railties/lib/rails/configuration.rb81
-rw-r--r--railties/lib/rails/engine.rb278
-rw-r--r--railties/lib/rails/engine/configurable.rb25
-rw-r--r--railties/lib/rails/engine/configuration.rb12
-rw-r--r--railties/lib/rails/engine/railties.rb23
-rw-r--r--railties/lib/rails/plugin.rb15
-rw-r--r--railties/lib/rails/railtie.rb29
-rw-r--r--railties/lib/rails/railtie/configurable.rb26
-rw-r--r--railties/lib/rails/railtie/configuration.rb10
-rw-r--r--railties/test/application/configuration_test.rb44
-rw-r--r--railties/test/application/initializers/frameworks_test.rb1
-rw-r--r--railties/test/application/loading_test.rb22
-rw-r--r--railties/test/railties/engine_test.rb494
-rw-r--r--railties/test/railties/mounted_engine_test.rb174
-rw-r--r--railties/test/railties/railtie_test.rb16
-rw-r--r--railties/test/railties/shared_tests.rb49
22 files changed, 1189 insertions, 265 deletions
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index 7c41367a84..3663910281 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -94,10 +94,5 @@ module Rails
def public_path
application && application.paths.public.to_a.first
end
-
- def public_path=(path)
- ActiveSupport::Deprecation.warn "Setting Rails.public_path= is deprecated. " <<
- "Please set paths.public = in config/application.rb instead.", caller
- end
end
end
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 5b26333486..8631a5df3e 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -41,24 +41,6 @@ module Rails
autoload :Railties, 'rails/application/railties'
class << self
- private :new
-
- def configure(&block)
- class_eval(&block)
- end
-
- def instance
- if self == Rails::Application
- if Rails.application
- ActiveSupport::Deprecation.warn "Calling a method in Rails::Application is deprecated, " <<
- "please call it directly in your application constant #{Rails.application.class.name}.", caller
- end
- Rails.application
- else
- @@instance ||= new
- end
- end
-
def inherited(base)
raise "You cannot have more than one Rails::Application" if Rails.application
super
@@ -66,19 +48,9 @@ module Rails
Rails.application.add_lib_to_load_path!
ActiveSupport.run_load_hooks(:before_configuration, base.instance)
end
-
- def respond_to?(*args)
- super || instance.respond_to?(*args)
- end
-
- protected
-
- def method_missing(*args, &block)
- instance.send(*args, &block)
- end
end
- delegate :middleware, :to => :config
+ delegate :default_url_options, :default_url_options=, :to => :routes
# This method is called just after an application inherits from Rails::Application,
# allowing the developer to load classes in lib and use them during application
@@ -108,14 +80,6 @@ module Rails
super
end
- def routes
- @routes ||= ActionDispatch::Routing::RouteSet.new
- end
-
- def railties
- @railties ||= Railties.new(config)
- end
-
def routes_reloader
@routes_reloader ||= ActiveSupport::FileUpdateChecker.new([]){ reload_routes! }
end
@@ -131,7 +95,9 @@ module Rails
end
def initialize!
+ raise "Application has been already initialized." if @initialized
run_initializers(self)
+ @initialized = true
self
end
@@ -156,38 +122,32 @@ module Rails
self
end
- def app
- @app ||= begin
- config.middleware = config.middleware.merge_into(default_middleware_stack)
- config.middleware.build(routes)
- end
- end
alias :build_middleware_stack :app
- def call(env)
- app.call(env.reverse_merge!(env_defaults))
- end
-
- def env_defaults
- @env_defaults ||= {
+ def env_config
+ @env_config ||= super.merge({
"action_dispatch.parameter_filter" => config.filter_parameters,
- "action_dispatch.secret_token" => config.secret_token
- }
+ "action_dispatch.secret_token" => config.secret_token,
+ "action_dispatch.asset_path" => nil
+ })
end
def initializers
initializers = Bootstrap.initializers_for(self)
- railties.all { |r| initializers += r.initializers }
initializers += super
initializers += Finisher.initializers_for(self)
initializers
end
+ def config
+ @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd))
+ end
+
protected
def default_middleware_stack
ActionDispatch::MiddlewareStack.new.tap do |middleware|
- middleware.use ::ActionDispatch::Static, paths.public.to_a.first if config.serve_static_assets
+ middleware.use ::ActionDispatch::Static, config.static_asset_paths if config.serve_static_assets
middleware.use ::Rack::Lock if !config.allow_concurrency
middleware.use ::Rack::Runtime
middleware.use ::Rails::Rack::Logger
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index 44e26b5713..e39b3bc705 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -6,10 +6,7 @@ module Rails
module Bootstrap
include Initializable
- initializer :load_environment_config do
- environment = config.paths.config.environments.to_a.first
- require environment if environment
- end
+ initializer :load_environment_hook do end
initializer :load_active_support do
require 'active_support/dependencies'
@@ -73,4 +70,4 @@ module Rails
end
end
end
-end \ No newline at end of file
+end
diff --git a/railties/lib/rails/application/configurable.rb b/railties/lib/rails/application/configurable.rb
deleted file mode 100644
index f598e33965..0000000000
--- a/railties/lib/rails/application/configurable.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module Rails
- class Application
- module Configurable
- def self.included(base)
- base.extend ClassMethods
- end
-
- module ClassMethods
- def inherited(base)
- raise "You cannot inherit from a Rails::Application child"
- end
- end
-
- def config
- @config ||= Application::Configuration.new(self.class.find_root_with_flag("config.ru", Dir.pwd))
- end
- end
- end
-end \ No newline at end of file
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index c3418e0d80..477bbbc1e7 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -1,16 +1,13 @@
-require 'active_support/deprecation'
require 'active_support/core_ext/string/encoding'
require 'rails/engine/configuration'
module Rails
class Application
class Configuration < ::Rails::Engine::Configuration
- include ::Rails::Configuration::Deprecated
-
attr_accessor :allow_concurrency, :cache_classes, :cache_store,
:encoding, :consider_all_requests_local, :dependency_loading,
- :filter_parameters, :log_level, :logger, :middleware,
- :plugins, :preload_frameworks, :reload_plugins,
+ :filter_parameters, :log_level, :logger,
+ :preload_frameworks, :reload_plugins,
:secret_token, :serve_static_assets, :session_options,
:time_zone, :whiny_nils
@@ -28,6 +25,22 @@ module Rails
@middleware = app_middleware
end
+ def asset_path=(value)
+ action_mailer.asset_path = value if respond_to?(:action_mailer) && action_mailer
+ action_controller.asset_path = value if respond_to?(:action_controller) && action_controller
+ super(value)
+ end
+
+ def asset_host=(value)
+ action_mailer.asset_host = value if action_mailer
+ action_controller.asset_host = value if action_controller
+ super(value)
+ end
+
+ def compiled_asset_path
+ "/"
+ end
+
def encoding=(value)
@encoding = value
if "ruby".encoding_aware?
@@ -48,19 +61,10 @@ module Rails
paths.app.controllers << builtin_controller if builtin_controller
paths.config.database "config/database.yml"
paths.config.environment "config/environment.rb"
- paths.config.environments "config/environments", :glob => "#{Rails.env}.rb"
paths.lib.templates "lib/templates"
paths.log "log/#{Rails.env}.log"
paths.tmp "tmp"
paths.tmp.cache "tmp/cache"
- paths.vendor "vendor", :load_path => true
- paths.vendor.plugins "vendor/plugins"
-
- if File.exists?("#{root}/test/mocks/#{Rails.env}")
- ActiveSupport::Deprecation.warn "\"Rails.root/test/mocks/#{Rails.env}\" won't be added " <<
- "automatically to load paths anymore in future releases"
- paths.mocks_path "test/mocks", :autoload => true, :glob => Rails.env
- end
paths
end
diff --git a/railties/lib/rails/application/railties.rb b/railties/lib/rails/application/railties.rb
index b3e6693f89..c1d2de571f 100644
--- a/railties/lib/rails/application/railties.rb
+++ b/railties/lib/rails/application/railties.rb
@@ -1,31 +1,21 @@
-module Rails
- class Application
- class Railties
- # TODO Write tests for this behavior extracted from Application
- def initialize(config)
- @config = config
- end
+require 'rails/engine/railties'
+module Rails
+ class Application < Engine
+ class Railties < Rails::Engine::Railties
def all(&block)
- @all ||= railties + engines + plugins
+ @all ||= railties + engines + super
@all.each(&block) if block
@all
end
def railties
- @railties ||= ::Rails::Railtie.subclasses.map(&:new)
+ @railties ||= ::Rails::Railtie.subclasses.map(&:instance)
end
def engines
- @engines ||= ::Rails::Engine.subclasses.map(&:new)
- end
-
- def plugins
- @plugins ||= begin
- plugin_names = (@config.plugins || [:all]).map { |p| p.to_sym }
- Plugin.all(plugin_names, @config.paths.vendor.plugins)
- end
+ @engines ||= ::Rails::Engine.subclasses.map(&:instance)
end
end
end
-end \ No newline at end of file
+end
diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb
index e5af12b901..8369795e71 100644
--- a/railties/lib/rails/configuration.rb
+++ b/railties/lib/rails/configuration.rb
@@ -71,86 +71,5 @@ module Rails
end
end
end
-
- module Deprecated
- def frameworks(*args)
- raise "config.frameworks in no longer supported. See the generated " \
- "config/boot.rb for steps on how to limit the frameworks that " \
- "will be loaded"
- end
- alias :frameworks= :frameworks
-
- def view_path=(value)
- ActiveSupport::Deprecation.warn "config.view_path= is deprecated, " <<
- "please do paths.app.views= instead", caller
- paths.app.views = value
- end
-
- def view_path
- ActiveSupport::Deprecation.warn "config.view_path is deprecated, " <<
- "please do paths.app.views instead", caller
- paths.app.views.to_a.first
- end
-
- def routes_configuration_file=(value)
- ActiveSupport::Deprecation.warn "config.routes_configuration_file= is deprecated, " <<
- "please do paths.config.routes= instead", caller
- paths.config.routes = value
- end
-
- def routes_configuration_file
- ActiveSupport::Deprecation.warn "config.routes_configuration_file is deprecated, " <<
- "please do paths.config.routes instead", caller
- paths.config.routes.to_a.first
- end
-
- def database_configuration_file=(value)
- ActiveSupport::Deprecation.warn "config.database_configuration_file= is deprecated, " <<
- "please do paths.config.database= instead", caller
- paths.config.database = value
- end
-
- def database_configuration_file
- ActiveSupport::Deprecation.warn "config.database_configuration_file is deprecated, " <<
- "please do paths.config.database instead", caller
- paths.config.database.to_a.first
- end
-
- def log_path=(value)
- ActiveSupport::Deprecation.warn "config.log_path= is deprecated, " <<
- "please do paths.log= instead", caller
- paths.config.log = value
- end
-
- def log_path
- ActiveSupport::Deprecation.warn "config.log_path is deprecated, " <<
- "please do paths.log instead", caller
- paths.config.log.to_a.first
- end
-
- def controller_paths=(value)
- ActiveSupport::Deprecation.warn "config.controller_paths= is deprecated, " <<
- "please do paths.app.controllers= instead", caller
- paths.app.controllers = value
- end
-
- def controller_paths
- ActiveSupport::Deprecation.warn "config.controller_paths is deprecated, " <<
- "please do paths.app.controllers instead", caller
- paths.app.controllers.to_a.uniq
- end
-
- def cookie_secret=(value)
- ActiveSupport::Deprecation.warn "config.cookie_secret= is deprecated, " <<
- "please use config.secret_token= instead", caller
- self.secret_token = value
- end
-
- def cookie_secret
- ActiveSupport::Deprecation.warn "config.cookie_secret is deprecated, " <<
- "please use config.secret_token instead", caller
- self.secret_token
- end
- end
end
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 555bc9dbc8..e10980a6d9 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -2,6 +2,7 @@ require 'rails/railtie'
require 'active_support/core_ext/module/delegation'
require 'pathname'
require 'rbconfig'
+require 'rails/engine/railties'
module Rails
# Rails::Engine allows you to wrap a specific Rails application and share it accross
@@ -86,14 +87,172 @@ module Rails
# all folders under "app" are automatically added to the load path. So if you have
# "app/observers", it's added by default.
#
+ # == Endpoint
+ #
+ # Engine can be also a rack application. It can be useful if you have a rack application that
+ # you would like to wrap with Engine and provide some of the Engine's features.
+ #
+ # To do that, use endpoint method:
+ # module MyEngine
+ # class Engine < Rails::Engine
+ # endpoint MyRackApplication
+ # end
+ # end
+ #
+ # Now you can mount your engine in application's routes just like that:
+ #
+ # MyRailsApp::Application.routes.draw do
+ # mount MyEngine::Engine => "/engine"
+ # end
+ #
+ # == Middleware stack
+ #
+ # As Engine can now be rack endpoint, it can also have a middleware stack. The usage is exactly
+ # the same as in application:
+ #
+ # module MyEngine
+ # class Engine < Rails::Engine
+ # middleware.use SomeMiddleware
+ # end
+ # end
+ #
+ # == Routes
+ #
+ # If you don't specify endpoint, routes will be used as default endpoint. You can use them
+ # just like you use application's routes:
+ #
+ # # ENGINE/config/routes.rb
+ # MyEngine::Engine.routes.draw do
+ # match "/" => "posts#index"
+ # end
+ #
+ # == Mount priority
+ #
+ # Note that now there can be more than one router in you application and it's better to avoid
+ # passing requests through many routers. Consider such situation:
+ #
+ # MyRailsApp::Application.routes.draw do
+ # mount MyEngine::Engine => "/blog"
+ # match "/blog/omg" => "main#omg"
+ # end
+ #
+ # MyEngine is mounted at "/blog" path and additionaly "/blog/omg" points application's controller.
+ # In such situation request to "/blog/omg" will go through MyEngine and if there is no such route
+ # in Engine's routes, it will be dispatched to "main#omg". It's much better to swap that:
+ #
+ # MyRailsApp::Application.routes.draw do
+ # match "/blog/omg" => "main#omg"
+ # mount MyEngine::Engine => "/blog"
+ # end
+ #
+ # Now, Engine will get only requests that were not handled by application.
+ #
+ # == Asset path
+ #
+ # When you use engine with its own public directory, you will probably want to copy or symlink it
+ # to application's public directory. To simplify generating paths for assets, you can set asset_path
+ # for an Engine:
+ #
+ # module MyEngine
+ # class Engine < Rails::Engine
+ # config.asset_path = "/my_engine/%s"
+ # end
+ # end
+ #
+ # With such config, asset paths will be automatically modified inside Engine:
+ # image_path("foo.jpg") #=> "/my_engine/images/foo.jpg"
+ #
+ # == Engine name
+ #
+ # There are some places where engine's name is used.
+ # * routes: when you mount engine with mount(MyEngine::Engine => '/my_engine'), it's used as default :as option
+ # * migrations: when you copy engine's migrations, they will be decorated with suffix based on engine_name, for example:
+ # 2010010203121314_create_users.my_engine.rb
+ #
+ # Engine name is set by default based on class name. For MyEngine::Engine it will be my_engine_engine.
+ # You can change it manually it manually using engine_name method:
+ #
+ # module MyEngine
+ # class Engine < Rails::Engine
+ # engine_name "my_engine"
+ # end
+ # end
+ #
+ # == Namespaced Engine
+ #
+ # Normally, when you create controllers, helpers and models inside engine, they are treated
+ # as they would be created inside application. One of the cosequences of that is including
+ # application's helpers and url_helpers inside controller. Sometimes, especially when your
+ # engine provides its own routes, you don't want that. To isolate engine's stuff from application
+ # you can use namespace method:
+ #
+ # module MyEngine
+ # class Engine < Rails::Engine
+ # namespace MyEngine
+ # end
+ # end
+ #
+ # With such Engine, everything that is inside MyEngine module, will be isolated from application.
+ #
+ # Consider such controller:
+ #
+ # module MyEngine
+ # class FooController < ActionController::Base
+ # end
+ # end
+ #
+ # If engine is marked as namespaced, FooController has access only to helpers from engine and
+ # url_helpers from MyEngine::Engine.routes.
+ #
+ # Additionaly namespaced engine will set its name according to namespace, so in that case:
+ # MyEngine::Engine.engine_name #=> "my_engine"
+ # and it will set MyEngine.table_name_prefix to "my_engine_"
+ #
+ # == Using Engine's routes outside Engine
+ #
+ # Since you can mount engine inside application's routes now, you do not have direct access to engine's
+ # url_helpers inside application. When you mount Engine in application's routes special helper is
+ # created to allow doing that. Consider such scenario:
+ #
+ # # APP/config/routes.rb
+ # MyApplication::Application.routes.draw do
+ # mount MyEngine::Engine => "/my_engine", :as => "my_engine"
+ # match "/foo" => "foo#index"
+ # end
+ #
+ # Now, you can use my_engine helper:
+ #
+ # class FooController < ApplicationController
+ # def index
+ # my_engine.root_url #=> /my_engine/
+ # end
+ # end
+ #
+ # There is also 'app' helper that gives you access to application's routes inside Engine:
+ #
+ # module MyEngine
+ # class BarController
+ # app.foo_path #=> /foo
+ # end
+ # end
+ #
+ # Note that :as option takes engine_name as default, so most of the time you can ommit it.
+ #
+ # If you want to generate url to engine's route using polymorphic_url, you can also use that helpers.
+ #
+ # Let's say that you want to create a form pointing to one of the engine's routes. All you need to do
+ # is passing helper as the first element in array with attributes for url:
+ #
+ # form_for([my_engine, @user])
+ #
+ # This code will use my_engine.user_path(@user) to generate proper route.
+ #
class Engine < Railtie
autoload :Configurable, "rails/engine/configurable"
autoload :Configuration, "rails/engine/configuration"
class << self
- attr_accessor :called_from
-
- # TODO Remove this. It's deprecated.
+ attr_accessor :called_from, :namespaced
alias :engine_name :railtie_name
def inherited(base)
@@ -122,9 +281,40 @@ module Rails
RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ?
Pathname.new(root).expand_path : Pathname.new(root).realpath
end
+
+ def endpoint(endpoint = nil)
+ @endpoint = endpoint if endpoint
+ @endpoint
+ end
+
+ def namespace(mod)
+ # TODO: extract that into a module
+ engine_name(generate_railtie_name(mod))
+
+ _railtie = self
+ name = engine_name
+ mod.singleton_class.instance_eval do
+ define_method(:_railtie) do
+ _railtie
+ end
+
+ define_method(:table_name_prefix) do
+ "#{name}_"
+ end
+ end
+
+ self.routes.default_scope = {:module => name}
+
+ self.namespaced = true
+ end
+
+ def namespaced?
+ !!namespaced
+ end
end
- delegate :paths, :root, :to => :config
+ delegate :middleware, :root, :paths, :to => :config
+ delegate :engine_name, :namespaced?, :to => "self.class"
def load_tasks
super
@@ -140,6 +330,47 @@ module Rails
end
end
+ def railties
+ @railties ||= self.class::Railties.new(config)
+ end
+
+ def app
+ @app ||= begin
+ config.middleware = config.middleware.merge_into(default_middleware_stack)
+ config.middleware.build(endpoint)
+ end
+ end
+
+ def endpoint
+ self.class.endpoint || routes
+ end
+
+ def call(env)
+ app.call(env.merge!(env_config))
+ end
+
+ def env_config
+ @env_config ||= {
+ 'action_dispatch.routes' => routes,
+ 'action_dispatch.asset_path' => config.asset_path
+ }
+ end
+
+ def routes
+ @routes ||= ActionDispatch::Routing::RouteSet.new
+ end
+
+ def initializers
+ initializers = []
+ railties.all { |r| initializers += r.initializers }
+ initializers += super
+ initializers
+ end
+
+ def config
+ @config ||= Engine::Configuration.new(find_root_with_flag("lib"))
+ end
+
# Add configured load paths to ruby load paths and remove duplicates.
initializer :set_load_path, :before => :bootstrap_hook do
_all_load_paths.reverse_each do |path|
@@ -196,6 +427,27 @@ module Rails
end
end
+ initializer :load_environment_config, :before => :load_environment_hook do
+ environment = config.paths.config.environments.to_a.first
+ require environment if environment
+ end
+
+ initializer :append_asset_paths do
+ config.asset_path = "/#{engine_name}%s" unless config.asset_path
+
+ public_path = config.paths.public.to_a.first
+ if config.compiled_asset_path && File.exist?(public_path)
+ config.static_asset_paths[config.compiled_asset_path] = public_path
+ end
+ end
+
+ initializer :prepend_helpers_path do
+ unless namespaced?
+ config.helpers_paths = [] unless config.respond_to?(:helpers_paths)
+ config.helpers_paths = config.paths.app.helpers.to_a + config.helpers_paths
+ end
+ end
+
initializer :load_config_initializers do
paths.config.initializers.to_a.sort.each do |initializer|
load(initializer)
@@ -208,6 +460,24 @@ module Rails
end
protected
+ def find_root_with_flag(flag, default=nil)
+ root_path = self.class.called_from
+
+ while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
+ parent = File.dirname(root_path)
+ root_path = parent != root_path && parent
+ end
+
+ root = File.exist?("#{root_path}/#{flag}") ? root_path : default
+ raise "Could not find root path for #{self}" unless root
+
+ Config::CONFIG['host_os'] =~ /mswin|mingw/ ?
+ Pathname.new(root).expand_path : Pathname.new(root).realpath
+ end
+
+ def default_middleware_stack
+ ActionDispatch::MiddlewareStack.new
+ end
def _all_autoload_paths
@_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq
diff --git a/railties/lib/rails/engine/configurable.rb b/railties/lib/rails/engine/configurable.rb
deleted file mode 100644
index 9a370f0abb..0000000000
--- a/railties/lib/rails/engine/configurable.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-module Rails
- class Engine
- module Configurable
- def self.included(base)
- base.extend ClassMethods
- end
-
- module ClassMethods
- delegate :middleware, :root, :paths, :to => :config
-
- def config
- @config ||= Engine::Configuration.new(find_root_with_flag("lib"))
- end
-
- def inherited(base)
- raise "You cannot inherit from a Rails::Engine child"
- end
- end
-
- def config
- self.class.config
- end
- end
- end
-end \ No newline at end of file
diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb
index 521ed95447..3ac8911ba8 100644
--- a/railties/lib/rails/engine/configuration.rb
+++ b/railties/lib/rails/engine/configuration.rb
@@ -5,10 +5,13 @@ module Rails
class Configuration < ::Rails::Railtie::Configuration
attr_reader :root
attr_writer :eager_load_paths, :autoload_once_paths, :autoload_paths
+ attr_accessor :middleware, :plugins, :asset_path
def initialize(root=nil)
super()
@root = root
+ @middleware = Rails::Configuration::MiddlewareStackProxy.new
+ @helpers_paths = []
end
def paths
@@ -26,9 +29,14 @@ module Rails
paths.config.initializers "config/initializers", :glob => "**/*.rb"
paths.config.locales "config/locales", :glob => "*.{rb,yml}"
paths.config.routes "config/routes.rb"
+ paths.config.environments "config/environments", :glob => "#{Rails.env}.rb"
paths.public "public"
paths.public.javascripts "public/javascripts"
paths.public.stylesheets "public/stylesheets"
+ paths.vendor "vendor", :load_path => true
+ paths.vendor.plugins "vendor/plugins"
+ paths.db "db"
+ paths.db.migrate "db/migrate"
paths
end
end
@@ -48,6 +56,10 @@ module Rails
def autoload_paths
@autoload_paths ||= paths.autoload_paths
end
+
+ def compiled_asset_path
+ asset_path % "" if asset_path
+ end
end
end
end
diff --git a/railties/lib/rails/engine/railties.rb b/railties/lib/rails/engine/railties.rb
new file mode 100644
index 0000000000..389a7602c6
--- /dev/null
+++ b/railties/lib/rails/engine/railties.rb
@@ -0,0 +1,23 @@
+module Rails
+ class Engine < Railtie
+ class Railties
+ # TODO Write tests for this behavior extracted from Application
+ def initialize(config)
+ @config = config
+ end
+
+ def all(&block)
+ @all ||= plugins
+ @all.each(&block) if block
+ @all
+ end
+
+ def plugins
+ @plugins ||= begin
+ plugin_names = (@config.plugins || [:all]).map { |p| p.to_sym }
+ Plugin.all(plugin_names, @config.paths.vendor.plugins)
+ end
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb
index 8d5132a5ca..c07ff2f9cf 100644
--- a/railties/lib/rails/plugin.rb
+++ b/railties/lib/rails/plugin.rb
@@ -18,6 +18,10 @@ module Rails
# root during the boot process.
#
class Plugin < Engine
+ def self.global_plugins
+ @global_plugins ||= []
+ end
+
def self.inherited(base)
raise "You cannot inherit from Rails::Plugin"
end
@@ -28,6 +32,11 @@ module Rails
Dir["#{path}/*"].each do |plugin_path|
plugin = new(plugin_path)
next unless list.include?(plugin.name) || list.include?(:all)
+ if global_plugins.include?(plugin.name)
+ warn "WARNING: plugin #{plugin.name} from #{path} was not loaded. Plugin with the same name has been already loaded."
+ next
+ end
+ global_plugins << plugin.name
plugins << plugin
end
end
@@ -39,6 +48,10 @@ module Rails
attr_reader :name, :path
+ def railtie_name
+ name.to_s
+ end
+
def load_tasks
super
load_deprecated_tasks
@@ -78,6 +91,8 @@ module Rails
ActiveSupport::Deprecation.warn "Use toplevel init.rb; rails/init.rb is deprecated: #{initrb}"
end
config = app.config
+ # TODO: think about evaling initrb in context of Engine (currently it's
+ # always evaled in context of Rails::Application)
eval(File.read(initrb), binding, initrb)
end
end
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index 58b0d851f7..09650789ac 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -1,7 +1,6 @@
require 'rails/initializable'
require 'rails/configuration'
require 'active_support/inflector'
-require 'active_support/deprecation'
module Rails
# Railtie is the core of the Rails Framework and provides several hooks to extend
@@ -131,25 +130,19 @@ module Rails
ABSTRACT_RAILTIES = %w(Rails::Railtie Rails::Plugin Rails::Engine Rails::Application)
class << self
+ private :new
+
def subclasses
@subclasses ||= []
end
def inherited(base)
unless base.abstract_railtie?
- base.send(:include, self::Configurable)
+ base.send(:include, Railtie::Configurable)
subclasses << base
end
end
- def railtie_name(*)
- ActiveSupport::Deprecation.warn "railtie_name is deprecated and has no effect", caller
- end
-
- def log_subscriber(*)
- ActiveSupport::Deprecation.warn "log_subscriber is deprecated and has no effect", caller
- end
-
def rake_tasks(&blk)
@rake_tasks ||= []
@rake_tasks << blk if blk
@@ -171,6 +164,22 @@ module Rails
def abstract_railtie?
ABSTRACT_RAILTIES.include?(name)
end
+
+ def railtie_name(name = nil)
+ @railtie_name = name.to_s if name
+ @railtie_name ||= generate_railtie_name(self.name)
+ end
+
+ protected
+ def generate_railtie_name(class_or_module)
+ ActiveSupport::Inflector.underscore(class_or_module).gsub("/", "_")
+ end
+ end
+
+ delegate :railtie_name, :to => "self.class"
+
+ def config
+ @config ||= Railtie::Configuration.new
end
def eager_load!
diff --git a/railties/lib/rails/railtie/configurable.rb b/railties/lib/rails/railtie/configurable.rb
index a2eb938c5a..b6d4ed2312 100644
--- a/railties/lib/rails/railtie/configurable.rb
+++ b/railties/lib/rails/railtie/configurable.rb
@@ -6,17 +6,29 @@ module Rails
end
module ClassMethods
- def config
- @config ||= Railtie::Configuration.new
- end
+ delegate :config, :to => :instance
def inherited(base)
- raise "You cannot inherit from a Rails::Railtie child"
+ raise "You cannot inherit from a #{self.superclass.name} child"
end
- end
- def config
- self.class.config
+ def instance
+ @instance ||= new
+ end
+
+ def respond_to?(*args)
+ super || instance.respond_to?(*args)
+ end
+
+ def configure(&block)
+ class_eval(&block)
+ end
+
+ protected
+
+ def method_missing(*args, &block)
+ instance.send(*args, &block)
+ end
end
end
end
diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb
index 4e6f94c534..f09e3940cc 100644
--- a/railties/lib/rails/railtie/configuration.rb
+++ b/railties/lib/rails/railtie/configuration.rb
@@ -5,6 +5,7 @@ module Rails
class Configuration
def initialize
@@options ||= {}
+ @@static_asset_paths = ActiveSupport::OrderedHash.new
end
# This allows you to modify the application's middlewares from Engines.
@@ -65,6 +66,13 @@ module Rails
super || @@options.key?(name.to_sym)
end
+ # static_asset_paths is a Hash containing asset_paths
+ # with associated public folders, like:
+ # { "/" => "/app/public", "/my_engine" => "app/engines/my_engine/public" }
+ def static_asset_paths
+ @@static_asset_paths
+ end
+
private
def method_missing(name, *args, &blk)
@@ -78,4 +86,4 @@ module Rails
end
end
end
-end \ No newline at end of file
+end
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index d63d25b42e..6bf56f7052 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -26,18 +26,17 @@ module ApplicationTests
FileUtils.rm_rf(new_app) if File.directory?(new_app)
end
- test "Rails::Application.instance is nil until app is initialized" do
+ test "Rails.application is nil until app is initialized" do
require 'rails'
- assert_nil Rails::Application.instance
+ assert_nil Rails.application
require "#{app_path}/config/environment"
- assert_equal AppTemplate::Application.instance, Rails::Application.instance
+ assert_equal AppTemplate::Application.instance, Rails.application
end
- test "Rails::Application responds to all instance methods" do
+ test "Rails.application responds to all instance methods" do
require "#{app_path}/config/environment"
- assert_respond_to Rails::Application, :routes_reloader
- assert_equal Rails::Application.routes_reloader, Rails.application.routes_reloader
- assert_equal Rails::Application.routes_reloader, AppTemplate::Application.routes_reloader
+ assert_respond_to Rails.application, :routes_reloader
+ assert_equal Rails.application.routes_reloader, AppTemplate::Application.routes_reloader
end
test "Rails::Application responds to paths" do
@@ -125,22 +124,6 @@ module ApplicationTests
assert !ActionController.autoload?(:RecordIdentifier)
end
- test "runtime error is raised if config.frameworks= is used" do
- add_to_config "config.frameworks = []"
-
- assert_raises RuntimeError do
- require "#{app_path}/config/environment"
- end
- end
-
- test "runtime error is raised if config.frameworks is used" do
- add_to_config "config.frameworks -= []"
-
- assert_raises RuntimeError do
- require "#{app_path}/config/environment"
- end
- end
-
test "filter_parameters should be able to set via config.filter_parameters" do
add_to_config <<-RUBY
config.filter_parameters += [ :foo, 'bar', lambda { |key, value|
@@ -277,5 +260,20 @@ module ApplicationTests
get "/"
assert_not_equal res, last_response.body
end
+
+ test "config.asset_path is not passed through env" do
+ make_basic_app do |app|
+ app.config.asset_path = "/omg%s"
+ end
+
+ class ::OmgController < ActionController::Base
+ def index
+ render :inline => "<%= image_path('foo.jpg') %>"
+ end
+ end
+
+ get "/"
+ assert_equal "/omg/images/foo.jpg", last_response.body
+ end
end
end
diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb
index 4ff10091b1..6e9ceb6ef7 100644
--- a/railties/test/application/initializers/frameworks_test.rb
+++ b/railties/test/application/initializers/frameworks_test.rb
@@ -61,6 +61,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
assert Foo.method_defined?(:foo_path)
+ assert Foo.method_defined?(:app)
assert_equal ["notify"], Foo.action_methods
end
diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb
index ecf7904c39..a2abf642b8 100644
--- a/railties/test/application/loading_test.rb
+++ b/railties/test/application/loading_test.rb
@@ -42,6 +42,23 @@ class LoadingTest < Test::Unit::TestCase
User
end
+ test "load config/environments/environment before Bootstrap initializers" do
+ app_file "config/environments/development.rb", <<-RUBY
+ AppTemplate::Application.configure do
+ config.development_environment_loaded = true
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ config.before_initialize do
+ config.loaded = config.development_environment_loaded
+ end
+ RUBY
+
+ require "#{app_path}/config/environment"
+ assert ::AppTemplate::Application.config.loaded
+ end
+
def test_descendants_are_cleaned_on_each_request_without_cache_classes
add_to_config <<-RUBY
config.cache_classes = false
@@ -72,6 +89,11 @@ class LoadingTest < Test::Unit::TestCase
assert_equal [], ActiveRecord::Base.descendants
end
+ test "initialize_cant_be_called_twice" do
+ require "#{app_path}/config/environment"
+ assert_raise(RuntimeError) { ::AppTemplate::Application.initialize! }
+ end
+
protected
def setup_ar!
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 7410a10712..0cc729907e 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -1,8 +1,23 @@
require "isolation/abstract_unit"
require "railties/shared_tests"
+require 'stringio'
module RailtiesTest
class EngineTest < Test::Unit::TestCase
+ # TODO: it's copied from generators/test_case, maybe make a module with such helpers?
+ def capture(stream)
+ begin
+ stream = stream.to_s
+ eval "$#{stream} = StringIO.new"
+ yield
+ result = eval("$#{stream}").string
+ ensure
+ eval("$#{stream} = #{stream.upcase}")
+ end
+
+ result
+ end
+
include ActiveSupport::Testing::Isolation
include SharedTests
@@ -13,6 +28,7 @@ module RailtiesTest
plugin.write "lib/bukkits.rb", <<-RUBY
class Bukkits
class Engine < ::Rails::Engine
+ railtie_name "bukkits"
end
end
RUBY
@@ -50,5 +66,483 @@ module RailtiesTest
assert index < initializers.index { |i| i.name == :build_middleware_stack }
end
+
+
+ class Upcaser
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ response = @app.call(env)
+ response[2].upcase!
+ response
+ end
+ end
+
+ test "engine is a rack app and can have his own middleware stack" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ class Bukkits
+ class Engine < ::Rails::Engine
+ endpoint lambda { |env| [200, {'Content-Type' => 'text/html'}, 'Hello World'] }
+
+ config.middleware.use ::RailtiesTest::EngineTest::Upcaser
+ end
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ AppTemplate::Application.routes.draw do
+ mount(Bukkits::Engine => "/bukkits")
+ end
+ RUBY
+
+ boot_rails
+
+ env = Rack::MockRequest.env_for("/bukkits")
+ response = Rails.application.call(env)
+
+ assert_equal "HELLO WORLD", response[2]
+ end
+
+ test "it provides routes as default endpoint" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ class Bukkits
+ class Engine < ::Rails::Engine
+ end
+ end
+ RUBY
+
+ @plugin.write "config/routes.rb", <<-RUBY
+ Bukkits::Engine.routes.draw do
+ match "/foo" => lambda { |env| [200, {'Content-Type' => 'text/html'}, 'foo'] }
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ mount(Bukkits::Engine => "/bukkits")
+ end
+ RUBY
+
+ boot_rails
+
+ env = Rack::MockRequest.env_for("/bukkits/foo")
+ response = Rails.application.call(env)
+
+ assert_equal "foo", response[2]
+ end
+
+ test "engine can load its own plugins" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ class Bukkits
+ class Engine < ::Rails::Engine
+ end
+ end
+ RUBY
+
+ @plugin.write "vendor/plugins/yaffle/init.rb", <<-RUBY
+ config.yaffle_loaded = true
+ RUBY
+
+ boot_rails
+
+ assert Bukkits::Engine.config.yaffle_loaded
+ end
+
+ test "engine does not load plugins that already exists in application" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ class Bukkits
+ class Engine < ::Rails::Engine
+ end
+ end
+ RUBY
+
+ @plugin.write "vendor/plugins/yaffle/init.rb", <<-RUBY
+ config.engine_yaffle_loaded = true
+ RUBY
+
+ app_file "vendor/plugins/yaffle/init.rb", <<-RUBY
+ config.app_yaffle_loaded = true
+ RUBY
+
+ warnings = capture(:stderr) { boot_rails }
+
+ assert !warnings.empty?
+ assert !Bukkits::Engine.config.respond_to?(:engine_yaffle_loaded)
+ assert Rails.application.config.app_yaffle_loaded
+ end
+
+ test "it loads its environment file" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ class Bukkits
+ class Engine < ::Rails::Engine
+ end
+ end
+ RUBY
+
+ @plugin.write "config/environments/development.rb", <<-RUBY
+ Bukkits::Engine.configure do
+ config.environment_loaded = true
+ end
+ RUBY
+
+ boot_rails
+
+ assert Bukkits::Engine.config.environment_loaded
+ end
+
+ test "it passes router in env" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ class Bukkits
+ class Engine < ::Rails::Engine
+ endpoint lambda { |env| [200, {'Content-Type' => 'text/html'}, 'hello'] }
+ end
+ end
+ RUBY
+
+ boot_rails
+
+ env = Rack::MockRequest.env_for("/")
+ response = Bukkits::Engine.call(env)
+
+ assert_equal Bukkits::Engine.routes, env['action_dispatch.routes']
+
+ env = Rack::MockRequest.env_for("/")
+ response = Rails.application.call(env)
+
+ assert_equal Rails.application.routes, env['action_dispatch.routes']
+ end
+
+ test "it allows to set asset_path" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ class Bukkits
+ class Engine < ::Rails::Engine
+ end
+ end
+ RUBY
+
+
+ @plugin.write "config/routes.rb", <<-RUBY
+ Bukkits::Engine.routes.draw do
+ match "/foo" => "foo#index"
+ end
+ RUBY
+
+ @plugin.write "app/controllers/foo_controller.rb", <<-RUBY
+ class FooController < ActionController::Base
+ def index
+ render :index
+ end
+ end
+ RUBY
+
+ @plugin.write "app/views/foo/index.html.erb", <<-RUBY
+ <%= compute_public_path("/foo", "") %>
+ <%= image_path("foo.png") %>
+ <%= javascript_include_tag("foo") %>
+ <%= stylesheet_link_tag("foo") %>
+ RUBY
+
+
+ app_file "app/controllers/bar_controller.rb", <<-RUBY
+ class BarController < ActionController::Base
+ def index
+ render :index
+ end
+ end
+ RUBY
+
+ app_file "app/views/bar/index.html.erb", <<-RUBY
+ <%= compute_public_path("/foo", "") %>
+ RUBY
+
+ add_to_config 'config.asset_path = "/omg%s"'
+
+ @plugin.write 'public/touch.txt', <<-RUBY
+ touch
+ RUBY
+
+ boot_rails
+
+ # should set asset_path with engine name by default
+ assert_equal "/bukkits_engine%s", ::Bukkits::Engine.config.asset_path
+
+ ::Bukkits::Engine.config.asset_path = "/bukkits%s"
+
+ env = Rack::MockRequest.env_for("/foo")
+ response = Bukkits::Engine.call(env)
+ stripped_body = response[2].body.split("\n").map(&:strip).join("\n")
+
+ expected = "/omg/bukkits/foo\n" +
+ "/omg/bukkits/images/foo.png\n" +
+ "<script src=\"/omg/bukkits/javascripts/foo.js\" type=\"text/javascript\"></script>\n" +
+ "<link href=\"/omg/bukkits/stylesheets/foo.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
+ assert_equal expected, stripped_body
+ end
+
+ test "engine's files are served via ActionDispatch::Static" do
+ add_to_config "config.serve_static_assets = true"
+
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ class Bukkits
+ class Engine < ::Rails::Engine
+ engine_name :bukkits
+ end
+ end
+ RUBY
+
+ @plugin.write "public/bukkits.html", "/bukkits/bukkits.html"
+ app_file "public/app.html", "/app.html"
+ app_file "public/bukkits/file_from_app.html", "/bukkits/file_from_app.html"
+
+ boot_rails
+
+ env = Rack::MockRequest.env_for("/app.html")
+ response = Rails.application.call(env)
+ assert_equal response[2].path, File.join(app_path, "public/app.html")
+
+ env = Rack::MockRequest.env_for("/bukkits/bukkits.html")
+ response = Rails.application.call(env)
+ assert_equal response[2].path, File.join(@plugin.path, "public/bukkits.html")
+
+ env = Rack::MockRequest.env_for("/bukkits/file_from_app.html")
+ response = Rails.application.call(env)
+ assert_equal response[2].path, File.join(app_path, "public/bukkits/file_from_app.html")
+ end
+
+ test "shared engine should include application's helpers and own helpers" do
+ app_file "config/routes.rb", <<-RUBY
+ AppTemplate::Application.routes.draw do
+ match "/foo" => "bukkits/foo#index", :as => "foo"
+ match "/foo/show" => "bukkits/foo#show"
+ match "/foo/bar" => "bukkits/foo#bar"
+ end
+ RUBY
+
+ app_file "app/helpers/some_helper.rb", <<-RUBY
+ module SomeHelper
+ def something
+ "Something... Something... Something..."
+ end
+ end
+ RUBY
+
+ @plugin.write "app/helpers/bar_helper.rb", <<-RUBY
+ module BarHelper
+ def bar
+ "It's a bar."
+ end
+ end
+ RUBY
+
+ @plugin.write "app/controllers/bukkits/foo_controller.rb", <<-RUBY
+ class Bukkits::FooController < ActionController::Base
+ def index
+ render :inline => "<%= something %>"
+ end
+
+ def show
+ render :text => foo_path
+ end
+
+ def bar
+ render :inline => "<%= bar %>"
+ end
+ end
+ RUBY
+
+ boot_rails
+
+ env = Rack::MockRequest.env_for("/foo")
+ response = Rails.application.call(env)
+ assert_equal "Something... Something... Something...", response[2].body
+
+ env = Rack::MockRequest.env_for("/foo/show")
+ response = Rails.application.call(env)
+ assert_equal "/foo", response[2].body
+
+ env = Rack::MockRequest.env_for("/foo/bar")
+ response = Rails.application.call(env)
+ assert_equal "It's a bar.", response[2].body
+ end
+
+ test "isolated engine should include only its own routes and helpers" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ module Bukkits
+ class Engine < ::Rails::Engine
+ namespace Bukkits
+ end
+ end
+ RUBY
+
+ @plugin.write "app/models/bukkits/post.rb", <<-RUBY
+ module Bukkits
+ class Post
+ extend ActiveModel::Naming
+
+ def to_param
+ "1"
+ end
+ end
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ AppTemplate::Application.routes.draw do
+ match "/bar" => "bar#index", :as => "bar"
+ mount Bukkits::Engine => "/bukkits", :as => "bukkits"
+ end
+ RUBY
+
+ @plugin.write "config/routes.rb", <<-RUBY
+ Bukkits::Engine.routes.draw do
+ match "/foo" => "foo#index", :as => "foo"
+ match "/foo/show" => "foo#show"
+ match "/from_app" => "foo#from_app"
+ match "/routes_helpers_in_view" => "foo#routes_helpers_in_view"
+ match "/polymorphic_path_without_namespace" => "foo#polymorphic_path_without_namespace"
+ resources :posts
+ end
+ RUBY
+
+ app_file "app/helpers/some_helper.rb", <<-RUBY
+ module SomeHelper
+ def something
+ "Something... Something... Something..."
+ end
+ end
+ RUBY
+
+ @plugin.write "app/helpers/engine_helper.rb", <<-RUBY
+ module EngineHelper
+ def help_the_engine
+ "Helped."
+ end
+ end
+ RUBY
+
+ @plugin.write "app/controllers/bukkits/foo_controller.rb", <<-RUBY
+ class Bukkits::FooController < ActionController::Base
+ def index
+ render :inline => "<%= help_the_engine %>"
+ end
+
+ def show
+ render :text => foo_path
+ end
+
+ def from_app
+ render :inline => "<%= (self.respond_to?(:bar_path) || self.respond_to?(:something)) %>"
+ end
+
+ def routes_helpers_in_view
+ render :inline => "<%= foo_path %>, <%= app.bar_path %>"
+ end
+
+ def polymorphic_path_without_namespace
+ render :text => polymorphic_path(Post.new)
+ end
+ end
+ RUBY
+
+ @plugin.write "app/mailers/bukkits/my_mailer.rb", <<-RUBY
+ module Bukkits
+ class MyMailer < ActionMailer::Base
+ end
+ end
+ RUBY
+
+ add_to_config("config.action_dispatch.show_exceptions = false")
+
+ boot_rails
+
+ assert_equal "bukkits_", Bukkits.table_name_prefix
+ assert_equal "bukkits", Bukkits::Engine.engine_name
+ assert_equal Bukkits._railtie, Bukkits::Engine
+ assert ::Bukkits::MyMailer.method_defined?(:foo_path)
+ assert !::Bukkits::MyMailer.method_defined?(:bar_path)
+
+ env = Rack::MockRequest.env_for("/bukkits/from_app")
+ response = AppTemplate::Application.call(env)
+ assert_equal "false", response[2].body
+
+ env = Rack::MockRequest.env_for("/bukkits/foo/show")
+ response = AppTemplate::Application.call(env)
+ assert_equal "/bukkits/foo", response[2].body
+
+ env = Rack::MockRequest.env_for("/bukkits/foo")
+ response = AppTemplate::Application.call(env)
+ assert_equal "Helped.", response[2].body
+
+ env = Rack::MockRequest.env_for("/bukkits/routes_helpers_in_view")
+ response = AppTemplate::Application.call(env)
+ assert_equal "/bukkits/foo, /bar", response[2].body
+
+ env = Rack::MockRequest.env_for("/bukkits/polymorphic_path_without_namespace")
+ response = AppTemplate::Application.call(env)
+ assert_equal "/bukkits/posts/1", response[2].body
+ end
+
+ test "isolated engine should avoid namespace in names if that's possible" do
+ @plugin.write "lib/bukkits.rb", <<-RUBY
+ module Bukkits
+ class Engine < ::Rails::Engine
+ namespace Bukkits
+ end
+ end
+ RUBY
+
+ @plugin.write "app/models/bukkits/post.rb", <<-RUBY
+ module Bukkits
+ class Post
+ extend ActiveModel::Naming
+ include ActiveModel::Conversion
+ attr_accessor :title
+
+ def to_param
+ "1"
+ end
+
+ def persisted?
+ false
+ end
+ end
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ AppTemplate::Application.routes.draw do
+ mount Bukkits::Engine => "/bukkits", :as => "bukkits"
+ end
+ RUBY
+
+ @plugin.write "config/routes.rb", <<-RUBY
+ Bukkits::Engine.routes.draw do
+ resources :posts
+ end
+ RUBY
+
+ @plugin.write "app/controllers/bukkits/posts_controller.rb", <<-RUBY
+ class Bukkits::PostsController < ActionController::Base
+ def new
+ end
+ end
+ RUBY
+
+ @plugin.write "app/views/bukkits/posts/new.html.erb", <<-RUBY
+ <%= form_for(Bukkits::Post.new) do |f| %>
+ <%= f.text_field :title %>
+ <% end %>
+ RUBY
+
+ add_to_config("config.action_dispatch.show_exceptions = false")
+
+ boot_rails
+
+ env = Rack::MockRequest.env_for("/bukkits/posts/new")
+ response = AppTemplate::Application.call(env)
+ assert response[2].body =~ /name="post\[title\]"/
+ end
end
end
diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb
new file mode 100644
index 0000000000..36dd01198f
--- /dev/null
+++ b/railties/test/railties/mounted_engine_test.rb
@@ -0,0 +1,174 @@
+require 'isolation/abstract_unit'
+
+module ApplicationTests
+ class ApplicationRoutingTest < Test::Unit::TestCase
+ require 'rack/test'
+ include Rack::Test::Methods
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+
+ add_to_config("config.action_dispatch.show_exceptions = false")
+
+ @plugin = engine "blog"
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match "/engine_route" => "application_generating#engine_route"
+ match "/engine_route_in_view" => "application_generating#engine_route_in_view"
+ match "/url_for_engine_route" => "application_generating#url_for_engine_route"
+ match "/polymorphic_route" => "application_generating#polymorphic_route"
+ scope "/:user", :user => "anonymous" do
+ mount Blog::Engine => "/blog"
+ end
+ root :to => 'main#index'
+ end
+ RUBY
+
+ @plugin.write "app/models/blog/post.rb", <<-RUBY
+ module Blog
+ class Post
+ extend ActiveModel::Naming
+
+ def id
+ 44
+ end
+
+ def to_param
+ id.to_s
+ end
+
+ def new_record?
+ false
+ end
+ end
+ end
+ RUBY
+
+ @plugin.write "lib/blog.rb", <<-RUBY
+ module Blog
+ class Engine < ::Rails::Engine
+ namespace(Blog)
+ end
+ end
+ RUBY
+
+ @plugin.write "config/routes.rb", <<-RUBY
+ Blog::Engine.routes.draw do
+ resources :posts
+ match '/generate_application_route', :to => 'posts#generate_application_route'
+ match '/application_route_in_view', :to => 'posts#application_route_in_view'
+ end
+ RUBY
+
+ @plugin.write "app/controllers/blog/posts_controller.rb", <<-RUBY
+ module Blog
+ class PostsController < ActionController::Base
+ def index
+ render :text => blog.post_path(1)
+ end
+
+ def generate_application_route
+ path = app.url_for(:controller => "/main",
+ :action => "index",
+ :only_path => true)
+ render :text => path
+ end
+
+ def application_route_in_view
+ render :inline => "<%= app.root_path %>"
+ end
+ end
+ end
+ RUBY
+
+ app_file "app/controllers/application_generating_controller.rb", <<-RUBY
+ class ApplicationGeneratingController < ActionController::Base
+ def engine_route
+ render :text => blog.posts_path
+ end
+
+ def engine_route_in_view
+ render :inline => "<%= blog.posts_path %>"
+ end
+
+ def url_for_engine_route
+ render :text => blog.url_for(:controller => "blog/posts", :action => "index", :user => "john", :only_path => true)
+ end
+
+ def polymorphic_route
+ render :text => polymorphic_url([blog, Blog::Post.new])
+ end
+ end
+ RUBY
+
+ boot_rails
+ end
+
+ def app
+ @app ||= begin
+ require "#{app_path}/config/environment"
+ Rails.application
+ end
+ end
+
+ def reset_script_name!
+ Rails.application.routes.default_url_options = {}
+ end
+
+ def script_name(script_name)
+ Rails.application.routes.default_url_options = {:script_name => script_name}
+ end
+
+ test "routes generation in engine and application" do
+ # test generating engine's route from engine
+ get "/john/blog/posts"
+ assert_equal "/john/blog/posts/1", last_response.body
+
+ # test generating engine's route from engine with default_url_options
+ script_name "/foo"
+ get "/john/blog/posts", {}, 'SCRIPT_NAME' => "/foo"
+ assert_equal "/foo/john/blog/posts/1", last_response.body
+ reset_script_name!
+
+ # test generating engine's route from application
+ get "/engine_route"
+ assert_equal "/anonymous/blog/posts", last_response.body
+
+ get "/engine_route_in_view"
+ assert_equal "/anonymous/blog/posts", last_response.body
+
+ get "/url_for_engine_route"
+ assert_equal "/john/blog/posts", last_response.body
+
+ # test generating engine's route from application with default_url_options
+ script_name "/foo"
+ get "/engine_route", {}, 'SCRIPT_NAME' => "/foo"
+ assert_equal "/foo/anonymous/blog/posts", last_response.body
+
+ script_name "/foo"
+ get "/url_for_engine_route", {}, 'SCRIPT_NAME' => "/foo"
+ assert_equal "/foo/john/blog/posts", last_response.body
+ reset_script_name!
+
+ # test generating application's route from engine
+ get "/someone/blog/generate_application_route"
+ assert_equal "/", last_response.body
+
+ get "/somone/blog/application_route_in_view"
+ assert_equal "/", last_response.body
+
+ # test generating application's route from engine with default_url_options
+ script_name "/foo"
+ get "/someone/blog/generate_application_route", {}, 'SCRIPT_NAME' => '/foo'
+ assert_equal "/foo/", last_response.body
+ reset_script_name!
+
+ # test polymorphic routes
+ get "/polymorphic_route"
+ assert_equal "http://example.org/anonymous/blog/posts/44", last_response.body
+ end
+ end
+end
+
diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb
index 6715003d3d..406d5d764f 100644
--- a/railties/test/railties/railtie_test.rb
+++ b/railties/test/railties/railtie_test.rb
@@ -19,6 +19,22 @@ module RailtiesTest
assert !Rails::Railtie.respond_to?(:config)
end
+ test "Railtie provides railtie_name" do
+ begin
+ class ::Foo < Rails::Railtie ; end
+ assert_equal "foo", ::Foo.railtie_name
+ ensure
+ Object.send(:remove_const, :"Foo")
+ end
+ end
+
+ test "railtie_name can be set manualy" do
+ class Foo < Rails::Railtie
+ railtie_name "bar"
+ end
+ assert_equal "bar", Foo.railtie_name
+ end
+
test "cannot inherit from a railtie" do
class Foo < Rails::Railtie ; end
assert_raise RuntimeError do
diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb
index ce7c55c11c..6aae17c237 100644
--- a/railties/test/railties/shared_tests.rb
+++ b/railties/test/railties/shared_tests.rb
@@ -10,6 +10,55 @@ module RailtiesTest
@app ||= Rails.application
end
+ def test_copying_migrations
+ @plugin.write "db/migrate/1_create_users.rb", <<-RUBY
+ class CreateUsers < ActiveRecord::Migration
+ end
+ RUBY
+
+ @plugin.write "db/migrate/2_add_last_name_to_users.rb", <<-RUBY
+ class AddLastNameToUsers < ActiveRecord::Migration
+ end
+ RUBY
+
+ app_file "db/migrate/1_create_sessions.rb", <<-RUBY
+ class CreateSessions < ActiveRecord::Migration
+ end
+ RUBY
+
+ yaffle = plugin "acts_as_yaffle", "::LEVEL = config.log_level" do |plugin|
+ plugin.write "lib/acts_as_yaffle.rb", "class ActsAsYaffle; end"
+ end
+
+ yaffle.write "db/migrate/1_create_yaffles.rb", <<-RUBY
+ class CreateYaffles < ActiveRecord::Migration
+ end
+ RUBY
+
+ add_to_config "ActiveRecord::Base.timestamped_migrations = false"
+
+ Dir.chdir(app_path) do
+ output = `rake db:copy_migrations FROM=bukkits`
+
+ assert File.exists?("#{app_path}/db/migrate/2_create_users.bukkits.rb")
+ assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb")
+ assert_match /2_create_users/, output
+ assert_match /3_add_last_name_to_users/, output
+ assert_equal 3, Dir["#{app_path}/db/migrate/*.rb"].length
+
+ output = `rake db:copy_migrations`
+
+ assert File.exists?("#{app_path}/db/migrate/4_create_yaffles.acts_as_yaffle.rb")
+ assert_match /4_create_yaffles/, output
+
+ migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length
+ output = `rake db:copy_migrations`
+
+ assert_equal migrations_count, Dir["#{app_path}/db/migrate/*.rb"].length
+ assert_match /No migrations were copied/, output
+ end
+ end
+
def test_puts_its_lib_directory_on_load_path
boot_rails
require "another"