diff options
Diffstat (limited to 'railties')
18 files changed, 301 insertions, 64 deletions
diff --git a/railties/bin/rails b/railties/bin/rails index 808df97429..0f51d5739f 100755 --- a/railties/bin/rails +++ b/railties/bin/rails @@ -4,9 +4,10 @@ rescue LoadError # If people are not using gems, the load path must still # be correct. # TODO: Remove the begin / rescue block somehow - $:.unshift File.dirname(__FILE__) + '/../lib' - $:.unshift File.dirname(__FILE__) + '/../../activesupport/lib' - retry + $:.unshift File.expand_path('../../lib', __FILE__) + $:.unshift File.expand_path('../../../activesupport/lib', __FILE__) + $:.unshift File.expand_path('../../../actionpack/lib', __FILE__) + require 'rails/ruby_version_check' end Signal.trap("INT") { puts; exit } diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index b7cae9a9ac..85aeb4af24 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -3,9 +3,11 @@ require "pathname" require 'active_support' require 'active_support/core_ext/kernel/reporting' require 'active_support/core_ext/logger' +require 'action_dispatch' require 'rails/initializable' require 'rails/application' +require 'rails/plugin' require 'rails/railties_path' require 'rails/version' require 'rails/rack' @@ -14,7 +16,6 @@ require 'rails/core' require 'rails/configuration' require 'rails/deprecation' require 'rails/initializer' -require 'rails/plugin' require 'rails/ruby_version_check' # For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the @@ -29,4 +30,4 @@ else Encoding.default_external = Encoding::UTF_8 end -RAILS_ENV = (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup unless defined?(RAILS_ENV)
\ No newline at end of file +RAILS_ENV = (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup unless defined?(RAILS_ENV) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 110311558c..e65c20de2c 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -13,7 +13,11 @@ module Rails end def config - @config ||= Configuration.new + @config ||= begin + config = Configuration.new + Plugin.plugins.each { |p| config.merge(p.config) } + config + end end # TODO: change the plugin loader to use config @@ -42,8 +46,13 @@ module Rails end end + attr_reader :route_configuration_files + def initialize Rails.application ||= self + + @route_configuration_files = [] + run_initializers(self) end @@ -65,6 +74,32 @@ module Rails ActionController::Routing::Routes end + def routes_changed_at + routes_changed_at = nil + + route_configuration_files.each do |config| + config_changed_at = File.stat(config).mtime + + if routes_changed_at.nil? || config_changed_at > routes_changed_at + routes_changed_at = config_changed_at + end + end + + routes_changed_at + end + + def reload_routes! + routes.disable_clear_and_finalize = true + + routes.clear! + route_configuration_files.each { |config| load(config) } + routes.finalize! + + nil + ensure + routes.disable_clear_and_finalize = false + end + def initializers initializers = super plugins.each { |p| initializers += p.initializers } @@ -73,6 +108,8 @@ module Rails def plugins @plugins ||= begin + plugin_names = config.plugins || [:all] + Plugin.plugins.select { |p| plugin_names.include?(p.plugin_name) } + Plugin::Vendored.all(config.plugins || [:all], config.paths.vendor.plugins) end end @@ -173,9 +210,9 @@ module Rails initializer :initialize_middleware_stack do if config.frameworks.include?(:action_controller) - config.middleware.use(::Rack::Lock) unless ActionController::Base.allow_concurrency - config.middleware.use(ActionDispatch::ShowExceptions, ActionController::Base.consider_all_requests_local) - config.middleware.use(ActionDispatch::Callbacks, ActionController::Dispatcher.prepare_each_request) + config.middleware.use(::Rack::Lock, :if => lambda { ActionController::Base.allow_concurrency }) + config.middleware.use(ActionDispatch::ShowExceptions, lambda { ActionController::Base.consider_all_requests_local }) + config.middleware.use(ActionDispatch::Callbacks, lambda { ActionController::Dispatcher.prepare_each_request }) config.middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options }) config.middleware.use(ActionDispatch::ParamsParser) config.middleware.use(::Rack::MethodOverride) @@ -359,6 +396,18 @@ module Rails next unless configuration.frameworks.include?(:action_controller) require 'rails/dispatcher' unless defined?(::Dispatcher) Dispatcher.define_dispatcher_callbacks(configuration.cache_classes) + + unless configuration.cache_classes + # Setup dev mode route reloading + routes_last_modified = routes_changed_at + reload_routes = lambda do + unless routes_changed_at == routes_last_modified + routes_last_modified = routes_changed_at + reload_routes! + end + end + ActionDispatch::Callbacks.before_dispatch { |callbacks| reload_routes.call } + end end # Routing must be initialized after plugins to allow the former to extend the routes @@ -368,10 +417,8 @@ module Rails # loading module used to lazily load controllers (Configuration#controller_paths). initializer :initialize_routing do next unless configuration.frameworks.include?(:action_controller) - - ActionController::Routing::Routes.controller_paths += configuration.controller_paths - ActionController::Routing::Routes.add_configuration_file(configuration.routes_configuration_file) - ActionController::Routing::Routes.reload! + route_configuration_files << configuration.routes_configuration_file + reload_routes! end # # # Observers are loaded after plugins in case Observers or observed models are modified by plugins. diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 3f43a48e2e..0fa42091dd 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -1,27 +1,71 @@ require 'active_support/ordered_options' module Rails - class Configuration - attr_accessor :cache_classes, :load_paths, :load_once_paths, :after_initialize_blocks, - :frameworks, :framework_root_path, :root, :gems, :plugins, - :i18n, :gems, :whiny_nils, :consider_all_requests_local, - :action_controller, :active_record, :action_view, :active_support, - :action_mailer, :active_resource, - :reload_plugins, :log_path, :log_level, :logger, :preload_frameworks, - :database_configuration_file, :cache_store, :time_zone, - :view_path, :metals, :controller_paths, :routes_configuration_file, - :eager_load_paths, :dependency_loading, :paths, :serve_static_assets + # Temporarily separate the plugin configuration class from the main + # configuration class while this bit is being cleaned up. + class Plugin::Configuration def initialize + @options = Hash.new { |h,k| h[k] = ActiveSupport::OrderedOptions.new } + end + + def middleware + @middleware ||= ActionDispatch::MiddlewareStack.new + end + + def respond_to?(name) + super || name.to_s =~ config_key_regexp + end + + def merge(config) + @options = config.options.merge(@options) + end + + protected + + attr_reader :options + + private + + def method_missing(name, *args, &blk) + if name.to_s =~ config_key_regexp + return $2 == '=' ? @options[$1] = args.first : @options[$1] + end + + super + end + + def config_key_regexp + bits = config_keys.map { |n| Regexp.escape(n.to_s) }.join('|') + /^(#{bits})(?:=)?$/ + end + + def config_keys + ([ :active_support, :active_record, :action_controller, + :action_view, :action_mailer, :active_resource ] + + Plugin.plugin_names).map { |n| n.to_s }.uniq + end + end + + class Configuration < Plugin::Configuration + attr_accessor :after_initialize_blocks, :cache_classes, + :consider_all_requests_local, :dependency_loading, :gems, + :load_once_paths, :logger, :metals, :plugins, + :preload_frameworks, :reload_plugins, :serve_static_assets, + :time_zone, :whiny_nils + + attr_writer :cache_store, :controller_paths, + :database_configuration_file, :eager_load_paths, + :frameworks, :framework_root_path, :i18n, :load_paths, + :log_level, :log_path, :paths, :routes_configuration_file, + :view_path + + def initialize + super @load_once_paths = [] @after_initialize_blocks = [] @dependency_loading = true @serve_static_assets = true - - for framework in frameworks - self.send("#{framework}=", ActiveSupport::OrderedOptions.new) - end - self.active_support = ActiveSupport::OrderedOptions.new end def after_initialize(&blk) @@ -80,7 +124,10 @@ module Rails self.preload_frameworks = true self.cache_classes = true self.dependency_loading = false - self.action_controller.allow_concurrency = true + + if respond_to?(:action_controller) + action_controller.allow_concurrency = true + end self end @@ -99,11 +146,6 @@ module Rails defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root}/vendor/rails" end - def middleware - require 'action_dispatch' - @middleware ||= ActionDispatch::MiddlewareStack.new - end - # Loads and returns the contents of the #database_configuration_file. The # contents of the file are processed via ERB before being sent through # YAML::load. diff --git a/railties/lib/rails/console_app.rb b/railties/lib/rails/console_app.rb index 9a51d594d3..2c4a7a51e8 100644 --- a/railties/lib/rails/console_app.rb +++ b/railties/lib/rails/console_app.rb @@ -1,7 +1,6 @@ require 'active_support/all' require 'active_support/test_case' require 'action_controller' -require 'action_dispatch/test_case' # work around the at_exit hook in test/unit, which kills IRB Test::Unit.run = true if Test::Unit.respond_to?(:run=) @@ -28,6 +27,6 @@ end def reload! puts "Reloading..." ActionDispatch::Callbacks.new(lambda {}, true) - ActionController::Routing::Routes.reload + Rails.application.reload_routes! true end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index ffb9cfe1cd..0e66c9f58f 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -1,5 +1,6 @@ -activesupport_path = "#{File.dirname(__FILE__)}/../../../activesupport/lib" -$LOAD_PATH.unshift(activesupport_path) if File.directory?(activesupport_path) +activesupport_path = File.expand_path('../../../../activesupport/lib', __FILE__) +$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path) + require 'active_support' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/metaclass' diff --git a/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb index 6460e5b599..51c4ad0e2e 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb @@ -7,7 +7,7 @@ </head> <body> -<p class="notice"><%%= flash[:notice] %></p> +<p class="notice"><%%= notice %></p> <%%= yield %> diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb index 6635a3f487..e7991fff92 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb +++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb @@ -2,9 +2,7 @@ # Likewise, all the methods added will be available for all controllers. class ApplicationController < ActionController::Base - helper :all # include all helpers, all the time - protect_from_forgery # See ActionController::RequestForgeryProtection for details - - # Scrub sensitive parameters from your log - # filter_parameter_logging :password + helper :all + protect_from_forgery + filter_parameter_logging :password, :password_confirmation end diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb index e0f9ca8a12..0d1b6bab4f 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb @@ -3,7 +3,7 @@ ActionController::Routing::Routes.draw do |map| # first created -> highest priority. # Sample of regular route: - # match 'products/:id', :to => 'catalog#view' + # match 'products/:id' => 'catalog#view' # Keep in mind you can assign values other than :controller and :action # Sample of named route: @@ -52,9 +52,7 @@ ActionController::Routing::Routes.draw do |map| # See how all your routes lay out with "rake routes" - # Install the default route as the lowest priority. - # Note: The default route make all actions in every controller accessible - # via GET requests. You should consider removing or commenting it out if - # you're using named routes and resources. - match ':controller(/:action(/:id(.:format)))' + # This is a legacy wild controller route that's not recommended for RESTful applications. + # Note: This route will make all actions in every controller accessible via GET requests. + # match ':controller(/:action(/:id(.:format)))' end diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index 3cc8bbf8e7..874e96a2b4 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -46,8 +46,7 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| if @<%= orm_instance.save %> - flash[:notice] = '<%= class_name %> was successfully created.' - format.html { redirect_to(@<%= file_name %>) } + format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully created.') } format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> } else format.html { render :action => "new" } @@ -63,8 +62,7 @@ class <%= controller_class_name %>Controller < ApplicationController respond_to do |format| if @<%= orm_instance.update_attributes("params[:#{file_name}]") %> - flash[:notice] = '<%= class_name %> was successfully updated.' - format.html { redirect_to(@<%= file_name %>) } + format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully updated.') } format.xml { head :ok } else format.html { render :action => "edit" } diff --git a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml index c21035113e..a30132bc99 100644 --- a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml +++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml @@ -11,9 +11,13 @@ two: <%= attribute.name %>: <%= attribute.default %> <% end -%> <% else -%> -# one: -# column: value +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below # -# two: -# column: value -<% end -%> +one: {} +# column: value +# +two: {} +# column: value +<% end -%>
\ No newline at end of file diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb index 96234739cf..add10bd207 100644 --- a/railties/lib/rails/initializable.rb +++ b/railties/lib/rails/initializable.rb @@ -5,7 +5,7 @@ module Rails end class Initializer - attr_reader :name, :before, :after, :global, :block + attr_reader :name, :block def initialize(name, context, options, &block) @name, @context, @options, @block = name, context, options, block @@ -62,7 +62,7 @@ module Rails end def run_initializers(*args) - return if @ran + return if instance_variable_defined?(:@ran) initializers.each do |initializer| initializer.run(*args) end diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb index 86bf032641..90dc1ad8dd 100644 --- a/railties/lib/rails/plugin.rb +++ b/railties/lib/rails/plugin.rb @@ -2,6 +2,27 @@ module Rails class Plugin include Initializable + def self.plugin_name + @plugin_name || name.demodulize.underscore + end + + def self.inherited(klass) + @plugins ||= [] + @plugins << klass unless klass == Vendored + end + + def self.plugins + @plugins + end + + def self.plugin_names + plugins.map { |p| p.plugin_name } + end + + def self.config + @config ||= Configuration.new + end + class Vendored < Plugin def self.all(list, paths) plugins = [] @@ -55,8 +76,8 @@ module Rails initializer :add_routing_file, :after => :initialize_routing do |app| routing_file = "#{path}/config/routes.rb" if File.exist?(routing_file) - app.routes.add_configuration_file(routing_file) - app.routes.reload! + app.route_configuration_files << routing_file + app.reload_routes! end end end diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 0bf5f5c625..b89b7b5c27 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -12,7 +12,6 @@ require 'active_support/core_ext/kernel/requires' # AP is always present require 'action_controller/test_case' require 'action_view/test_case' -require 'action_dispatch/test_case' require 'action_mailer/test_case' if defined?(ActionMailer) require 'active_model/test_case' if defined?(ActiveModel) diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 1fcab8c651..89337b7f66 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -53,5 +53,26 @@ module ApplicationTests assert_raises(NoMethodError) { 1.day } end end + + test "marking the application as threadsafe sets the correct config variables" do + add_to_config <<-RUBY + config.threadsafe! + RUBY + + require "#{app_path}/config/application" + assert AppTemplate.configuration.action_controller.allow_concurrency + end + + test "the application can be marked as threadsafe when there are no frameworks" do + FileUtils.rm_rf("#{app_path}/config/environments") + add_to_config <<-RUBY + config.frameworks = [] + config.threadsafe! + RUBY + + assert_nothing_raised do + require "#{app_path}/config/application" + end + end end end diff --git a/railties/test/application/initializer_test.rb b/railties/test/application/initializer_test.rb index 56582c5772..fa00d287ca 100644 --- a/railties/test/application/initializer_test.rb +++ b/railties/test/application/initializer_test.rb @@ -6,6 +6,7 @@ module ApplicationTests def setup build_app + FileUtils.rm_rf("#{app_path}/config/environments") boot_rails require "rails" end diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index 1bfec3805b..decde056fd 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -81,5 +81,75 @@ module ApplicationTests get '/admin/foo' assert_equal 'admin::foo', last_response.body end + + test "merges with plugin routes" do + controller 'foo', <<-RUBY + class FooController < ActionController::Base + def index + render :text => "foo" + end + end + RUBY + + app_file 'config/routes.rb', <<-RUBY + ActionController::Routing::Routes.draw do |map| + match 'foo', :to => 'foo#index' + end + RUBY + + plugin 'bar', 'require File.dirname(__FILE__) + "/app/controllers/bar"' do |plugin| + plugin.write 'app/controllers/bar.rb', <<-RUBY + class BarController < ActionController::Base + def index + render :text => "bar" + end + end + RUBY + + plugin.write 'config/routes.rb', <<-RUBY + ActionController::Routing::Routes.draw do |map| + match 'bar', :to => 'bar#index' + end + RUBY + end + + get '/foo' + assert_equal 'foo', last_response.body + + get '/bar' + assert_equal 'bar', last_response.body + end + + test "reloads routes when configuration is changed" do + controller :foo, <<-RUBY + class FooController < ActionController::Base + def bar + render :text => "bar" + end + + def baz + render :text => "baz" + end + end + RUBY + + app_file 'config/routes.rb', <<-RUBY + ActionController::Routing::Routes.draw do |map| + match 'foo', :to => 'foo#bar' + end + RUBY + + get '/foo' + assert_equal 'bar', last_response.body + + app_file 'config/routes.rb', <<-RUBY + ActionController::Routing::Routes.draw do |map| + match 'foo', :to => 'foo#baz' + end + RUBY + + get '/foo' + assert_equal 'baz', last_response.body + end end end diff --git a/railties/test/plugins/configuration_test.rb b/railties/test/plugins/configuration_test.rb new file mode 100644 index 0000000000..edf8bb37f5 --- /dev/null +++ b/railties/test/plugins/configuration_test.rb @@ -0,0 +1,36 @@ +require "isolation/abstract_unit" + +module PluginsTest + class ConfigurationTest < Test::Unit::TestCase + def setup + build_app + boot_rails + require "rails" + end + + test "config is available to plugins" do + class Foo < Rails::Plugin ; end + assert_nil Foo.config.action_controller.foo + end + + test "a config name is available for the plugin" do + class Foo < Rails::Plugin ; config.foo.greetings = "hello" ; end + assert_equal "hello", Foo.config.foo.greetings + end + + test "plugin configurations are available in the application" do + class Foo < Rails::Plugin ; config.foo.greetings = "hello" ; end + require "#{app_path}/config/application" + assert_equal "hello", AppTemplate.config.foo.greetings + end + + test "plugin config merges are deep" do + class Foo < Rails::Plugin ; config.foo.greetings = 'hello' ; end + class MyApp < Rails::Application + config.foo.bar = "bar" + end + assert_equal "hello", MyApp.config.foo.greetings + assert_equal "bar", MyApp.config.foo.bar + end + end +end
\ No newline at end of file |