diff --git a/Gemfile b/Gemfile
index a51c560232..ea9842c0c5 100644
--- a/Gemfile
+++ b/Gemfile
@@ -7,14 +7,17 @@ gem "rails", "3.0.0.beta1"
gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
-if RUBY_VERSION < '1.9'
- gem "ruby-debug", ">= 0.10.3"
+group :mri do
+ if RUBY_VERSION < '1.9'
+ gem "system_timer"
+ gem "ruby-debug", ">= 0.10.3"
+ end
end
# AR
gem "sqlite3-ruby", ">= 1.2.5", :require => 'sqlite3'
-group :test do
+group :db do
gem "pg", ">= 0.9.0"
gem "mysql", ">= 2.8.1"
end
diff --git a/Rakefile b/Rakefile
index 4437b48d9a..66a65fb249 100644
--- a/Rakefile
+++ b/Rakefile
@@ -49,13 +49,13 @@ end
desc "Install gems for all projects."
task :install => :gem do
- require File.expand_path("../actionpack/lib/action_pack/version", __FILE__)
+ version = File.read("RAILS_VERSION").strip
(PROJECTS - ["railties"]).each do |project|
puts "INSTALLING #{project}"
- system("gem install #{project}/pkg/#{project}-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc")
+ system("gem install #{project}/pkg/#{project}-#{version}.gem --no-ri --no-rdoc")
end
- system("gem install railties/pkg/railties-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc")
- system("gem install pkg/rails-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc")
+ system("gem install railties/pkg/railties-#{version}.gem --no-ri --no-rdoc")
+ system("gem install pkg/rails-#{version}.gem --no-ri --no-rdoc")
end
desc "Generate documentation for the Rails framework"
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index ef3820ad67..0519783d02 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -1,6 +1,7 @@
require 'mail'
require 'action_mailer/tmail_compat'
require 'action_mailer/collector'
+require 'active_support/core_ext/array/wrap'
module ActionMailer #:nodoc:
# Action Mailer allows you to send email from your application using a mailer model and views.
@@ -590,7 +591,7 @@ def collect_responses_and_parts_order(headers) #:nodoc:
responses, parts_order = [], nil
if block_given?
- collector = ActionMailer::Collector.new(self) { render(action_name) }
+ collector = ActionMailer::Collector.new(lookup_context) { render(action_name) }
yield(collector)
parts_order = collector.responses.map { |r| r[:content_type] }
responses = collector.responses
@@ -604,8 +605,10 @@ def collect_responses_and_parts_order(headers) #:nodoc:
templates_name = headers.delete(:template_name) || action_name
each_template(templates_path, templates_name) do |template|
+ self.formats = template.formats
+
responses << {
- :body => render(:_template => template),
+ :body => render(:template => template),
:content_type => template.mime_type.to_s
}
end
@@ -615,7 +618,7 @@ def collect_responses_and_parts_order(headers) #:nodoc:
end
def each_template(paths, name, &block) #:nodoc:
- Array(paths).each do |path|
+ Array.wrap(paths).each do |path|
templates = lookup_context.find_all(name, path)
templates = templates.uniq_by { |t| t.formats }
diff --git a/actionmailer/lib/action_mailer/collector.rb b/actionmailer/lib/action_mailer/collector.rb
index 5431efccfe..d03e085e83 100644
--- a/actionmailer/lib/action_mailer/collector.rb
+++ b/actionmailer/lib/action_mailer/collector.rb
@@ -11,7 +11,6 @@ def initialize(context, &block)
@context = context
@responses = []
@default_render = block
- @default_formats = context.formats
end
def any(*args, &block)
@@ -21,16 +20,11 @@ def any(*args, &block)
end
alias :all :any
- def custom(mime, options={}, &block)
+ def custom(mime, options={})
options.reverse_merge!(:content_type => mime.to_s)
- @context.formats = [mime.to_sym]
- options[:body] = if block
- block.call
- else
- @default_render.call
- end
+ @context.freeze_formats([mime.to_sym])
+ options[:body] = block_given? ? yield : @default_render.call
@responses << options
- @context.formats = @default_formats
end
end
end
\ No newline at end of file
diff --git a/actionmailer/lib/action_mailer/old_api.rb b/actionmailer/lib/action_mailer/old_api.rb
index aeb653c5db..c7f341d46c 100644
--- a/actionmailer/lib/action_mailer/old_api.rb
+++ b/actionmailer/lib/action_mailer/old_api.rb
@@ -31,9 +31,6 @@ module OldApi #:nodoc:
# replies to this message.
adv_attr_accessor :reply_to
- # Specify additional headers to be added to the message.
- adv_attr_accessor :headers
-
# Specify the order in which parts should be sorted, based on content-type.
# This defaults to the value for the +default_implicit_parts_order+.
adv_attr_accessor :implicit_parts_order
@@ -207,7 +204,8 @@ def create_parts
@parts.unshift create_inline_part(@body)
elsif @parts.empty? || @parts.all? { |p| p.content_disposition =~ /^attachment/ }
lookup_context.find_all(@template, @mailer_name).each do |template|
- @parts << create_inline_part(render(:_template => template), template.mime_type)
+ self.formats = template.formats
+ @parts << create_inline_part(render(:template => template), template.mime_type)
end
if @parts.size > 1
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index 0182e48425..2703367fdb 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -3,14 +3,14 @@
module ActionMailer
class Railtie < Rails::Railtie
- railtie_name :action_mailer
+ config.action_mailer = ActiveSupport::OrderedOptions.new
initializer "action_mailer.url_for", :before => :load_environment_config do |app|
ActionMailer.base_hook { include app.routes.url_helpers }
end
require "action_mailer/railties/log_subscriber"
- log_subscriber ActionMailer::Railties::LogSubscriber.new
+ log_subscriber :action_mailer, ActionMailer::Railties::LogSubscriber.new
initializer "action_mailer.logger" do
ActionMailer.base_hook { self.logger ||= Rails.logger }
diff --git a/actionmailer/lib/action_mailer/railties/log_subscriber.rb b/actionmailer/lib/action_mailer/railties/log_subscriber.rb
index d1b3dd33af..af76d807d0 100644
--- a/actionmailer/lib/action_mailer/railties/log_subscriber.rb
+++ b/actionmailer/lib/action_mailer/railties/log_subscriber.rb
@@ -1,8 +1,10 @@
+require 'active_support/core_ext/array/wrap'
+
module ActionMailer
module Railties
class LogSubscriber < Rails::LogSubscriber
def deliver(event)
- recipients = Array(event.payload[:to]).join(', ')
+ recipients = Array.wrap(event.payload[:to]).join(', ')
info("\nSent mail to #{recipients} (%1.fms)" % event.duration)
debug(event.payload[:mail])
end
@@ -17,4 +19,4 @@ def logger
end
end
end
-end
\ No newline at end of file
+end
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 16fef3a9a4..ea15709b45 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -1,4 +1,23 @@
-require File.expand_path('../../../load_paths', __FILE__)
+# Pathname has a warning, so require it first while silencing
+# warnings to shut it up.
+#
+# Also, in 1.9, Bundler creates warnings due to overriding
+# Rubygems methods
+begin
+ old, $VERBOSE = $VERBOSE, nil
+ require 'pathname'
+ require File.expand_path('../../../load_paths', __FILE__)
+ensure
+ $VERBOSE = old
+end
+
+
+require 'active_support/core_ext/kernel/reporting'
+silence_warnings do
+ # These external dependencies have warnings :/
+ require 'text/format'
+ require 'mail'
+end
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index c1cf1f0157..6f274c11df 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -2,6 +2,8 @@
require 'abstract_unit'
class BaseTest < ActiveSupport::TestCase
+ # TODO Add some tests for implicity layout render and url helpers
+ # so we can get rid of old base tests altogether with old base.
class BaseMailer < ActionMailer::Base
self.mailer_name = "base_mailer"
@@ -72,13 +74,20 @@ def explicit_multipart_with_any(hash = {})
end
end
- def custom_block(include_html=false)
+ def explicit_multipart_with_options(include_html = false)
mail do |format|
format.text(:content_transfer_encoding => "base64"){ render "welcome" }
format.html{ render "welcome" } if include_html
end
end
+ def explicit_multipart_with_one_template(hash = {})
+ mail(hash) do |format|
+ format.html
+ format.text
+ end
+ end
+
def implicit_different_template(template_name='')
mail(:template_name => template_name)
end
@@ -146,6 +155,13 @@ def different_layout(layout_name='')
assert_equal("Hello there", email.body.encoded)
end
+ test "should set template content type if mail has only one part" do
+ mail = BaseMailer.html_only
+ assert_equal('text/html', mail.mime_type)
+ mail = BaseMailer.plain_text_only
+ assert_equal('text/plain', mail.mime_type)
+ end
+
# Custom headers
test "custom headers" do
email = BaseMailer.welcome
@@ -160,7 +176,7 @@ def different_layout(layout_name='')
assert_equal('1234@mikel.me.com', mail['In-Reply-To'].decoded)
end
- test "can pass random headers in as a hash" do
+ test "can pass random headers in as a hash to headers" do
hash = {'X-Special-Domain-Specific-Header' => "SecretValue",
'In-Reply-To' => '1234@mikel.me.com' }
mail = BaseMailer.welcome_with_headers(hash)
@@ -364,6 +380,11 @@ def different_layout(layout_name='')
assert_equal("HTML Explicit Multipart", email.parts[1].body.encoded)
end
+ test "explicit multipart have a boundary" do
+ mail = BaseMailer.explicit_multipart
+ assert_not_nil(mail.content_type_parameters[:boundary])
+ end
+
test "explicit multipart does not sort order" do
order = ["text/html", "text/plain"]
with_default BaseMailer, :parts_order => order do
@@ -397,7 +418,7 @@ def different_layout(layout_name='')
assert_equal("TEXT Explicit Multipart Templates", email.parts[1].body.encoded)
end
- test "explicit multipart with any" do
+ test "explicit multipart with format.any" do
email = BaseMailer.explicit_multipart_with_any
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
@@ -407,8 +428,8 @@ def different_layout(layout_name='')
assert_equal("Format with any!", email.parts[1].body.encoded)
end
- test "explicit multipart with options" do
- email = BaseMailer.custom_block(true)
+ test "explicit multipart with format(Hash)" do
+ email = BaseMailer.explicit_multipart_with_options(true)
email.ready_to_send!
assert_equal(2, email.parts.size)
assert_equal("multipart/alternative", email.mime_type)
@@ -418,28 +439,23 @@ def different_layout(layout_name='')
assert_equal("7bit", email.parts[1].content_transfer_encoding)
end
- test "explicit multipart should be multipart" do
- mail = BaseMailer.explicit_multipart
- assert_not_nil(mail.content_type_parameters[:boundary])
- end
-
- test "should set a content type if only has an html part" do
- mail = BaseMailer.html_only
- assert_equal('text/html', mail.mime_type)
- end
-
- test "should set a content type if only has an plain text part" do
- mail = BaseMailer.plain_text_only
- assert_equal('text/plain', mail.mime_type)
- end
-
- test "explicit multipart with one part is rendered as body" do
- email = BaseMailer.custom_block
+ test "explicit multipart with one part is rendered as body and options are merged" do
+ email = BaseMailer.explicit_multipart_with_options
assert_equal(0, email.parts.size)
assert_equal("text/plain", email.mime_type)
assert_equal("base64", email.content_transfer_encoding)
end
+ test "explicit multipart with one template has the expected format" do
+ email = BaseMailer.explicit_multipart_with_one_template
+ assert_equal(2, email.parts.size)
+ assert_equal("multipart/alternative", email.mime_type)
+ assert_equal("text/html", email.parts[0].mime_type)
+ assert_equal("[:html]", email.parts[0].body.encoded)
+ assert_equal("text/plain", email.parts[1].mime_type)
+ assert_equal("[:text]", email.parts[1].body.encoded)
+ end
+
# Class level API with method missing
test "should respond to action methods" do
assert BaseMailer.respond_to?(:welcome)
diff --git a/actionmailer/test/fixtures/base_mailer/explicit_multipart_with_one_template.erb b/actionmailer/test/fixtures/base_mailer/explicit_multipart_with_one_template.erb
new file mode 100644
index 0000000000..8a69657b08
--- /dev/null
+++ b/actionmailer/test/fixtures/base_mailer/explicit_multipart_with_one_template.erb
@@ -0,0 +1 @@
+<%= self.formats.inspect %>
\ No newline at end of file
diff --git a/actionmailer/test/fixtures/test_mailer/signed_up_with_url.erb b/actionmailer/test/fixtures/url_test_mailer/signed_up_with_url.erb
similarity index 100%
rename from actionmailer/test/fixtures/test_mailer/signed_up_with_url.erb
rename to actionmailer/test/fixtures/url_test_mailer/signed_up_with_url.erb
diff --git a/actionmailer/test/old_base/mail_layout_test.rb b/actionmailer/test/old_base/mail_layout_test.rb
index 5679aa5a64..2c2daa0f28 100644
--- a/actionmailer/test/old_base/mail_layout_test.rb
+++ b/actionmailer/test/old_base/mail_layout_test.rb
@@ -69,47 +69,25 @@ def test_should_pickup_default_layout
def test_should_pickup_multipart_layout
mail = AutoLayoutMailer.multipart
- # CHANGED: content_type returns an object
- # assert_equal "multipart/alternative", mail.content_type
assert_equal "multipart/alternative", mail.mime_type
assert_equal 2, mail.parts.size
- # CHANGED: content_type returns an object
- # assert_equal 'text/plain', mail.parts.first.content_type
assert_equal 'text/plain', mail.parts.first.mime_type
-
- # CHANGED: body returns an object
- # assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s
- # CHANGED: content_type returns an object
- # assert_equal 'text/html', mail.parts.last.content_type
assert_equal 'text/html', mail.parts.last.mime_type
-
- # CHANGED: body returns an object
- # assert_equal "Hello from layout text/html multipart", mail.parts.last.body
assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s
end
def test_should_pickup_multipartmixed_layout
mail = AutoLayoutMailer.multipart("multipart/mixed")
- # CHANGED: content_type returns an object
- # assert_equal "multipart/mixed", mail.content_type
assert_equal "multipart/mixed", mail.mime_type
assert_equal 2, mail.parts.size
- # CHANGED: content_type returns an object
- # assert_equal 'text/plain', mail.parts.first.content_type
assert_equal 'text/plain', mail.parts.first.mime_type
- # CHANGED: body returns an object
- # assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body.to_s
- # CHANGED: content_type returns an object
- # assert_equal 'text/html', mail.parts.last.content_type
assert_equal 'text/html', mail.parts.last.mime_type
- # CHANGED: body returns an object
- # assert_equal "Hello from layout text/html multipart", mail.parts.last.body
assert_equal "Hello from layout text/html multipart", mail.parts.last.body.to_s
end
diff --git a/actionmailer/test/old_base/mail_service_test.rb b/actionmailer/test/old_base/mail_service_test.rb
index 70dafaf33c..e49307bfda 100644
--- a/actionmailer/test/old_base/mail_service_test.rb
+++ b/actionmailer/test/old_base/mail_service_test.rb
@@ -340,6 +340,8 @@ def setup
@original_logger = TestMailer.logger
@recipient = 'test@localhost'
+
+ TestMailer.delivery_method = :test
end
def teardown
@@ -444,9 +446,6 @@ def test_custom_templating_extension
expected.from = "system@loudthinking.com"
expected.date = Time.local(2004, 12, 12)
- # Stub the render method so no alternative renderers need be present.
- ActionView::Base.any_instance.stubs(:render).returns("Hello there, \n\nMr. #{@recipient}")
-
# Now that the template is registered, there should be one part. The text/plain part.
created = nil
assert_nothing_raised { created = TestMailer.custom_templating_extension(@recipient) }
@@ -1194,6 +1193,6 @@ def test_should_still_raise_exception_with_expected_message_when_calling_an_unde
RespondToMailer.not_a_method
end
- assert_match(/undefined method.*not_a_method/, error.message)
+ assert_match(/method.*not_a_method/, error.message)
end
-end
\ No newline at end of file
+end
diff --git a/actionmailer/test/old_base/url_test.rb b/actionmailer/test/old_base/url_test.rb
index 60740d6b0b..17b383cc2a 100644
--- a/actionmailer/test/old_base/url_test.rb
+++ b/actionmailer/test/old_base/url_test.rb
@@ -10,7 +10,7 @@ class ActionMailer::Base
include AppRoutes.url_helpers
end
-class TestMailer < ActionMailer::Base
+class UrlTestMailer < ActionMailer::Base
default_url_options[:host] = 'www.basecamphq.com'
configure do |c|
@@ -26,14 +26,6 @@ def signed_up_with_url(recipient)
@recipient = recipient
@welcome_url = url_for :host => "example.com", :controller => "welcome", :action => "greeting"
end
-
- class < :'self.class'
self._helpers = Module.new
- self._helper_serial = ::AbstractController::Helpers.next_serial
end
module ClassMethods
@@ -95,8 +89,6 @@ def #{meth}(*args, &blk)
# helper(:three, BlindHelper) { def mice() 'mice' end }
#
def helper(*args, &block)
- self._helper_serial = AbstractController::Helpers.next_serial + 1
-
modules_for_helpers(args).each do |mod|
add_template_helper(mod)
end
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index 2f9616124a..319472c937 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -1,3 +1,5 @@
+require "active_support/core_ext/module/remove_method"
+
module AbstractController
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
# repeated setups. The inclusion pattern has pages that look like this:
@@ -182,7 +184,9 @@ module LayoutConditions
#
# ==== Returns
# Boolean:: True if the action has a layout, false otherwise.
- def _action_has_layout?
+ def action_has_layout?
+ return unless super
+
conditions = _layout_conditions
if only = conditions[:only]
@@ -237,6 +241,8 @@ def _implied_layout_name
# name, return that string. Otherwise, use the superclass'
# layout (which might also be implied)
def _write_layout_method
+ remove_possible_method(:_layout)
+
case defined?(@_layout) ? @_layout : nil
when String
self.class_eval %{def _layout; #{@_layout.inspect} end}
@@ -287,6 +293,17 @@ def _normalize_options(options)
end
end
+ attr_writer :action_has_layout
+
+ def initialize(*)
+ @action_has_layout = true
+ super
+ end
+
+ def action_has_layout?
+ @action_has_layout
+ end
+
private
# This will be overwritten by _write_layout_method
@@ -326,13 +343,13 @@ def _layout_for_option(name)
# Template:: The template object for the default layout (or nil)
def _default_layout(require_layout = false)
begin
- layout_name = _layout if _action_has_layout?
+ layout_name = _layout if action_has_layout?
rescue NameError => e
raise NoMethodError,
"You specified #{@_layout.inspect} as the layout, but no such method was found"
end
- if require_layout && _action_has_layout? && !layout_name
+ if require_layout && action_has_layout? && !layout_name
raise ArgumentError,
"There was no default layout for #{self.class} in #{view_paths.inspect}"
end
@@ -343,9 +360,5 @@ def _default_layout(require_layout = false)
def _include_layout?(options)
(options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout)
end
-
- def _action_has_layout?
- true
- end
end
end
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index 42f4939108..b251bd6405 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -31,6 +31,7 @@ def locale=(value)
module Rendering
extend ActiveSupport::Concern
+
include AbstractController::ViewPaths
# Overwrite process to setup I18n proxy.
@@ -41,21 +42,52 @@ def process(*) #:nodoc:
I18n.config = old_config
end
+ module ClassMethods
+ def view_context_class
+ @view_context_class ||= begin
+ controller = self
+ Class.new(ActionView::Base) do
+ if controller.respond_to?(:_helpers)
+ include controller._helpers
+
+ if controller.respond_to?(:_router)
+ include controller._router.url_helpers
+ end
+
+ # TODO: Fix RJS to not require this
+ self.helpers = controller._helpers
+ end
+ end
+ end
+ end
+ end
+
+ attr_writer :view_context_class
+
+ def view_context_class
+ @view_context_class || self.class.view_context_class
+ end
+
+ def initialize(*)
+ @view_context_class = nil
+ super
+ end
+
# An instance of a view class. The default view class is ActionView::Base
#
# The view class must have the following methods:
- # View.for_controller[controller]
+ # View.new[lookup_context, assigns, controller]
# Create a new ActionView instance for a controller
- # View#render_template[options]
+ # View#render[options]
# Returns String with the rendered template
#
# Override this method in a module to change the default behavior.
def view_context
- @_view_context ||= ActionView::Base.for_controller(self)
+ view_context_class.new(lookup_context, view_assigns, self)
end
- # Mostly abstracts the fact that calling render twice is a DoubleRenderError.
- # Delegates render_to_body and sticks the result in self.response_body.
+ # Normalize arguments, options and then delegates render_to_body and
+ # sticks the result in self.response_body.
def render(*args, &block)
options = _normalize_args(*args, &block)
_normalize_options(options)
@@ -74,12 +106,13 @@ def render_to_body(options = {})
# :api: plugin
def render_to_string(options={})
_normalize_options(options)
- AbstractController::Rendering.body_to_s(render_to_body(options))
+ render_to_body(options)
end
# Find and renders a template based on the options given.
- def _render_template(options)
- view_context.render_template(options) { |template| _with_template_hook(template) }
+ # :api: private
+ def _render_template(options) #:nodoc:
+ view_context.render(options)
end
# The prefix used in render "foo" shortcuts.
@@ -87,20 +120,19 @@ def _prefix
controller_path
end
- # Return a string representation of a Rack-compatible response body.
- def self.body_to_s(body)
- if body.respond_to?(:to_str)
- body
- else
- strings = []
- body.each { |part| strings << part.to_s }
- body.close if body.respond_to?(:close)
- strings.join
- end
- end
-
private
+ # This method should return a hash with assigns.
+ # You can overwrite this configuration per controller.
+ # :api: public
+ def view_assigns
+ hash = {}
+ variables = instance_variable_names
+ variables -= protected_instance_variables if respond_to?(:protected_instance_variables)
+ variables.each { |name| hash[name.to_s[1..-1]] = instance_variable_get(name) }
+ hash
+ end
+
# Normalize options by converting render "foo" to render :action => "foo" and
# render "foo/bar" to render :file => "foo/bar".
def _normalize_args(action=nil, options={})
@@ -134,9 +166,5 @@ def _normalize_options(options)
def _process_options(options)
end
-
- def _with_template_hook(template)
- self.formats = template.formats
- end
end
end
diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb
index c2a9f6336d..b331eb51b6 100644
--- a/actionpack/lib/abstract_controller/view_paths.rb
+++ b/actionpack/lib/abstract_controller/view_paths.rb
@@ -7,7 +7,7 @@ module ViewPaths
self._view_paths = ActionView::PathSet.new
end
- delegate :template_exists?, :view_paths, :formats, :formats=,
+ delegate :find_template, :template_exists?, :view_paths, :formats, :formats=,
:locale, :locale=, :to => :lookup_context
# LookupContext is the object responsible to hold all information required to lookup
@@ -29,10 +29,6 @@ def prepend_view_path(path)
lookup_context.view_paths.unshift(*path)
end
- def template_exists?(*args)
- lookup_context.exists?(*args)
- end
-
module ClassMethods
# Append a path to the list of view paths for this controller.
#
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index fcd3cb9bd3..5797282b41 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -2,7 +2,6 @@ module ActionController
class Base < Metal
abstract!
- include AbstractController::Callbacks
include AbstractController::Layouts
include AbstractController::Translation
@@ -20,9 +19,11 @@ class Base < Metal
include SessionManagement
include ActionController::Caching
include ActionController::MimeResponds
+ include ActionController::PolymorphicRoutes
# Rails 2.x compatibility
include ActionController::Compatibility
+ include ActionController::ImplicitRender
include ActionController::Cookies
include ActionController::Flash
@@ -36,8 +37,12 @@ class Base < Metal
# Add instrumentations hooks at the bottom, to ensure they instrument
# all the methods properly.
include ActionController::Instrumentation
- include ImplicitRender
+ # Before callbacks should also be executed the earliest as possible, so
+ # also include them at the bottom.
+ include AbstractController::Callbacks
+
+ # The same with rescue, append it at the end to wrap as much as possible.
include ActionController::Rescue
def self.inherited(klass)
diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb
index 35111a4b92..43ddf6435a 100644
--- a/actionpack/lib/action_controller/caching/actions.rb
+++ b/actionpack/lib/action_controller/caching/actions.rb
@@ -80,6 +80,7 @@ module ClassMethods
def caches_action(*actions)
return unless cache_configured?
options = actions.extract_options!
+ options[:layout] = true unless options.key?(:layout)
filter_options = options.extract!(:if, :unless).merge(:only => actions)
cache_options = options.extract!(:layout, :cache_path).merge(:store_options => options)
@@ -87,14 +88,12 @@ def caches_action(*actions)
end
end
- def _render_cache_fragment(cache, extension, layout)
- render :text => cache, :layout => layout, :content_type => Mime[extension || :html]
- end
-
- def _save_fragment(name, layout, options)
+ def _save_fragment(name, options)
return unless caching_allowed?
- content = layout ? view_context.content_for(:layout) : response_body
+ content = response_body
+ content = content.join if content.is_a?(Array)
+
write_fragment(name, content, options)
end
@@ -112,7 +111,7 @@ def expire_action(options = {})
class ActionCacheFilter #:nodoc:
def initialize(options, &block)
- @cache_path, @store_options, @layout =
+ @cache_path, @store_options, @cache_layout =
options.values_at(:cache_path, :store_options, :layout)
end
@@ -125,12 +124,19 @@ def filter(controller)
cache_path = ActionCachePath.new(controller, path_options || {})
- if cache = controller.read_fragment(cache_path.path, @store_options)
- controller._render_cache_fragment(cache, cache_path.extension, @layout == false)
- else
+ body = controller.read_fragment(cache_path.path, @store_options)
+
+ unless body
+ controller.action_has_layout = false unless @cache_layout
yield
- controller._save_fragment(cache_path.path, @layout == false, @store_options)
+ controller.action_has_layout = true
+ body = controller._save_fragment(cache_path.path, @store_options)
end
+
+ body = controller.render_to_string(:text => cache, :layout => true) unless @cache_layout
+
+ controller.response_body = body
+ controller.content_type = Mime[cache_path.extension || :html]
end
end
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb
index 00a7f034d3..473a2fe214 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/action_controller/caching/fragments.rb
@@ -34,26 +34,13 @@ def fragment_cache_key(key)
ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views)
end
- def fragment_for(buffer, name = {}, options = nil, &block) #:nodoc:
- if perform_caching
- if fragment_exist?(name, options)
- buffer.safe_concat(read_fragment(name, options))
- else
- pos = buffer.length
- block.call
- write_fragment(name, buffer[pos..-1], options)
- end
- else
- block.call
- end
- end
-
# Writes content to the location signified by key (see expire_fragment for acceptable formats)
def write_fragment(key, content, options = nil)
return content unless cache_configured?
- key = fragment_cache_key(key)
+ key = fragment_cache_key(key)
instrument_fragment_cache :write_fragment, key do
+ content = content.html_safe.to_str if content.respond_to?(:html_safe)
cache_store.write(key, content, options)
end
content
@@ -62,10 +49,11 @@ def write_fragment(key, content, options = nil)
# Reads a cached fragment from the location signified by key (see expire_fragment for acceptable formats)
def read_fragment(key, options = nil)
return unless cache_configured?
- key = fragment_cache_key(key)
+ key = fragment_cache_key(key)
instrument_fragment_cache :read_fragment, key do
- cache_store.read(key, options)
+ result = cache_store.read(key, options)
+ result.respond_to?(:html_safe) ? result.html_safe : result
end
end
diff --git a/actionpack/lib/action_controller/deprecated/base.rb b/actionpack/lib/action_controller/deprecated/base.rb
index 1d05b3fbd6..bbde570ca9 100644
--- a/actionpack/lib/action_controller/deprecated/base.rb
+++ b/actionpack/lib/action_controller/deprecated/base.rb
@@ -63,7 +63,7 @@ def ip_spoofing_check=(value)
def ip_spoofing_check
ActiveSupport::Deprecation.warn "ActionController::Base.ip_spoofing_check is deprecated. " <<
"Configuring ip_spoofing_check on the application configures a middleware.", caller
- Rails.application.config.action_disaptch.ip_spoofing_check
+ Rails.application.config.action_dispatch.ip_spoofing_check
end
def trusted_proxies=(value)
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index eebd2c943a..30aa34d956 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -34,11 +34,12 @@ def controller_name
# and response object available. You might wish to control the
# environment and response manually for performance reasons.
- attr_internal :status, :headers, :content_type, :response, :request
+ attr_internal :headers, :response, :request
delegate :session, :to => "@_request"
def initialize(*)
- @_headers = {}
+ @_headers = {"Content-Type" => "text/html"}
+ @_status = 200
super
end
@@ -62,10 +63,19 @@ def location=(url)
headers["Location"] = url
end
+ def status
+ @_status
+ end
+
def status=(status)
@_status = Rack::Utils.status_code(status)
end
+ def response_body=(val)
+ body = val.respond_to?(:each) ? val : [val]
+ super body
+ end
+
# :api: private
def dispatch(name, request)
@_request = request
diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb
index ab8d87b2c4..e6cea483bb 100644
--- a/actionpack/lib/action_controller/metal/compatibility.rb
+++ b/actionpack/lib/action_controller/metal/compatibility.rb
@@ -40,15 +40,6 @@ def rescue_action(env)
def initialize_template_class(*) end
def assign_shortcuts(*) end
- def template
- @template ||= view_context
- end
-
- def process_action(*)
- template
- super
- end
-
def _normalize_options(options)
if options[:action] && options[:action].to_s.include?(?/)
ActiveSupport::Deprecation.warn "Giving a path to render :action is deprecated. " <<
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index e70a20b2be..4f384d1ec5 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -261,7 +261,8 @@ def retrieve_response_from_mimes(mimes=nil, &block)
block.call(collector) if block_given?
if format = request.negotiate_mime(collector.order)
- self.formats = [format.to_sym]
+ self.content_type ||= format.to_s
+ lookup_context.freeze_formats([format.to_sym])
collector.response_for(format)
else
head :not_acceptable
diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index 37106733cb..060117756e 100644
--- a/actionpack/lib/action_controller/metal/rack_delegation.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -5,10 +5,8 @@ module ActionController
module RackDelegation
extend ActiveSupport::Concern
- included do
- delegate :headers, :status=, :location=, :content_type=,
- :status, :location, :content_type, :to => "@_response"
- end
+ delegate :headers, :status=, :location=, :content_type=,
+ :status, :location, :content_type, :to => "@_response"
def dispatch(action, request)
@_response = ActionDispatch::Response.new
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 25e4e18493..b5f1d23ef0 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -76,7 +76,7 @@ def _compute_redirect_to_location(options)
# The scheme name consist of a letter followed by any combination of
# letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
# characters; and is terminated by a colon (":").
- when %r{^\w[\w\d+.-]*:.*}
+ when %r{^\w[\w+.-]*:.*}
options
when String
request.protocol + request.host_with_port + options
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index 49d3d6b466..d906e1fb5b 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -87,8 +87,9 @@ def self._write_render_options
end
add :update do |proc, options|
+ view_context = self.view_context
generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc)
- self.content_type = Mime::JS
+ self.content_type = Mime::JS
self.response_body = generator.to_s
end
end
diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb
index f892bd9b91..86bb810947 100644
--- a/actionpack/lib/action_controller/metal/rendering.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -5,26 +5,31 @@ module Rendering
include ActionController::RackDelegation
include AbstractController::Rendering
- def process(*)
+ # Before processing, set the request formats in current controller formats.
+ def process_action(*) #:nodoc:
self.formats = request.formats.map { |x| x.to_sym }
super
end
- def render(*args)
+ # Check for double render errors and set the content_type after rendering.
+ def render(*args) #:nodoc:
raise ::AbstractController::DoubleRenderError if response_body
super
+ self.content_type ||= Mime[formats.first].to_s
response_body
end
private
- def _normalize_args(action=nil, options={}, &blk)
+ # Normalize arguments by catching blocks and setting them on :update.
+ def _normalize_args(action=nil, options={}, &blk) #:nodoc:
options = super
options[:update] = blk if block_given?
options
end
- def _normalize_options(options)
+ # Normalize both text and status options.
+ def _normalize_options(options) #:nodoc:
if options.key?(:text) && options[:text].respond_to?(:to_text)
options[:text] = options[:text].to_text
end
@@ -36,7 +41,8 @@ def _normalize_options(options)
super
end
- def _process_options(options)
+ # Process controller specific options, as status, content-type and location.
+ def _process_options(options) #:nodoc:
status, content_type, location = options.values_at(:status, :content_type, :location)
self.status = status if status
@@ -46,10 +52,5 @@ def _process_options(options)
super
end
- def _with_template_hook(template)
- super
- self.content_type ||= template.mime_type.to_s
- end
-
end
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 6765314df2..39a809657b 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -12,7 +12,7 @@ module RequestForgeryProtection
included do
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
# sets it to :authenticity_token by default.
- config.request_forgery_protection_token ||= true
+ config.request_forgery_protection_token ||= :authenticity_token
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
config.allow_forgery_protection ||= true
diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb
index 6178a59029..0b2cee6868 100644
--- a/actionpack/lib/action_controller/metal/responder.rb
+++ b/actionpack/lib/action_controller/metal/responder.rb
@@ -1,3 +1,5 @@
+require 'active_support/json'
+
module ActionController #:nodoc:
# Responder is responsible for exposing a resource to different mime requests,
# usually depending on the HTTP verb. The responder is triggered when
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index 6a3afbb157..0ec89928af 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -1,16 +1,17 @@
require "rails"
require "action_controller"
+require "action_dispatch/railtie"
require "action_view/railtie"
require "active_support/core_ext/class/subclasses"
require "active_support/deprecation/proxy_wrappers"
require "active_support/deprecation"
+require "action_controller/railties/log_subscriber"
+require "action_controller/railties/url_helpers"
+
module ActionController
class Railtie < Rails::Railtie
- railtie_name :action_controller
-
- require "action_controller/railties/log_subscriber"
- require "action_controller/railties/url_helpers"
+ config.action_controller = ActiveSupport::OrderedOptions.new
ad = config.action_dispatch
config.action_controller.singleton_class.send(:define_method, :session) do
@@ -37,7 +38,7 @@ class Railtie < Rails::Railtie
ad.session_store = val
end
- log_subscriber ActionController::Railties::LogSubscriber.new
+ log_subscriber :action_controller, ActionController::Railties::LogSubscriber.new
initializer "action_controller.logger" do
ActionController.base_hook { self.logger ||= Rails.logger }
@@ -52,7 +53,9 @@ class Railtie < Rails::Railtie
ac.stylesheets_dir = paths.public.stylesheets.to_a.first
ac.secret = app.config.cookie_secret
- ActionController.base_hook { self.config.replace(ac) }
+ ActionController.base_hook do
+ self.config.merge!(ac)
+ end
end
initializer "action_controller.initialize_framework_caches" do
@@ -67,7 +70,7 @@ class Railtie < Rails::Railtie
initializer "action_controller.url_helpers" do |app|
ActionController.base_hook do
- extend ::ActionController::Railtie::UrlHelpers.with(app.routes)
+ extend ::ActionController::Railties::UrlHelpers.with(app.routes)
end
message = "ActionController::Routing::Routes is deprecated. " \
diff --git a/actionpack/lib/action_controller/railties/url_helpers.rb b/actionpack/lib/action_controller/railties/url_helpers.rb
index ad2a8d4ef3..5f95e1c621 100644
--- a/actionpack/lib/action_controller/railties/url_helpers.rb
+++ b/actionpack/lib/action_controller/railties/url_helpers.rb
@@ -1,5 +1,5 @@
module ActionController
- class Railtie
+ module Railties
module UrlHelpers
def self.with(router)
Module.new do
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index cdb5db32aa..120f34460e 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -1,7 +1,107 @@
require 'rack/session/abstract/id'
-require 'action_view/test_case'
module ActionController
+ module TemplateAssertions
+ extend ActiveSupport::Concern
+
+ included do
+ setup :setup_subscriptions
+ teardown :teardown_subscriptions
+ end
+
+ def setup_subscriptions
+ @partials = Hash.new(0)
+ @templates = Hash.new(0)
+ @layouts = Hash.new(0)
+
+ ActiveSupport::Notifications.subscribe("action_view.render_template") do |name, start, finish, id, payload|
+ path = payload[:layout]
+ @layouts[path] += 1
+ end
+
+ ActiveSupport::Notifications.subscribe("action_view.render_template!") do |name, start, finish, id, payload|
+ path = payload[:virtual_path]
+ next unless path
+ partial = path =~ /^.*\/_[^\/]*$/
+ if partial
+ @partials[path] += 1
+ @partials[path.split("/").last] += 1
+ @templates[path] += 1
+ else
+ @templates[path] += 1
+ end
+ end
+ end
+
+ def teardown_subscriptions
+ ActiveSupport::Notifications.unsubscribe("action_view.render_template!")
+ end
+
+ # Asserts that the request was rendered with the appropriate template file or partials
+ #
+ # ==== Examples
+ #
+ # # assert that the "new" view template was rendered
+ # assert_template "new"
+ #
+ # # assert that the "_customer" partial was rendered twice
+ # assert_template :partial => '_customer', :count => 2
+ #
+ # # assert that no partials were rendered
+ # assert_template :partial => false
+ #
+ def assert_template(options = {}, message = nil)
+ validate_request!
+
+ case options
+ when NilClass, String
+ rendered = @templates
+ msg = build_message(message,
+ "expecting > but rendering with >",
+ options, rendered.keys.join(', '))
+ assert_block(msg) do
+ if options.nil?
+ @templates.blank?
+ else
+ rendered.any? { |t,num| t.match(options) }
+ end
+ end
+ when Hash
+ if expected_partial = options[:partial]
+ if expected_count = options[:count]
+ actual_count = @partials[expected_partial]
+ # actual_count = found.nil? ? 0 : found[1]
+ msg = build_message(message,
+ "expecting ? to be rendered ? time(s) but rendered ? time(s)",
+ expected_partial, expected_count, actual_count)
+ assert(actual_count == expected_count.to_i, msg)
+ elsif options.key?(:layout)
+ msg = build_message(message,
+ "expecting layout > but action rendered >",
+ expected_layout, @layouts.keys)
+
+ case layout = options[:layout]
+ when String
+ assert(@layouts.include?(expected_layout), msg)
+ when Regexp
+ assert(@layouts.any? {|l| l =~ layout }, msg)
+ when nil
+ assert(@layouts.empty?, msg)
+ end
+ else
+ msg = build_message(message,
+ "expecting partial > but action rendered >",
+ options[:partial], @partials.keys)
+ assert(@partials.include?(expected_partial), msg)
+ end
+ else
+ assert @partials.empty?,
+ "Expected no partials to be rendered"
+ end
+ end
+ end
+ end
+
class TestRequest < ActionDispatch::TestRequest #:nodoc:
def initialize(env = {})
super
@@ -181,6 +281,7 @@ def initialize(session = {})
# assert_redirected_to page_url(:title => 'foo')
class TestCase < ActiveSupport::TestCase
include ActionDispatch::TestProcess
+ include ActionController::TemplateAssertions
# Executes a request simulating GET HTTP method and set/volley the response
def get(action, parameters = nil, session = nil, flash = nil)
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 451b79b190..e42b4d09b0 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -25,7 +25,6 @@ module Http
module FilterParameters
extend ActiveSupport::Concern
- mattr_reader :compiled_parameter_filter_for
@@compiled_parameter_filter_for = {}
# Return a hash of parameters with all sensitive data replaced.
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 13c0f2bad0..3f1a77295d 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -52,12 +52,6 @@ class Type
cattr_reader :browser_generated_types
attr_reader :symbol
- @@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
- def self.unverifiable_types
- ActiveSupport::Deprecation.warn("unverifiable_types is deprecated and has no effect", caller)
- @@unverifiable_types
- end
-
# A simple helper class used in parsing the accept header
class AcceptItem #:nodoc:
attr_accessor :order, :name, :q
@@ -100,7 +94,7 @@ def register_alias(string, symbol, extension_synonyms = [])
end
def register(string, symbol, mime_type_synonyms = [], extension_synonyms = [], skip_lookup = false)
- Mime.instance_eval { const_set symbol.to_s.upcase, Type.new(string, symbol, mime_type_synonyms) }
+ Mime.const_set(symbol.to_s.upcase, Type.new(string, symbol, mime_type_synonyms))
SET << Mime.const_get(symbol.to_s.upcase)
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 0dc03a1a7e..ab7130ab08 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -84,6 +84,7 @@ def []=(key, options)
options[:path] ||= "/"
@set_cookies[key] = options
+ @delete_cookies.delete(key)
value
end
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index 3bcd004e12..43440e5f7c 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -5,20 +5,6 @@
module ActionDispatch
# This middleware rescues any exception returned by the application and renders
# nice exception pages if it's being rescued locally.
- #
- # Every time an exception is caught, a notification is published, becoming a good API
- # to deal with exceptions. So, if you want send an e-mail through ActionMailer
- # everytime this notification is published, you just need to do the following:
- #
- # ActiveSupport::Notifications.subscribe "action_dispatch.show_exception" do |name, start, end, instrumentation_id, payload|
- # ExceptionNotifier.deliver_exception(start, payload)
- # end
- #
- # The payload is a hash which has two pairs:
- #
- # * :env - Contains the rack env for the given request;
- # * :exception - The exception raised;
- #
class ShowExceptions
LOCALHOST = ['127.0.0.1', '::1'].freeze
diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index e486bd4079..563df0f256 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -3,9 +3,8 @@
module ActionDispatch
class Railtie < Rails::Railtie
- railtie_name :action_dispatch
-
- config.action_dispatch.x_sendfile_header = "X-Sendfile"
+ config.action_dispatch = ActiveSupport::OrderedOptions.new
+ config.action_dispatch.x_sendfile_header = ""
config.action_dispatch.ip_spoofing_check = true
# Prepare dispatcher callbacks and run 'prepare' callbacks
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 5bc3205c51..c6e942555f 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/object/to_param'
require 'active_support/core_ext/regexp'
+require 'action_controller/polymorphic_routes'
module ActionDispatch
# == Routing
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 0b7b09ee7a..5a3868e1d4 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -32,6 +32,8 @@ def call(env)
end
class Mapping
+ IGNORE_OPTIONS = [:to, :as, :controller, :action, :via, :on, :constraints, :defaults, :only, :except, :anchor]
+
def initialize(set, scope, args)
@set, @scope = set, scope
@path, @options = extract_path_and_options(args)
@@ -45,18 +47,21 @@ def to_route
def extract_path_and_options(args)
options = args.extract_options!
- case
- when using_to_shorthand?(args, options)
+ if using_to_shorthand?(args, options)
path, to = options.find { |name, value| name.is_a?(String) }
options.merge!(:to => to).delete(path) if path
- when using_match_shorthand?(args, options)
- path = args.first
- options = { :to => path.gsub("/", "#"), :as => path.gsub("/", "_") }
else
path = args.first
end
- [ normalize_path(path), options ]
+ path = normalize_path(path)
+
+ if using_match_shorthand?(path, options)
+ options[:to] ||= path[1..-1].sub(%r{/([^/]*)$}, '#\1')
+ options[:as] ||= path[1..-1].gsub("/", "_")
+ end
+
+ [ path, options ]
end
# match "account" => "account#index"
@@ -65,14 +70,13 @@ def using_to_shorthand?(args, options)
end
# match "account/overview"
- def using_match_shorthand?(args, options)
- args.present? && options.except(:via, :anchor).empty? && !args.first.include?(':')
+ def using_match_shorthand?(path, options)
+ path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w\/]+$}
end
def normalize_path(path)
- path = "#{@scope[:path]}/#{path}"
- raise ArgumentError, "path is required" if path.empty?
- Mapper.normalize_path(path)
+ raise ArgumentError, "path is required" if @scope[:path].blank? && path.blank?
+ Mapper.normalize_path("#{@scope[:path]}/#{path}")
end
def app
@@ -94,7 +98,15 @@ def requirements
end
def defaults
- @defaults ||= if to.respond_to?(:call)
+ @defaults ||= (@options[:defaults] || {}).tap do |defaults|
+ defaults.merge!(default_controller_and_action)
+ defaults.reverse_merge!(@scope[:defaults]) if @scope[:defaults]
+ @options.each { |k, v| defaults[k] = v unless v.is_a?(Regexp) || IGNORE_OPTIONS.include?(k.to_sym) }
+ end
+ end
+
+ def default_controller_and_action
+ if to.respond_to?(:call)
{ }
else
defaults = case to
@@ -144,8 +156,8 @@ def request_method_condition
def segment_keys
@segment_keys ||= Rack::Mount::RegexpWithNamedGroups.new(
- Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS)
- ).names
+ Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS)
+ ).names
end
def to
@@ -297,11 +309,14 @@ def constraints(constraints = {})
scope(:constraints => constraints) { yield }
end
+ def defaults(defaults = {})
+ scope(:defaults => defaults) { yield }
+ end
+
def match(*args)
options = args.extract_options!
options = (@scope[:options] || {}).merge(options)
- options[:anchor] = true unless options.key?(:anchor)
if @scope[:name_prefix] && !options[:as].blank?
options[:as] = "#{@scope[:name_prefix]}_#{options[:as]}"
@@ -342,6 +357,10 @@ def merge_constraints_scope(parent, child)
merge_options_scope(parent, child)
end
+ def merge_defaults_scope(parent, child)
+ merge_options_scope(parent, child)
+ end
+
def merge_blocks_scope(parent, child)
(parent || []) + [child]
end
@@ -362,11 +381,11 @@ def self.default_actions
attr_reader :plural, :singular, :options
def initialize(entities, options = {})
- entities = entities.to_s
+ @name = entities.to_s
@options = options
- @plural = entities.pluralize
- @singular = entities.singularize
+ @plural = @name.pluralize
+ @singular = @name.singularize
end
def default_actions
@@ -393,7 +412,7 @@ def action_type(action)
end
def name
- options[:as] || plural
+ options[:as] || @name
end
def controller
@@ -438,8 +457,8 @@ def action_type(action)
end
end
- def name
- options[:as] || singular
+ def member_name
+ name
end
end
@@ -460,7 +479,7 @@ def resource(*resources, &block)
scope(:path => resource.name.to_s, :controller => resource.controller) do
with_scope_level(:resource, resource) do
- scope(:name_prefix => resource.name.to_s) do
+ scope(:name_prefix => resource.name.to_s, :as => "") do
yield if block_given?
end
@@ -468,8 +487,8 @@ def resource(*resources, &block)
post :create if resource.actions.include?(:create)
put :update if resource.actions.include?(:update)
delete :destroy if resource.actions.include?(:destroy)
- get :new, :as => resource.singular if resource.actions.include?(:new)
- get :edit, :as => resource.singular if resource.actions.include?(:edit)
+ get :new, :as => resource.name if resource.actions.include?(:new)
+ get :edit, :as => resource.name if resource.actions.include?(:edit)
end
end
@@ -563,6 +582,8 @@ def mount(app, options = nil)
def match(*args)
options = args.extract_options!
+ options[:anchor] = true unless options.key?(:anchor)
+
if args.length > 1
args.each { |path| match(path, options) }
return self
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 722be432c7..bb689beed9 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -65,7 +65,7 @@ def split_glob_param!(params)
# named routes.
class NamedRouteCollection #:nodoc:
include Enumerable
- attr_reader :routes, :helpers
+ attr_reader :routes, :helpers, :module
def initialize
clear!
@@ -179,6 +179,7 @@ def #{selector}(*args)
url_for(options)
end
+ protected :#{selector}
END_EVAL
helpers << selector
end
@@ -219,14 +220,16 @@ def draw(&block)
end
def finalize!
+ return if @finalized
+ @finalized = true
@set.add_route(NotFound)
- install_helpers
@set.freeze
end
def clear!
# Clear the controller cache so we may discover new ones
@controller_constraints = nil
+ @finalized = false
routes.clear
named_routes.clear
@set = ::Rack::Mount::RouteSet.new(:parameters_key => PARAMETERS_KEY)
@@ -239,21 +242,30 @@ def install_helpers(destinations = [ActionController::Base, ActionView::Base], r
def url_helpers
@url_helpers ||= begin
- router = self
+ routes = self
- Module.new do
+ helpers = Module.new do
extend ActiveSupport::Concern
include UrlFor
+ @routes = routes
+ class << self
+ delegate :url_for, :to => '@routes'
+ end
+ extend routes.named_routes.module
+
# ROUTES TODO: install_helpers isn't great... can we make a module with the stuff that
# we can include?
# Yes plz - JP
included do
- router.install_helpers(self)
+ routes.install_helpers(self)
+ singleton_class.send(:define_method, :_router) { routes }
end
- define_method(:_router) { router }
+ define_method(:_router) { routes }
end
+
+ helpers
end
end
@@ -406,6 +418,7 @@ def generate(options, recall = {}, extras = false)
RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash]
def url_for(options)
+ finalize!
options = default_url_options.merge(options || {})
handle_positional_args(options)
@@ -437,6 +450,7 @@ def url_for(options)
end
def call(env)
+ finalize!
@set.call(env)
end
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index ec78f53fa6..b8c02f402c 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -72,7 +72,7 @@ module Routing
# you can do that by including ActionController::UrlFor in your class:
#
# class User < ActiveRecord::Base
- # include ActionController::UrlFor
+ # include Rails.application.routes.url_helpers
#
# def base_uri
# user_path(self)
diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb
index 937c9f48d2..ec5e9efe44 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -73,58 +73,6 @@ def assert_redirected_to(options = {}, message=nil)
end
end
- # Asserts that the request was rendered with the appropriate template file or partials
- #
- # ==== Examples
- #
- # # assert that the "new" view template was rendered
- # assert_template "new"
- #
- # # assert that the "_customer" partial was rendered twice
- # assert_template :partial => '_customer', :count => 2
- #
- # # assert that no partials were rendered
- # assert_template :partial => false
- #
- def assert_template(options = {}, message = nil)
- validate_request!
-
- case options
- when NilClass, String
- rendered = (@controller.template.rendered[:template] || []).map { |t| t.identifier }
- msg = build_message(message,
- "expecting > but rendering with >",
- options, rendered.join(', '))
- assert_block(msg) do
- if options.nil?
- @controller.template.rendered[:template].blank?
- else
- rendered.any? { |t| t.match(options) }
- end
- end
- when Hash
- if expected_partial = options[:partial]
- partials = @controller.template.rendered[:partials]
- if expected_count = options[:count]
- found = partials.detect { |p, _| p.identifier.match(expected_partial) }
- actual_count = found.nil? ? 0 : found.second
- msg = build_message(message,
- "expecting ? to be rendered ? time(s) but rendered ? time(s)",
- expected_partial, expected_count, actual_count)
- assert(actual_count == expected_count.to_i, msg)
- else
- msg = build_message(message,
- "expecting partial > but action rendered >",
- options[:partial], partials.keys)
- assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg)
- end
- else
- assert @controller.template.rendered[:partials].empty?,
- "Expected no partials to be rendered"
- end
- end
- end
-
private
# Proxy to to_param if the object will respond to it.
def parameterize(value)
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 1d7e8090e4..1bb81ede3b 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -145,11 +145,25 @@ def with_routing
old_routes, @router = @router, ActionDispatch::Routing::RouteSet.new
old_controller, @controller = @controller, @controller.clone if @controller
_router = @router
- @controller.singleton_class.send(:send, :include, @router.url_helpers) if @controller
+
+ # Unfortunately, there is currently an abstraction leak between AC::Base
+ # and AV::Base which requires having the URL helpers in both AC and AV.
+ # To do this safely at runtime for tests, we need to bump up the helper serial
+ # to that the old AV subclass isn't cached.
+ #
+ # TODO: Make this unnecessary
+ if @controller
+ @controller.singleton_class.send(:include, _router.url_helpers)
+ @controller.view_context_class = Class.new(@controller.view_context_class) do
+ include _router.url_helpers
+ end
+ end
yield @router
ensure
@router = old_routes
- @controller = old_controller if @controller
+ if @controller
+ @controller = old_controller
+ end
end
# ROUTES TODO: These assertions should really work in an integration context
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 0aff4250c1..621d63c5e2 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -2,6 +2,7 @@
require 'uri'
require 'active_support/core_ext/object/singleton_class'
require 'rack/test'
+require 'test/unit/assertions'
module ActionDispatch
module Integration #:nodoc:
@@ -177,14 +178,8 @@ def initialize(app)
reset!
end
- def url_options
- opts = super.reverse_merge(
- :host => host,
- :protocol => https? ? "https" : "http"
- )
-
- opts.merge!(:port => 443) if !opts.key?(:port) && https?
- opts
+ def default_url_options
+ { :host => host, :protocol => https? ? "https" : "http" }
end
# Resets the instance. This can be used to reset the state information
@@ -293,6 +288,8 @@ def process(method, path, parameters = nil, rack_environment = nil)
end
module Runner
+ include ActionDispatch::Assertions
+
def app
@app
end
@@ -300,7 +297,7 @@ def app
# Reset the current session. This is useful for testing multiple sessions
# in a single test case.
def reset!
- @integration_session = open_session
+ @integration_session = Integration::Session.new(app)
end
%w(get post put head delete cookies assigns
@@ -326,30 +323,9 @@ def reset!
# can use this method to open multiple sessions that ought to be tested
# simultaneously.
def open_session(app = nil)
- session = Integration::Session.new(app || self.app)
-
- # delegate the fixture accessors back to the test instance
- extras = Module.new { attr_accessor :delegate, :test_result }
- if self.class.respond_to?(:fixture_table_names)
- self.class.fixture_table_names.each do |table_name|
- name = table_name.tr(".", "_")
- next unless respond_to?(name)
- extras.__send__(:define_method, name) { |*args|
- delegate.send(name, *args)
- }
- end
+ dup.tap do |session|
+ yield session if block_given?
end
-
- # delegate add_assertion to the test case
- extras.__send__(:define_method, :add_assertion) {
- test_result.add_assertion
- }
- session.extend(extras)
- session.delegate = self
- session.test_result = @_result
-
- yield session if block_given?
- session
end
# Copy the instance variables from the current session instance into the
@@ -460,6 +436,7 @@ def method_missing(sym, *args, &block)
# end
class IntegrationTest < ActiveSupport::TestCase
include Integration::Runner
+ include ActionController::TemplateAssertions
@@app = nil
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index afe6386105..5555217ee2 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -44,13 +44,15 @@ module ActionView
autoload :Base
autoload :LookupContext
- autoload :MissingTemplate, 'action_view/base'
autoload :Resolver, 'action_view/template/resolver'
autoload :PathResolver, 'action_view/template/resolver'
autoload :FileSystemResolver, 'action_view/template/resolver'
autoload :PathSet, 'action_view/paths'
+ autoload :MissingTemplate, 'action_view/template/error'
+ autoload :ActionViewError, 'action_view/template/error'
autoload :TemplateError, 'action_view/template/error'
+
autoload :TemplateHandler, 'action_view/template'
autoload :TemplateHandlers, 'action_view/template'
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index ffe3060404..919b1e3470 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -1,27 +1,10 @@
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/class/attribute'
+require 'active_support/core_ext/array/wrap'
module ActionView #:nodoc:
- class ActionViewError < StandardError #:nodoc:
- end
-
- class MissingTemplate < ActionViewError #:nodoc:
- attr_reader :path
-
- def initialize(paths, path, details, partial)
- @path = path
- display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ")
- template_type = if partial
- "partial"
- elsif path =~ /layouts/i
- 'layout'
- else
- 'template'
- end
-
- super("Missing #{template_type} #{path} with #{details.inspect} in view paths #{display_paths}")
- end
+ class NonConcattingString < ActiveSupport::SafeBuffer
end
# Action View templates can be written in three ways. If the template file has a .erb (or .rhtml) extension then it uses a mixture of ERb
@@ -176,14 +159,13 @@ module Subclasses
include Helpers, Rendering, Partials, Layouts, ::ERB::Util, Context
extend ActiveSupport::Memoizable
- ActionView.run_base_hooks(self)
-
# Specify whether RJS responses should be wrapped in a try/catch block
# that alert()s the caught exception (and then re-raises it).
cattr_accessor :debug_rjs
@@debug_rjs = false
class_attribute :helpers
+ remove_method :helpers
attr_reader :helpers
class << self
@@ -191,10 +173,12 @@ class << self
delegate :logger, :to => 'ActionController::Base', :allow_nil => true
end
- attr_accessor :base_path, :assigns, :template_extension, :lookup_context
- attr_internal :captures, :request, :layout, :controller, :template, :config
+ ActionView.run_base_hooks(self)
- delegate :find, :exists?, :formats, :formats=, :locale, :locale=,
+ attr_accessor :base_path, :assigns, :template_extension, :lookup_context
+ attr_internal :captures, :request, :controller, :template, :config
+
+ delegate :find_template, :template_exists?, :formats, :formats=, :locale, :locale=,
:view_paths, :view_paths=, :with_fallbacks, :update_details, :to => :lookup_context
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
@@ -202,42 +186,17 @@ class << self
delegate :logger, :to => :controller, :allow_nil => true
+ # TODO: HACK FOR RJS
+ def view_context
+ self
+ end
+
def self.xss_safe? #:nodoc:
true
end
def self.process_view_paths(value)
- ActionView::PathSet.new(Array(value))
- end
-
- def self.for_controller(controller)
- @views ||= {}
-
- # TODO: Decouple this so helpers are a separate concern in AV just like
- # they are in AC.
- if controller.class.respond_to?(:_helper_serial)
- klass = @views[controller.class._helper_serial] ||= Class.new(self) do
- # Try to make stack traces clearer
- class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
- def self.name
- "ActionView for #{controller.class}"
- end
-
- def inspect
- "#<#{self.class.name}>"
- end
- ruby_eval
-
- if controller.respond_to?(:_helpers)
- include controller._helpers
- self.helpers = controller._helpers
- end
- end
- else
- klass = self
- end
-
- klass.new(controller.lookup_context, {}, controller)
+ ActionView::PathSet.new(Array.wrap(value))
end
def initialize(lookup_context = nil, assigns_for_first_render = {}, controller = nil, formats = nil) #:nodoc:
@@ -246,7 +205,7 @@ def initialize(lookup_context = nil, assigns_for_first_render = {}, controller =
@helpers = self.class.helpers || Module.new
@_controller = controller
- @_config = ActiveSupport::InheritableOptions.new(controller.config) if controller
+ @_config = ActiveSupport::InheritableOptions.new(controller.config) if controller && controller.respond_to?(:config)
@_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
@_virtual_path = nil
@@ -264,14 +223,5 @@ def punctuate_body!(part)
response.body_parts << part
nil
end
-
- # Evaluates the local assigns and controller ivars, pushes them to the view.
- def _evaluate_assigns_and_ivars #:nodoc:
- if controller
- variables = controller.instance_variable_names
- variables -= controller.protected_instance_variables if controller.respond_to?(:protected_instance_variables)
- variables.each { |name| instance_variable_set(name, controller.instance_variable_get(name)) }
- end
- end
end
end
diff --git a/actionpack/lib/action_view/context.rb b/actionpack/lib/action_view/context.rb
index df078a7151..61d2e702a7 100644
--- a/actionpack/lib/action_view/context.rb
+++ b/actionpack/lib/action_view/context.rb
@@ -10,8 +10,6 @@ module CompiledTemplates #:nodoc:
# In order to work with ActionController, a Context
# must implement:
#
- # Context.for_controller[controller] Create a new ActionView instance for a
- # controller
# Context#render_partial[options]
# - responsible for setting options[:_template]
# - Returns String with the rendered partial
diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb
index e359b0bdac..a50c180f63 100644
--- a/actionpack/lib/action_view/helpers.rb
+++ b/actionpack/lib/action_view/helpers.rb
@@ -2,30 +2,32 @@
module ActionView #:nodoc:
module Helpers #:nodoc:
- autoload :ActiveModelHelper, 'action_view/helpers/active_model_helper'
- autoload :AssetTagHelper, 'action_view/helpers/asset_tag_helper'
- autoload :AtomFeedHelper, 'action_view/helpers/atom_feed_helper'
- autoload :CacheHelper, 'action_view/helpers/cache_helper'
- autoload :CaptureHelper, 'action_view/helpers/capture_helper'
- autoload :CsrfHelper, 'action_view/helpers/csrf_helper'
- autoload :DateHelper, 'action_view/helpers/date_helper'
- autoload :DebugHelper, 'action_view/helpers/debug_helper'
- autoload :DeprecatedBlockHelpers, 'action_view/helpers/deprecated_block_helpers'
- autoload :FormHelper, 'action_view/helpers/form_helper'
- autoload :FormOptionsHelper, 'action_view/helpers/form_options_helper'
- autoload :FormTagHelper, 'action_view/helpers/form_tag_helper'
- autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper'
- autoload :NumberHelper, 'action_view/helpers/number_helper'
- autoload :PrototypeHelper, 'action_view/helpers/prototype_helper'
- autoload :RawOutputHelper, 'action_view/helpers/raw_output_helper'
- autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper'
- autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper'
- autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper'
- autoload :ScriptaculousHelper, 'action_view/helpers/scriptaculous_helper'
- autoload :TagHelper, 'action_view/helpers/tag_helper'
- autoload :TextHelper, 'action_view/helpers/text_helper'
- autoload :TranslationHelper, 'action_view/helpers/translation_helper'
- autoload :UrlHelper, 'action_view/helpers/url_helper'
+ extend ActiveSupport::Autoload
+
+ autoload :ActiveModelHelper
+ autoload :AssetTagHelper
+ autoload :AtomFeedHelper
+ autoload :CacheHelper
+ autoload :CaptureHelper
+ autoload :CsrfHelper
+ autoload :DateHelper
+ autoload :DebugHelper
+ autoload :DeprecatedBlockHelpers
+ autoload :FormHelper
+ autoload :FormOptionsHelper
+ autoload :FormTagHelper
+ autoload :JavaScriptHelper, "action_view/helpers/javascript_helper"
+ autoload :NumberHelper
+ autoload :PrototypeHelper
+ autoload :RawOutputHelper
+ autoload :RecordIdentificationHelper
+ autoload :RecordTagHelper
+ autoload :SanitizeHelper
+ autoload :ScriptaculousHelper
+ autoload :TagHelper
+ autoload :TextHelper
+ autoload :TranslationHelper
+ autoload :UrlHelper
def self.included(base)
base.extend(ClassMethods)
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index 4e12cdab54..80b3d3a664 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -3,6 +3,7 @@
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/kernel/reporting'
+require 'active_support/core_ext/object/blank'
module ActionView
ActionView.base_hook do
@@ -127,9 +128,9 @@ def error_message_on(object, method, *args)
object = convert_to_model(object)
if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
- (errors = obj.errors[method])
+ (errors = obj.errors[method]).presence
content_tag("div",
- (options[:prepend_text].html_safe << errors.first).safe_concat(options[:append_text]),
+ "#{options[:prepend_text]}#{ERB::Util.h(errors.first)}#{options[:append_text]}".html_safe,
:class => options[:css_class]
)
else
@@ -295,6 +296,10 @@ def error_wrapping(html_tag)
end
end
+ def error_message
+ object.errors[@method_name]
+ end
+
def column_type
object.send(:column_for_attribute, @method_name).type
end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index de3d61ebbe..02ad41719b 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -3,6 +3,7 @@
require 'action_view/helpers/url_helper'
require 'action_view/helpers/tag_helper'
require 'active_support/core_ext/file'
+require 'active_support/core_ext/object/blank'
module ActionView
module Helpers #:nodoc:
@@ -11,7 +12,7 @@ module Helpers #:nodoc:
# the assets exist before linking to them:
#
# image_tag("rails.png")
- # # =>
+ # # =>
# stylesheet_link_tag("application")
# # =>
#
@@ -58,7 +59,7 @@ module Helpers #:nodoc:
# +asset_host+ to a proc like this:
#
# ActionController::Base.asset_host = Proc.new { |source|
- # "http://assets#{rand(2) + 1}.example.com"
+ # "http://assets#{source.hash % 2 + 1}.example.com"
# }
# image_tag("rails.png")
# # =>
@@ -66,7 +67,7 @@ module Helpers #:nodoc:
# # =>
#
# The example above generates "http://assets1.example.com" and
- # "http://assets2.example.com" randomly. This option is useful for example if
+ # "http://assets2.example.com". This option is useful for example if
# you need fewer/more than four hosts, custom host names, etc.
#
# As you see the proc takes a +source+ parameter. That's a string with the
@@ -242,12 +243,12 @@ def javascript_path(source)
# == Caching multiple javascripts into one
#
# You can also cache multiple javascripts into one file, which requires less HTTP connections to download and can better be
- # compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching
+ # compressed by gzip (leading to faster transfers). Caching will only happen if config.perform_caching
# is set to true (which is the case by default for the Rails production environment, but not for the development
# environment).
#
# ==== Examples
- # javascript_include_tag :all, :cache => true # when ActionController::Base.perform_caching is false =>
+ # javascript_include_tag :all, :cache => true # when config.perform_caching is false =>
#
#
# ...
@@ -255,15 +256,15 @@ def javascript_path(source)
#
#
#
- # javascript_include_tag :all, :cache => true # when ActionController::Base.perform_caching is true =>
+ # javascript_include_tag :all, :cache => true # when config.perform_caching is true =>
#
#
- # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when ActionController::Base.perform_caching is false =>
+ # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when config.perform_caching is false =>
#
#
#
#
- # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when ActionController::Base.perform_caching is true =>
+ # javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when config.perform_caching is true =>
#
#
# The :recursive option is also available for caching:
@@ -275,11 +276,11 @@ def javascript_include_tag(*sources)
cache = concat || options.delete("cache")
recursive = options.delete("recursive")
- if concat || (ActionController::Base.perform_caching && cache)
+ if concat || (config.perform_caching && cache)
joined_javascript_name = (cache == true ? "all" : cache) + ".js"
joined_javascript_path = File.join(joined_javascript_name[/^#{File::SEPARATOR}/] ? config.assets_dir : config.javascripts_dir, joined_javascript_name)
- unless ActionController::Base.perform_caching && File.exists?(joined_javascript_path)
+ unless config.perform_caching && File.exists?(joined_javascript_path)
write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive))
end
javascript_src_tag(joined_javascript_name, options)
@@ -390,25 +391,25 @@ def stylesheet_path(source)
# == Caching multiple stylesheets into one
#
# You can also cache multiple stylesheets into one file, which requires less HTTP connections and can better be
- # compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching
+ # compressed by gzip (leading to faster transfers). Caching will only happen if config.perform_caching
# is set to true (which is the case by default for the Rails production environment, but not for the development
# environment). Examples:
#
# ==== Examples
- # stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is false =>
+ # stylesheet_link_tag :all, :cache => true # when config.perform_caching is false =>
#
#
#
#
- # stylesheet_link_tag :all, :cache => true # when ActionController::Base.perform_caching is true =>
+ # stylesheet_link_tag :all, :cache => true # when config.perform_caching is true =>
#
#
- # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when ActionController::Base.perform_caching is false =>
+ # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when config.perform_caching is false =>
#
#
#
#
- # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when ActionController::Base.perform_caching is true =>
+ # stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when config.perform_caching is true =>
#
#
# The :recursive option is also available for caching:
@@ -426,11 +427,11 @@ def stylesheet_link_tag(*sources)
cache = concat || options.delete("cache")
recursive = options.delete("recursive")
- if concat || (ActionController::Base.perform_caching && cache)
+ if concat || (config.perform_caching && cache)
joined_stylesheet_name = (cache == true ? "all" : cache) + ".css"
joined_stylesheet_path = File.join(joined_stylesheet_name[/^#{File::SEPARATOR}/] ? config.assets_dir : config.stylesheets_dir, joined_stylesheet_name)
- unless ActionController::Base.perform_caching && File.exists?(joined_stylesheet_path)
+ unless config.perform_caching && File.exists?(joined_stylesheet_path)
write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive))
end
stylesheet_tag(joined_stylesheet_name, options)
@@ -523,7 +524,7 @@ def image_tag(source, options = {})
options.symbolize_keys!
src = options[:src] = path_to_image(source)
- options[:alt] ||= File.basename(src, '.*').split('.').first.to_s.capitalize
+ options[:alt] ||= File.basename(src, '.*').capitalize
if size = options.delete(:size)
options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$}
@@ -623,41 +624,37 @@ def self.cache_asset_timestamps=(value)
@@cache_asset_timestamps = true
private
+ def rewrite_extension?(source, dir, ext)
+ source_ext = File.extname(source)[1..-1]
+ ext && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}"))))
+ end
+
+ def rewrite_host_and_protocol(source, has_request)
+ host = compute_asset_host(source)
+ if has_request && host.present? && !is_uri?(host)
+ host = "#{controller.request.protocol}#{host}"
+ end
+ "#{host}#{source}"
+ end
+
# Add the the extension +ext+ if not present. Return full URLs otherwise untouched.
# Prefix with /dir/ if lacking a leading +/+. Account for relative URL
# roots. Rewrite the asset path for cache-busting asset ids. Include
# asset host, if configured, with the correct request protocol.
def compute_public_path(source, dir, ext = nil, include_host = true)
+ return source if is_uri?(source)
+
+ source += ".#{ext}" if rewrite_extension?(source, dir, ext)
+ source = "/#{dir}/#{source}" unless source[0] == ?/
+ source = rewrite_asset_path(source)
+
has_request = controller.respond_to?(:request)
-
- source_ext = File.extname(source)[1..-1]
- if ext && !is_uri?(source) && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}"))))
- source += ".#{ext}"
+ if has_request && include_host && source !~ %r{^#{controller.config.relative_url_root}/}
+ source = "#{controller.config.relative_url_root}#{source}"
end
+ source = rewrite_host_and_protocol(source, has_request) if include_host
- unless is_uri?(source)
- source = "/#{dir}/#{source}" unless source[0] == ?/
-
- source = rewrite_asset_path(source)
-
- if has_request && include_host
- unless source =~ %r{^#{controller.config.relative_url_root}/}
- source = "#{controller.config.relative_url_root}#{source}"
- end
- end
- end
-
- if include_host && !is_uri?(source)
- host = compute_asset_host(source)
-
- if has_request && !host.blank? && !is_uri?(host)
- host = "#{controller.request.protocol}#{host}"
- end
-
- "#{host}#{source}"
- else
- source
- end
+ source
end
def is_uri?(path)
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index d5cc14b29a..a904af56bb 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -32,7 +32,28 @@ module CacheHelper
# Topics listed alphabetically
# <% end %>
def cache(name = {}, options = nil, &block)
- controller.fragment_for(output_buffer, name, options, &block)
+ safe_concat fragment_for(name, options, &block)
+ nil
+ end
+
+ private
+ # TODO: Create an object that has caching read/write on it
+ def fragment_for(name = {}, options = nil, &block) #:nodoc:
+ if controller.perform_caching
+ if controller.fragment_exist?(name, options)
+ controller.read_fragment(name, options)
+ else
+ # VIEW TODO: Make #capture usable outside of ERB
+ # This dance is needed because Builder can't use capture
+ pos = output_buffer.length
+ yield
+ fragment = output_buffer.slice!(pos..-1)
+ controller.write_fragment(name, fragment, options)
+ end
+ else
+ ret = yield
+ ActiveSupport::SafeBuffer.new(ret) if ret.is_a?(String)
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 75fc2fddeb..f0be814700 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -2,22 +2,22 @@ module ActionView
module Helpers
# CaptureHelper exposes methods to let you extract generated markup which
# can be used in other parts of a template or layout file.
- # It provides a method to capture blocks into variables through capture and
+ # It provides a method to capture blocks into variables through capture and
# a way to capture a block of markup for use in a layout through content_for.
module CaptureHelper
- # The capture method allows you to extract part of a template into a
- # variable. You can then use this variable anywhere in your templates or layout.
- #
+ # The capture method allows you to extract part of a template into a
+ # variable. You can then use this variable anywhere in your templates or layout.
+ #
# ==== Examples
# The capture method can be used in ERb templates...
- #
+ #
# <% @greeting = capture do %>
# Welcome to my shiny new web page! The date and time is
# <%= Time.now %>
# <% end %>
#
# ...and Builder (RXML) templates.
- #
+ #
# @timestamp = capture do
# "The current timestamp is #{Time.now}."
# end
@@ -32,16 +32,18 @@ module CaptureHelper
#
def capture(*args)
value = nil
- buffer = with_output_buffer { value = yield *args }
- buffer.presence || value
+ buffer = with_output_buffer { value = yield(*args) }
+ if string = buffer.presence || value and string.is_a?(String)
+ NonConcattingString.new(string)
+ end
end
# Calling content_for stores a block of markup in an identifier for later use.
# You can make subsequent calls to the stored content in other templates or the layout
# by passing the identifier as an argument to yield.
- #
+ #
# ==== Examples
- #
+ #
# <% content_for :not_authorized do %>
# alert('You are not authorized to do that!')
# <% end %>
@@ -75,7 +77,7 @@ def capture(*args)
#
# Then, in another view, you could to do something like this:
#
- # <%= link_to_remote 'Logout', :action => 'logout' %>
+ # <%= link_to 'Logout', :action => 'logout', :remote => true %>
#
# <% content_for :script do %>
# <%= javascript_include_tag :defaults %>
@@ -92,7 +94,7 @@ def capture(*args)
# <% end %>
#
# <%# Add some other content, or use a different template: %>
- #
+ #
# <% content_for :navigation do %>
#
<%= link_to 'Login', :action => 'login' %>
# <% end %>
@@ -109,13 +111,13 @@ def capture(*args)
# for elements that will be fragment cached.
def content_for(name, content = nil, &block)
content = capture(&block) if block_given?
- return @_content_for[name] << content if content
- @_content_for[name]
+ @_content_for[name] << content if content
+ @_content_for[name] unless content
end
# content_for? simply checks whether any content has been captured yet using content_for
# Useful to render parts of your layout differently based on what is in your views.
- #
+ #
# ==== Examples
#
# Perhaps you will use different css in you layout if no content_for :right_column
@@ -140,7 +142,7 @@ def content_for?(name)
def with_output_buffer(buf = nil) #:nodoc:
unless buf
buf = ActionView::OutputBuffer.new
- buf.force_encoding(output_buffer.encoding) if buf.respond_to?(:force_encoding)
+ buf.force_encoding(output_buffer.encoding) if output_buffer && buf.respond_to?(:force_encoding)
end
self.output_buffer, old_buffer = buf, output_buffer
yield
diff --git a/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb b/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb
deleted file mode 100644
index 3d0657e873..0000000000
--- a/actionpack/lib/action_view/helpers/deprecated_block_helpers.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-module ActionView
- module Helpers
- module DeprecatedBlockHelpers
- extend ActiveSupport::Concern
-
- include ActionView::Helpers::TagHelper
- include ActionView::Helpers::TextHelper
- include ActionView::Helpers::JavaScriptHelper
- include ActionView::Helpers::FormHelper
-
- def content_tag(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def javascript_tag(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def form_for(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def form_tag(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def fields_for(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- def field_set_tag(*, &block)
- block_called_from_erb?(block) ? safe_concat(super) : super
- end
-
- BLOCK_CALLED_FROM_ERB = 'defined? __in_erb_template'
-
- if RUBY_VERSION < '1.9.0'
- # Check whether we're called from an erb template.
- # We'd return a string in any other case, but erb <%= ... %>
- # can't take an <% end %> later on, so we have to use <% ... %>
- # and implicitly concat.
- def block_called_from_erb?(block)
- block && eval(BLOCK_CALLED_FROM_ERB, block)
- end
- else
- def block_called_from_erb?(block)
- block && eval(BLOCK_CALLED_FROM_ERB, block.binding)
- end
- end
- end
- end
-end
\ No newline at end of file
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 48df26efaa..2ba5339b7d 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -28,7 +28,7 @@ module Helpers
#
# # Note: a @person variable will have been created in the controller.
# # For example: @person = Person.new
- # <% form_for :person, @person, :url => { :action => "create" } do |f| %>
+ # <%= form_for :person, @person, :url => { :action => "create" } do |f| %>
# <%= f.text_field :first_name %>
# <%= f.text_field :last_name %>
# <%= submit_tag 'Create' %>
@@ -44,7 +44,7 @@ module Helpers
#
# If you are using a partial for your form fields, you can use this shortcut:
#
- # <% form_for :person, @person, :url => { :action => "create" } do |f| %>
+ # <%= form_for :person, @person, :url => { :action => "create" } do |f| %>
# <%= render :partial => f %>
# <%= submit_tag 'Create' %>
# <% end %>
@@ -102,7 +102,7 @@ module FormHelper
# Rails provides succinct resource-oriented form generation with +form_for+
# like this:
#
- # <% form_for @offer do |f| %>
+ # <%= form_for @offer do |f| %>
# <%= f.label :version, 'Version' %>:
# <%= f.text_field :version %>
# <%= f.label :author, 'Author' %>:
@@ -119,7 +119,7 @@ module FormHelper
# The generic way to call +form_for+ yields a form builder around a
# model:
#
- # <% form_for :person, :url => { :action => "update" } do |f| %>
+ # <%= form_for :person, :url => { :action => "update" } do |f| %>
# <%= f.error_messages %>
# First name: <%= f.text_field :first_name %>
# Last name : <%= f.text_field :last_name %>
@@ -143,7 +143,7 @@ module FormHelper
# If the instance variable is not @person you can pass the actual
# record as the second argument:
#
- # <% form_for :person, person, :url => { :action => "update" } do |f| %>
+ # <%= form_for :person, person, :url => { :action => "update" } do |f| %>
# ...
# <% end %>
#
@@ -175,7 +175,7 @@ module FormHelper
# possible to use both the stand-alone FormHelper methods and methods
# from FormTagHelper. For example:
#
- # <% form_for :person, @person, :url => { :action => "update" } do |f| %>
+ # <%= form_for :person, @person, :url => { :action => "update" } do |f| %>
# First name: <%= f.text_field :first_name %>
# Last name : <%= f.text_field :last_name %>
# Biography : <%= text_area :person, :biography %>
@@ -195,37 +195,37 @@ module FormHelper
#
# For example, if @post is an existing record you want to edit
#
- # <% form_for @post do |f| %>
+ # <%= form_for @post do |f| %>
# ...
# <% end %>
#
# is equivalent to something like:
#
- # <% form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
+ # <%= form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
# ...
# <% end %>
#
# And for new records
#
- # <% form_for(Post.new) do |f| %>
+ # <%= form_for(Post.new) do |f| %>
# ...
# <% end %>
#
# expands to
#
- # <% form_for :post, Post.new, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %>
+ # <%= form_for :post, Post.new, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %>
# ...
# <% end %>
#
# You can also overwrite the individual conventions, like this:
#
- # <% form_for(@post, :url => super_post_path(@post)) do |f| %>
+ # <%= form_for(@post, :url => super_post_path(@post)) do |f| %>
# ...
# <% end %>
#
# And for namespaced routes, like +admin_post_url+:
#
- # <% form_for([:admin, @post]) do |f| %>
+ # <%= form_for([:admin, @post]) do |f| %>
# ...
# <% end %>
#
@@ -243,7 +243,7 @@ module FormHelper
#
# Example:
#
- # <% form_for(:post, @post, :remote => true, :html => { :id => 'create-post', :method => :put }) do |f| %>
+ # <%= form_for(:post, @post, :remote => true, :html => { :id => 'create-post', :method => :put }) do |f| %>
# ...
# <% end %>
#
@@ -263,7 +263,7 @@ module FormHelper
# custom builder. For example, let's say you made a helper to
# automatically add labels to form inputs.
#
- # <% form_for :person, @person, :url => { :action => "update" }, :builder => LabellingFormBuilder do |f| %>
+ # <%= form_for :person, @person, :url => { :action => "update" }, :builder => LabellingFormBuilder do |f| %>
# <%= f.text_field :first_name %>
# <%= f.text_field :last_name %>
# <%= text_area :person, :biography %>
@@ -340,11 +340,11 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
#
# === Generic Examples
#
- # <% form_for @person, :url => { :action => "update" } do |person_form| %>
+ # <%= form_for @person, :url => { :action => "update" } do |person_form| %>
# First name: <%= person_form.text_field :first_name %>
# Last name : <%= person_form.text_field :last_name %>
#
- # <% fields_for @person.permission do |permission_fields| %>
+ # <%= fields_for @person.permission do |permission_fields| %>
# Admin? : <%= permission_fields.check_box :admin %>
# <% end %>
# <% end %>
@@ -352,13 +352,13 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
# ...or if you have an object that needs to be represented as a different
# parameter, like a Client that acts as a Person:
#
- # <% fields_for :person, @client do |permission_fields| %>
+ # <%= fields_for :person, @client do |permission_fields| %>
# Admin?: <%= permission_fields.check_box :admin %>
# <% end %>
#
# ...or if you don't have an object, just a name of the parameter:
#
- # <% fields_for :person do |permission_fields| %>
+ # <%= fields_for :person do |permission_fields| %>
# Admin?: <%= permission_fields.check_box :admin %>
# <% end %>
#
@@ -402,9 +402,9 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
#
# This model can now be used with a nested fields_for, like so:
#
- # <% form_for @person, :url => { :action => "update" } do |person_form| %>
+ # <%= form_for @person, :url => { :action => "update" } do |person_form| %>
# ...
- # <% person_form.fields_for :address do |address_fields| %>
+ # <%= person_form.fields_for :address do |address_fields| %>
# Street : <%= address_fields.text_field :street %>
# Zip code: <%= address_fields.text_field :zip_code %>
# <% end %>
@@ -427,15 +427,15 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
# accepts_nested_attributes_for :address, :allow_destroy => true
# end
#
- # Now, when you use a form element with the _delete parameter,
+ # Now, when you use a form element with the _destroy parameter,
# with a value that evaluates to +true+, you will destroy the associated
# model (eg. 1, '1', true, or 'true'):
#
- # <% form_for @person, :url => { :action => "update" } do |person_form| %>
+ # <%= form_for @person, :url => { :action => "update" } do |person_form| %>
# ...
- # <% person_form.fields_for :address do |address_fields| %>
+ # <%= person_form.fields_for :address do |address_fields| %>
# ...
- # Delete: <%= address_fields.check_box :_delete %>
+ # Delete: <%= address_fields.check_box :_destroy %>
# <% end %>
# <% end %>
#
@@ -459,9 +459,9 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
# the nested fields_for call will be repeated for each instance in the
# collection:
#
- # <% form_for @person, :url => { :action => "update" } do |person_form| %>
+ # <%= form_for @person, :url => { :action => "update" } do |person_form| %>
# ...
- # <% person_form.fields_for :projects do |project_fields| %>
+ # <%= person_form.fields_for :projects do |project_fields| %>
# <% if project_fields.object.active? %>
# Name: <%= project_fields.text_field :name %>
# <% end %>
@@ -470,11 +470,11 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
#
# It's also possible to specify the instance to be used:
#
- # <% form_for @person, :url => { :action => "update" } do |person_form| %>
+ # <%= form_for @person, :url => { :action => "update" } do |person_form| %>
# ...
# <% @person.projects.each do |project| %>
# <% if project.active? %>
- # <% person_form.fields_for :projects, project do |project_fields| %>
+ # <%= person_form.fields_for :projects, project do |project_fields| %>
# Name: <%= project_fields.text_field :name %>
# <% end %>
# <% end %>
@@ -483,9 +483,9 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
#
# Or a collection to be used:
#
- # <% form_for @person, :url => { :action => "update" } do |person_form| %>
+ # <%= form_for @person, :url => { :action => "update" } do |person_form| %>
# ...
- # <% person_form.fields_for :projects, @active_projects do |project_fields| %>
+ # <%= person_form.fields_for :projects, @active_projects do |project_fields| %>
# Name: <%= project_fields.text_field :name %>
# <% end %>
# <% end %>
@@ -508,14 +508,14 @@ def apply_form_for_options!(object_or_array, options) #:nodoc:
# end
#
# This will allow you to specify which models to destroy in the
- # attributes hash by adding a form element for the _delete
+ # attributes hash by adding a form element for the _destroy
# parameter with a value that evaluates to +true+
# (eg. 1, '1', true, or 'true'):
#
- # <% form_for @person, :url => { :action => "update" } do |person_form| %>
+ # <%= form_for @person, :url => { :action => "update" } do |person_form| %>
# ...
- # <% person_form.fields_for :projects do |project_fields| %>
- # Delete: <%= project_fields.check_box :_delete %>
+ # <%= person_form.fields_for :projects do |project_fields| %>
+ # Delete: <%= project_fields.check_box :_destroy %>
# <% end %>
# <% end %>
def fields_for(record_or_name_or_array, *args, &block)
@@ -725,7 +725,7 @@ def text_area(object_name, method, options = {})
# Unfortunately that workaround does not work when the check box goes
# within an array-like parameter, as in
#
- # <% fields_for "project[invoice_attributes][]", invoice, :index => nil do |form| %>
+ # <%= fields_for "project[invoice_attributes][]", invoice, :index => nil do |form| %>
# <%= form.check_box :paid %>
# ...
# <% end %>
@@ -1014,7 +1014,7 @@ class InstanceTag
class FormBuilder #:nodoc:
# The methods which wrap a form helper call.
class_inheritable_accessor :field_helpers
- self.field_helpers = (FormHelper.instance_methods - ['form_for'])
+ self.field_helpers = (FormHelper.instance_method_names - ['form_for'])
attr_accessor :object_name, :object, :options
@@ -1040,7 +1040,7 @@ def initialize(object_name, object, template, options, proc)
end
(field_helpers - %w(label check_box radio_button fields_for hidden_field)).each do |selector|
- src = <<-end_src
+ src, file, line = <<-end_src, __FILE__, __LINE__ + 1
def #{selector}(method, options = {}) # def text_field(method, options = {})
@template.send( # @template.send(
#{selector.inspect}, # "text_field",
@@ -1049,7 +1049,7 @@ def #{selector}(method, options = {}) # def text_field(method, options = {})
objectify_options(options)) # objectify_options(options))
end # end
end_src
- class_eval src, __FILE__, __LINE__
+ class_eval src, file, line
end
def fields_for(record_or_name_or_array, *args, &block)
@@ -1115,7 +1115,7 @@ def error_messages(options = {})
# Add the submit button for the given form. When no value is given, it checks
# if the object is a new resource or not to create the proper label:
#
- # <% form_for @post do |f| %>
+ # <%= form_for @post do |f| %>
# <%= f.submit %>
# <% end %>
#
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 7039ecd233..4c523d4b20 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -151,7 +151,7 @@ def select(object, method, choices, options = {}, html_options = {})
# end
#
# Sample usage (selecting the associated Author for an instance of Post, @post):
- # collection_select(:post, :author_id, Author.all, :id, :name_with_initial, {:prompt => true})
+ # collection_select(:post, :author_id, Author.all, :id, :name_with_initial, :prompt => true)
#
# If @post.author_id is already 1, this would return:
#
- <%= f.submit button_label %>
+ <%= f.submit %>
<% end %>
-Although the same partial will be rendered into both views, the label on the submit button is controlled by a local variable passed into the partial.
+Although the same partial will be rendered into both views, Action View's submit helper will return "Create Zone" for the new action and "Update Zone" for the edit action.
Every partial also has a local variable with the same name as the partial (minus the underscore). You can pass an object in to this local variable via the +:object+ option:
@@ -838,15 +1058,15 @@ Every partial also has a local variable with the same name as the partial (minus
Within the +customer+ partial, the +customer+ variable will refer to +@new_customer+ from the parent view.
-WARNING: In previous versions of Rails, the default local variable would look for an instance variable with the same name as the partial in the parent. This behavior is deprecated in Rails 2.2 and will be removed in a future version.
+WARNING: In previous versions of Rails, the default local variable would look for an instance variable with the same name as the partial in the parent. This behavior was deprecated in 2.3 and has been removed in Rails 3.0.
If you have an instance of a model to render into a partial, you can use a shorthand syntax:
-<%= render :partial => @customer %>
+<%= render @customer %>
-Assuming that the +@customer+ instance variable contains an instance of the +Customer+ model, this will use +_customer.html.erb+ to render it.
+Assuming that the +@customer+ instance variable contains an instance of the +Customer+ model, this will use +_customer.html.erb+ to render it and will pass the local variable +customer+ into the partial which will refer to the +@customer+ instance variable in the parent view.
h5. Rendering Collections
@@ -865,39 +1085,16 @@ Partials are very useful in rendering collections. When you pass a collection to
Product Name: <%= product.name %>
-When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is +_product+, and within the +_product+ partial, you can refer to +product+ to get the instance that is being rendered. To use a custom local variable name within the partial, specify the +:as+ option in the call to the partial:
+When a partial is called with a pluralized collection, then the individual instances of the partial have access to the member of the collection being rendered via a variable named after the partial. In this case, the partial is +_product+, and within the +_product+ partial, you can refer to +product+ to get the instance that is being rendered.
-
-<%= render :partial => "product", :collection => @products, :as => :item %>
-
-
-With this change, you can access an instance of the +@products+ collection as the +item+ local variable within the partial.
-
-TIP: Rails also makes a counter variable available within a partial called by the collection, named after the member of the collection followed by +_counter+. For example, if you're rendering +@products+, within the partial you can refer to +product_counter+ to tell you how many times the partial has been rendered.
-
-You can also specify a second partial to be rendered between instances of the main partial by using the +:spacer_template+ option:
-
-
-<%= render :partial => "product", :collection => @products,
- :spacer_template => "product_ruler" %>
-
-
-Rails will render the +_product_ruler+ partial (with no data passed in to it) between each pair of +_product+ partials.
-
-There's also a shorthand syntax available for rendering collections. For example, if +@products+ is a collection of products, you can render the collection this way:
-
-* +index.html.erb+
+In Rails 3.0 there is also a shorthand for this, assuming +@posts+ is a collection of +post+ instances, you can simply do in the +index.html.erb+:
-
+To produce the same result.
Rails determines the name of the partial to use by looking at the model name in the collection. In fact, you can even create a heterogeneous collection and render it this way, and Rails will choose the proper partial for each member of the collection:
@@ -905,24 +1102,54 @@ Rails determines the name of the partial to use by looking at the model name in
In this case, Rails will use the customer or employee partials as appropriate for each member of the collection.
+h5. Local Variables
+
+To use a custom local variable name within the partial, specify the +:as+ option in the call to the partial:
+
+
+<%= render :partial => "product", :collection => @products, :as => :item %>
+
+
+With this change, you can access an instance of the +@products+ collection as the +item+ local variable within the partial.
+
+You can also pass in arbitrary local variables to any partial you are rendering with the +:locals => {}+ option:
+
+
+<%= render :partial => 'products', :collection => @products,
+ :as => :item, :locals => {:title => "Products Page"} %>
+
+
+Would render a partial +_products.html.erb+ once for each instance of +product+ in the +@products+ instance variable passing the instance to the partial as a local variable called +item+ and to each partial, make the local variable +title+ available with the value +Products Page+.
+
+TIP: Rails also makes a counter variable available within a partial called by the collection, named after the member of the collection followed by +_counter+. For example, if you're rendering +@products+, within the partial you can refer to +product_counter+ to tell you how many times the partial has been rendered. This does not work in conjunction with the +:as => :value+ option.
+
+You can also specify a second partial to be rendered between instances of the main partial by using the +:spacer_template+ option:
+
+h5. Spacer Templates
+
+
+<%= render @products, :spacer_template => "product_ruler" %>
+
+
+Rails will render the +_product_ruler+ partial (with no data passed in to it) between each pair of +_product+ partials.
+
h4. Using Nested Layouts
You may find that your application requires a layout that differs slightly from your regular application layout to support one particular controller. Rather than repeating the main layout and editing it, you can accomplish this by using nested layouts (sometimes called sub-templates). Here's an example:
@@ -964,12 +1191,13 @@ On pages generated by +NewsController+, you want to hide the top menu and add a
That's it. The News views will use the new layout, hiding the top menu and adding a new right menu inside the "content" div.
-There are several ways of getting similar results with different sub-templating schemes using this technique. Note that there is no limit in nesting levels. One can use the +ActionView::render+ method via +render :file => 'layouts/news'+ to base a new layout on the News layout. If one is sure she will not subtemplate the +News+ layout, she can omit the +yield(:news_content) or + part.
+There are several ways of getting similar results with different sub-templating schemes using this technique. Note that there is no limit in nesting levels. One can use the +ActionView::render+ method via +render :file => 'layouts/news'+ to base a new layout on the News layout. If you are sure you will not subtemplate the +News+ layout, you can replace the +yield(:news_content) or yield+ with simply +yield+.
h3. Changelog
"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/15
+* January 25, 2010: Rails 3.0 Update by "Mikel Lindsaar":credits.html#raasdnil
* December 27, 2008: Merge patch from Rodrigo Rosenfeld Rosas covering subtemplates
* December 27, 2008: Information on new rendering defaults by "Mike Gunderloy":credits.html#mgunderloy
* November 9, 2008: Added partial collection counter by "Mike Gunderloy":credits.html#mgunderloy
diff --git a/railties/guides/source/plugins.textile b/railties/guides/source/plugins.textile
index 71e1a7e3d3..2db421aa91 100644
--- a/railties/guides/source/plugins.textile
+++ b/railties/guides/source/plugins.textile
@@ -104,7 +104,7 @@ To make it easy to organize your files and to make the plugin more compatible wi
`-- init.rb
-*vendor/plugins/yaffle/rails/init.rb*
+*vendor/plugins/yaffle/init.rb*
require 'yaffle'
@@ -341,13 +341,15 @@ $ rails console
h4. Working with +init.rb+
-When rails loads plugins it looks for the file named 'init.rb' or 'rails/init.rb'. However, when the plugin is initialized, 'init.rb' is invoked via +eval+ (not +require+) so it has slightly different behavior.
+When Rails loads plugins it looks for a file named +init.rb+. However, when the plugin is initialized, +init.rb+ is invoked via +eval+ (not +require+) so it has slightly different behavior.
-Under certain circumstances if you reopen classes or modules in 'init.rb' you may inadvertently create a new class, rather than reopening an existing class. A better alternative is to reopen the class in a different file, and require that file from +init.rb+, as shown above.
+NOTE: The plugins loader also looks for +rails/init.rb+, but that one is deprecated in favor of the top-level +init.rb+ aforementioned.
+
+Under certain circumstances if you reopen classes or modules in +init.rb+ you may inadvertently create a new class, rather than reopening an existing class. A better alternative is to reopen the class in a different file, and require that file from +init.rb+, as shown above.
If you must reopen a class in +init.rb+ you can use +module_eval+ or +class_eval+ to avoid any issues:
-* *vendor/plugins/yaffle/rails/init.rb*
+* *vendor/plugins/yaffle/init.rb*
Hash.class_eval do
@@ -359,7 +361,7 @@ end
Another way is to explicitly define the top-level module space for all modules and classes, like +::Hash+:
-* *vendor/plugins/yaffle/rails/init.rb*
+* *vendor/plugins/yaffle/init.rb*
class ::Hash
@@ -1333,15 +1335,15 @@ yaffle:squawk # Prints out the word 'Yaffle'
You can add as many files as you want in the tasks directory, and if they end in .rake Rails will pick them up.
-Note that tasks from 'vendor/plugins/yaffle/Rakefile' are not available to the main app.
+Note that tasks from +vendor/plugins/yaffle/Rakefile+ are not available to the main app.
-h3. PluginGems
+h3. Plugins as Gems
Turning your rails plugin into a gem is a simple and straightforward task. This section will cover how to turn your plugin into a gem. It will not cover how to distribute that gem.
-Historically rails plugins loaded the plugin's 'init.rb' file. In fact some plugins contain all of their code in that one file. To be compatible with plugins, 'init.rb' was moved to 'rails/init.rb'.
+The initialization file has to be called +rails/init.rb+, the root +init.rb+ file, if any, is ignored by Rails. Also, the name of the plugin now is relevant since +config.gem+ tries to load it. Either name the main file after your gem, or document that users should use the +:lib+ option.
-It's common practice to put any developer-centric rake tasks (such as tests, rdoc and gem package tasks) in 'Rakefile'. A rake task that packages the gem might look like this:
+It's common practice to put any developer-centric rake tasks (such as tests, rdoc and gem package tasks) in +Rakefile+. A rake task that packages the gem might look like this:
* *vendor/plugins/yaffle/Rakefile:*
@@ -1383,7 +1385,7 @@ rake gem
sudo gem install pkg/yaffle-0.0.1.gem
-To test this, create a new rails app, add 'config.gem "yaffle"' to environment.rb and all of your plugin's functionality will be available to you.
+To test this, create a new rails app, add +config.gem "yaffle"+ to +config/environment.rb+ and all of your plugin's functionality will be available to you.
h3. RDoc Documentation
diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile
index 24f0578545..8cf084494b 100644
--- a/railties/guides/source/routing.textile
+++ b/railties/guides/source/routing.textile
@@ -4,7 +4,7 @@ This guide covers the user-facing features of Rails routing. By referring to thi
* Understand the purpose of routing
* Decipher the code in +routes.rb+
-* Construct your own routes, using either the classic hash style or the now-preferred RESTful style
+* Construct your own routes, using either the @match@ method or the preferred RESTful style
* Identify how a route will map to a controller and action
endprologue.
@@ -37,7 +37,7 @@ Routing also works in reverse. If your application contains this code:
Then the routing engine is the piece that translates that to a link to a URL such as +http://example.com/patients/17+. By using routing in this way, you can reduce the brittleness of your application as compared to one with hard-coded URLs, and make your code easier to read and understand.
-NOTE: Patient needs to be declared as a resource for this style of translation via a named route to be available.
+NOTE: Patient needs to be declared as a Restful resource for this style of translation to be available.
h3. Quick Tour of +routes.rb+
@@ -45,7 +45,7 @@ There are two components to routing in Rails: the routing engine itself, which i
h4. Processing the File
-In format, +routes.rb+ is nothing more than one big block sent to +ActionController::Routing::Routes.draw+. Within this block, you can have comments, but it's likely that most of your content will be individual lines of code - each line being a route in your application. You'll find five main types of content in this file:
+In format, +routes.rb+ is nothing more than one big block sent to +ApplicationName::Application.routes.draw+. Within this block, you can have comments, but it's likely that most of your content will be individual lines of code - each line being a route in your application. You'll find five main types of content in this file:
* RESTful Routes
* Named Routes
@@ -55,31 +55,39 @@ In format, +routes.rb+ is nothing more than one big block sent to +ActionControl
Each of these types of route is covered in more detail later in this guide.
-The +routes.rb+ file is processed from top to bottom when a request comes in. The request will be dispatched to the first matching route. If there is no matching route, then Rails returns HTTP status 404 to the caller.
+The +routes.rb+ file is processed from top to bottom when a request comes in. The request will be dispatched to the first matching route, and then proceeds to the next. If there is no matching route, then Rails returns HTTP status 404 to the caller.
h4. RESTful Routes
-RESTful routes take advantage of the built-in REST orientation of Rails to wrap up a lot of routing information in a single declaration. A RESTful route looks like this:
+RESTful routes take advantage of the built-in REST orientation of Rails to wrap up a lot of routing information with a single declaration. A RESTful route looks like this:
-map.resources :books
+resources :books
h4. Named Routes
Named routes give you very readable links in your code, as well as handling incoming requests. Here's a typical named route:
+
+match 'login' => 'sessions#new', :as => 'login'
+
+
+If you're coming from Rails 2, this route will be equivalent to:
+
map.login '/login', :controller => 'sessions', :action => 'new'
+You will also notice that +sessions#new+ is a shorthand for +:controller => 'sessions', :action => 'new'+. By declaring a named route such as this, you can use +login_path+ or +login_url+ in your controllers and views to generate the URLs for this route.
+
h4. Nested Routes
Nested routes let you declare that one resource is contained within another resource. You'll see later on how this translates to URLs and paths in your code. For example, if your application includes parts, each of which belongs to an assembly, you might have this nested route declaration:
-map.resources :assemblies do |assemblies|
- assemblies.resources :parts
+resources :assemblies do
+ resources :parts
end
@@ -88,19 +96,18 @@ h4. Regular Routes
In many applications, you'll also see non-RESTful routing, which explicitly connects the parts of a URL to a particular action. For example,
-map.connect 'parts/:number', :controller => 'inventory', :action => 'show'
+match 'parts/:number' => 'inventory#show'
h4. Default Routes
-The default routes are a safety net that catch otherwise-unrouted requests. Many Rails applications will contain this pair of default routes:
+The default route is a safety net that catches otherwise-unrouted requests. Many Rails applications will contain this default route:
-map.connect ':controller/:action/:id'
-map.connect ':controller/:action/:id.:format'
+match ':controller(/:action(/:id(.:format)))'
-These default routes are automatically generated when you create a new Rails application. If you're using RESTful routing for everything in your application, you will probably want to remove them. But be sure you're not using the default routes before you remove them!
+In Rails 3, this route is commented out advising to use RESTful routes as much as possible. So if you're using RESTful routing for everything in your application, you will probably want to leave it like that.
h3. RESTful Routing: the Rails Default
@@ -126,7 +133,7 @@ h4. CRUD, Verbs, and Actions
In Rails, a RESTful route provides a mapping between HTTP verbs, controller actions, and (implicitly) CRUD operations in a database. A single entry in the routing file, such as
-map.resources :photos
+resources :photos
creates seven different routes in your application:
@@ -142,11 +149,9 @@ creates seven different routes in your application:
For the specific routes (those that reference just a single resource), the identifier for the resource will be available within the corresponding controller action as +params[:id]+.
-TIP: If you consistently use RESTful routes in your application, you should disable the default routes in +routes.rb+ so that Rails will enforce the mapping between HTTP verbs and routes.
-
h4. URLs and Paths
-Creating a RESTful route will also make available a pile of helpers within your application:
+Creating a RESTful route will also make available a pile of helpers within your application, something that requires explicit mention otherwise:
* +photos_url+ and +photos_path+ map to the path for the index and create actions
* +new_photo_url+ and +new_photo_path+ map to the path for the new action
@@ -164,26 +169,26 @@ photos_path # => "/photos"
h4. Defining Multiple Resources at the Same Time
-If you need to create routes for more than one RESTful resource, you can save a bit of typing by defining them all with a single call to +map.resources+:
+If you need to create routes for more than one RESTful resource, you can save a bit of typing by defining them all with a single call to +resources+:
-map.resources :photos, :books, :videos
+resources :photos, :books, :videos
This has exactly the same effect as
-map.resources :photos
-map.resources :books
-map.resources :videos
+resources :photos
+resources :books
+resources :videos
h4. Singular Resources
-You can also apply RESTful routing to singleton resources within your application. In this case, you use +map.resource+ instead of +map.resources+ and the route generation is slightly different. For example, a routing entry of
+You can also apply RESTful routing to singleton resources within your application. In this case, you use +resource+ instead of +resources+ and the route generation is slightly different. For example, a routing entry of
-map.resource :geocoder
+resource :geocoder
creates six different routes in your application:
@@ -214,19 +219,17 @@ Although the conventions of RESTful routing are likely to be sufficient for many
* +:conditions+
* +:as+
* +:path_names+
-* +:path_prefix+
-* +:name_prefix+
* +:only+
* +:except+
-You can also add additional routes via the +:member+ and +:collection+ options, which are discussed later in this guide.
+You can also add additional routes via the +member+ and +collection+ blocks, which are discussed later in this guide.
h5. Using +:controller+
The +:controller+ option lets you use a controller name that is different from the public-facing resource name. For example, this routing entry:
-map.resources :photos, :controller => "images"
+resources :photos, :controller => "images"
will recognize incoming URLs containing +photo+ but route the requests to the Images controller:
@@ -247,35 +250,37 @@ h4. Controller Namespaces and Routing
Rails allows you to group your controllers into namespaces by saving them in folders underneath +app/controllers+. The +:controller+ option provides a convenient way to use these routes. For example, you might have a resource whose controller is purely for admin users in the +admin+ folder:
-map.resources :adminphotos, :controller => "admin/photos"
+resources :photos, :controller => "admin/photos"
-If you use controller namespaces, you need to be aware of a subtlety in the Rails routing code: it always tries to preserve as much of the namespace from the previous request as possible. For example, if you are on a view generated from the +adminphoto_path+ helper, and you follow a link generated with +<%= link_to "show", adminphoto(1) %>+ you will end up on the view generated by +admin/photos/show+, but you will also end up in the same place if you have +<%= link_to "show", {:controller => "photos", :action => "show"} %>+ because Rails will generate the show URL relative to the current URL.
+If you use controller namespaces, you need to be aware of a subtlety in the Rails routing code: it always tries to preserve as much of the namespace from the previous request as possible. For example, if you are on a view generated from the +photo_path+ helper, and you follow a link generated with +<%= link_to "show", photo_path(1) %>+ you will end up on the view generated by +admin/photos/show+, but you will also end up in the same place if you have +<%= link_to "show", {:controller => "photos", :action => "show"} %>+ because Rails will generate the show URL relative to the current URL.
TIP: If you want to guarantee that a link goes to a top-level controller, use a preceding slash to anchor the controller name: +<%= link_to "show", {:controller => "/photos", :action => "show"} %>+
You can also specify a controller namespace with the +:namespace+ option instead of a path:
-map.resources :adminphotos, :namespace => "admin", :controller => "photos"
+resources :adminphotos, :namespace => "admin", :controller => "photos"
-This can be especially useful when combined with +with_options+ to map multiple namespaced routes together:
+This can be especially useful when map multiple namespaced routes together using +namespace+ block by:
-map.with_options(:namespace => "admin") do |admin|
- admin.resources :photos, :videos
+namespace :admin do
+ resources :photos, :videos
end
-That would give you routing for +admin/photos+ and +admin/videos+ controllers.
+That would give you routing for +admin/photos+ and +admin/videos+ controllers.
+
+The difference between generating routes through +namespace+ and the +:controller+ key is that the +namespace+ will add +admin+ to the generated helpers as well, so the above route generates +admin_photos_path+.
h5. Using +:singular+
If for some reason Rails isn't doing what you want in converting the plural resource name to a singular name in member routes, you can override its judgment with the +:singular+ option:
-map.resources :teeth, :singular => "tooth"
+resources :teeth, :singular => "tooth"
TIP: Depending on the other code in your application, you may prefer to add additional rules to the +Inflector+ class instead.
@@ -285,7 +290,7 @@ h5. Using +:requirements+
You can use the +:requirements+ option in a RESTful route to impose a format on the implied +:id+ parameter in the singular routes. For example:
-map.resources :photos, :requirements => {:id => /[A-Z][A-Z][0-9]+/}
+resources :photos, :requirements => {:id => /[A-Z][A-Z][0-9]+/}
This declaration constrains the +:id+ parameter to match the supplied regular expression. So, in this case, +/photos/1+ would no longer be recognized by this route, but +/photos/RR27+ would.
@@ -299,7 +304,7 @@ h5. Using +:as+
The +:as+ option lets you override the normal naming for the actual generated paths. For example:
-map.resources :photos, :as => "images"
+resources :photos, :as => "images"
will recognize incoming URLs containing +image+ but route the requests to the Photos controller:
@@ -320,7 +325,7 @@ h5. Using +:path_names+
The +:path_names+ option lets you override the automatically-generated "new" and "edit" segments in URLs:
-map.resources :photos, :path_names => { :new => 'make', :edit => 'change' }
+resources :photos, :path_names => { :new => 'make', :edit => 'change' }
This would cause the routing to recognize URLs such as
@@ -343,7 +348,7 @@ h5. Using +:path_prefix+
The +:path_prefix+ option lets you add additional parameters that will be prefixed to the recognized paths. For example, suppose each photo in your application belongs to a particular photographer. In that case, you might declare this route:
-map.resources :photos, :path_prefix => '/photographers/:photographer_id'
+resources :photos, :path_prefix => '/photographers/:photographer_id'
Routes recognized by this entry would include:
@@ -362,9 +367,9 @@ h5. Using +:name_prefix+
You can use the :name_prefix option to avoid collisions between routes. This is most useful when you have two resources with the same name that use +:path_prefix+ to map differently. For example:
-map.resources :photos, :path_prefix => '/photographers/:photographer_id',
+resources :photos, :path_prefix => '/photographers/:photographer_id',
:name_prefix => 'photographer_'
-map.resources :photos, :path_prefix => '/agencies/:agency_id',
+resources :photos, :path_prefix => '/agencies/:agency_id',
:name_prefix => 'agency_'
@@ -377,7 +382,7 @@ h5. Using +:only+ and +:except+
By default, Rails creates routes for all seven of the default actions (index, show, new, create, edit, update, and destroy) for every RESTful route in your application. You can use the +:only+ and +:except+ options to fine-tune this behavior. The +:only+ option specifies that only certain routes should be generated:
-map.resources :photos, :only => [:index, :show]
+resources :photos, :only => [:index, :show]
With this declaration, a +GET+ request to +/photos+ would succeed, but a +POST+ request to +/photos+ (which would ordinarily be routed to the create action) will fail.
@@ -385,7 +390,7 @@ With this declaration, a +GET+ request to +/photos+ would succeed, but a +POST+
The +:except+ option specifies a route or list of routes that should _not_ be generated:
-map.resources :photos, :except => :destroy
+resources :photos, :except => :destroy
In this case, all of the normal routes except the route for +destroy+ (a +DELETE+ request to +/photos/id+) will be generated.
@@ -411,12 +416,12 @@ end
Each ad is logically subservient to one magazine. Nested routes allow you to capture this relationship in your routing. In this case, you might include this route declaration:
-map.resources :magazines do |magazine|
- magazine.resources :ads
+resources :magazines do
+ resources :ads
end
-TIP: Further below you'll learn about a convenient shortcut for this construct: +map.resources :magazines, :has_many => :ads+
+TIP: Further below you'll learn about a convenient shortcut for this construct: +resources :magazines, :has_many => :ads+
In addition to the routes for magazines, this declaration will also create routes for ads, each of which requires the specification of a magazine in the URL:
@@ -437,16 +442,16 @@ h5. Using +:name_prefix+
The +:name_prefix+ option overrides the automatically-generated prefix in nested route helpers. For example,
-map.resources :magazines do |magazine|
- magazine.resources :ads, :name_prefix => 'periodical'
+resources :magazines do
+ resources :ads, :name_prefix => 'periodical'
end
This will create routing helpers such as +periodical_ads_url+ and +periodical_edit_ad_path+. You can even use +:name_prefix+ to suppress the prefix entirely:
-map.resources :magazines do |magazine|
- magazine.resources :ads, :name_prefix => nil
+resources :magazines do
+ resources :ads, :name_prefix => nil
end
@@ -462,16 +467,16 @@ h5. Using +:has_one+ and +:has_many+
The +:has_one+ and +:has_many+ options provide a succinct notation for simple nested routes. Use +:has_one+ to nest a singleton resource, or +:has_many+ to nest a plural resource:
-map.resources :photos, :has_one => :photographer, :has_many => [:publications, :versions]
+resources :photos, :has_one => :photographer, :has_many => [:publications, :versions]
This has the same effect as this set of declarations:
-map.resources :photos do |photo|
- photo.resource :photographer
- photo.resources :publications
- photo.resources :versions
+resources :photos do
+ resource :photographer
+ resources :publications
+ resources :versions
end
@@ -480,9 +485,9 @@ h5. Limits to Nesting
You can nest resources within other nested resources if you like. For example:
-map.resources :publishers do |publisher|
- publisher.resources :magazines do |magazine|
- magazine.resources :photos
+resources :publishers do
+ resources :magazines do
+ resources :photos
end
end
@@ -502,9 +507,9 @@ h5. Shallow Nesting
The +:shallow+ option provides an elegant solution to the difficulties of deeply-nested routes. If you specify this option at any level of routing, then paths for nested resources which reference a specific member (that is, those with an +:id+ parameter) will not use the parent path prefix or name prefix. To see what this means, consider this set of routes:
-map.resources :publishers, :shallow => true do |publisher|
- publisher.resources :magazines do |magazine|
- magazine.resources :photos
+resources :publishers, :shallow => true do
+ resources :magazines do
+ resources :photos
end
end
@@ -522,7 +527,7 @@ This will enable recognition of (among others) these routes:
With shallow nesting, you need only supply enough information to uniquely identify the resource that you want to work with. If you like, you can combine shallow nesting with the +:has_one+ and +:has_many+ options:
-map.resources :publishers, :has_many => { :magazines => :photos }, :shallow => true
+resources :publishers, :has_many => { :magazines => :photos }, :shallow => true
h4. Route Generation from Arrays
@@ -530,8 +535,8 @@ h4. Route Generation from Arrays
In addition to using the generated routing helpers, Rails can also generate RESTful routes from an array of parameters. For example, suppose you have a set of routes generated with these entries in routes.rb:
-map.resources :magazines do |magazine|
- magazine.resources :ads
+resources :magazines do
+ resources :ads
end
@@ -554,17 +559,16 @@ h4. Namespaced Resources
It's possible to do some quite complex things by combining +:path_prefix+ and +:name_prefix+. For example, you can use the combination of these two options to move administrative resources to their own folder in your application:
-map.resources :photos, :path_prefix => 'admin', :controller => 'admin/photos'
-map.resources :tags, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_tags'
-map.resources :ratings, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_ratings'
+resources :photos, :path_prefix => 'admin', :controller => 'admin/photos'
+resources :tags, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_tags'
+resources :ratings, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_ratings'
The good news is that if you find yourself using this level of complexity, you can stop. Rails supports _namespaced resources_ to make placing resources in their own folder a snap. Here's the namespaced version of those same three routes:
-map.namespace(:admin) do |admin|
- admin.resources :photos,
- :has_many => { :tags, :ratings}
+namespace :admin do
+ resources :photos, :has_many => { :tags, :ratings }
end
@@ -576,18 +580,24 @@ You are not limited to the seven routes that RESTful routing creates by default.
h5. Adding Member Routes
-To add a member route, use the +:member+ option:
+To add a member route, just add +member+ block into resource block:
-map.resources :photos, :member => { :preview => :get }
+resources :photos do
+ member do
+ get :preview
+ end
+end
This will enable Rails to recognize URLs such as +/photos/1/preview+ using the GET HTTP verb, and route them to the preview action of the Photos controller. It will also create the +preview_photo_url+ and +preview_photo_path+ route helpers.
-Within the hash of member routes, each route name specifies the HTTP verb that it will recognize. You can use +:get+, +:put+, +:post+, +:delete+, or +:any+ here. You can also specify an array of methods, if you need more than one but you don't want to allow just anything:
+Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use +get+, +put+, +post+, +delete+, or +any+ here. If you don't have multiple +member+ route, you can also passing +:on+ to the routing.
-map.resources :photos, :member => { :prepare => [:get, :post] }
+resources :photos do
+ get :preview, :on => :member
+end
h5. Adding Collection Routes
@@ -595,32 +605,35 @@ h5. Adding Collection Routes
To add a collection route, use the +:collection+ option:
-map.resources :photos, :collection => { :search => :get }
+resources :photos do
+ collection do
+ get :search
+ end
+end
This will enable Rails to recognize URLs such as +/photos/search+ using the GET HTTP verb, and route them to the search action of the Photos controller. It will also create the +search_photos_url+ and +search_photos_path+ route helpers.
-Just as with member routes, you can specify an array of methods for a collection route:
+Just as with member routes, you can passing +:on+ to the routing.
-map.resources :photos, :collection => { :search => [:get, :post] }
+resources :photos do
+ get :search, :on => :collection
+end
h5. Adding New Routes
-To add a new route (one that creates a new resource), use the +:new+ option:
+As of writing, Rails 3 has deprecated +:new+ option from routing. You will need to explicit define the route using +match+ method
-map.resources :photos, :new => { :upload => :post }
+resources :photos
+match 'photos/new/upload' => 'photos#upload', :as => 'upload_new_photos'
-This will enable Rails to recognize URLs such as +/photos/new/upload+ using the POST HTTP verb, and route them to the upload action of the Photos controller. It will also create the +upload_new_photos_path+ and +upload_new_photos_url+ route helpers.
-
-TIP: If you want to redefine the verbs accepted by one of the standard actions, you can do so by explicitly mapping that action. For example: +map.resources :photos, :new => { :new => :any }+ This will allow the new action to be invoked by any request to +photos/new+, no matter what HTTP verb you use.
-
h5. A Note of Caution
-If you find yourself adding many extra actions to a RESTful route, it's time to stop and ask yourself whether you're disguising the presence of another resource that would be better split off on its own. When the +:member+ and +:collection+ hashes become a dumping-ground, RESTful routes lose the advantage of easy readability that is one of their strongest points.
+If you find yourself adding many extra actions to a RESTful route, it's time to stop and ask yourself whether you're disguising the presence of another resource that would be better split off on its own. When the +member+ and +collection+ hashes become a dumping-ground, RESTful routes lose the advantage of easy readability that is one of their strongest points.
h3. Regular Routes
@@ -633,7 +646,7 @@ h4. Bound Parameters
When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. Two of these symbols are special: +:controller+ maps to the name of a controller in your application, and +:action+ maps to the name of an action within that controller. For example, consider one of the default Rails routes:
-map.connect ':controller/:action/:id'
+match ':controller(/:action(/:id))'
If an incoming request of +/photos/show/1+ is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the +show+ action of the +Photos+ controller, and to make the final parameter (1) available as +params[:id]+.
@@ -643,7 +656,7 @@ h4. Wildcard Components
You can set up as many wildcard symbols within a regular route as you like. Anything other than +:controller+ or +:action+ will be available to the matching action as part of the params hash. So, if you set up this route:
-map.connect ':controller/:action/:id/:user_id'
+match ':controller/:action/:id/:user_id'
An incoming URL of +/photos/show/1/2+ will be dispatched to the +show+ action of the +Photos+ controller. +params[:id]+ will be set to 1, and +params[:user_id]+ will be set to 2.
@@ -653,7 +666,7 @@ h4. Static Text
You can specify static text when creating a route. In this case, the static text is used only for matching the incoming requests:
-map.connect ':controller/:action/:id/with_user/:user_id'
+match ':controller/:action/:id/with_user/:user_id'
This route would respond to URLs such as +/photos/show/1/with_user/2+.
@@ -663,17 +676,17 @@ h4. Querystring Parameters
Rails routing automatically picks up querystring parameters and makes them available in the +params+ hash. For example, with this route:
-map.connect ':controller/:action/:id'
+match ':controller/:action/:id
An incoming URL of +/photos/show/1?user_id=2+ will be dispatched to the +show+ action of the +Photos+ controller. +params[:id]+ will be set to 1, and +params[:user_id]+ will be equal to 2.
h4. Defining Defaults
-You do not need to explicitly use the +:controller+ and +:action+ symbols within a route. You can supply defaults for these two parameters in a hash:
+You do not need to explicitly use the +:controller+ and +:action+ symbols within a route. You can supply defaults for these two parameters by putting it after +=>+:
-map.connect 'photos/:id', :controller => 'photos', :action => 'show'
+match 'photos/:id' => 'photos#show'
With this route, an incoming URL of +/photos/12+ would be dispatched to the +show+ action within the +Photos+ controller.
@@ -681,8 +694,7 @@ With this route, an incoming URL of +/photos/12+ would be dispatched to the +sho
You can also define other defaults in a route by supplying a hash for the +:defaults+ option. This even applies to parameters that are not explicitly defined elsewhere in the route. For example:
-map.connect 'photos/:id', :controller => 'photos', :action => 'show',
- :defaults => { :format => 'jpg' }
+match 'photos/:id' => 'photos#show', :defaults => { :format => 'jpg' }
With this route, an incoming URL of +photos/12+ would be dispatched to the +show+ action within the +Photos+ controller, and +params[:format]+ will be set to +jpg+.
@@ -692,7 +704,7 @@ h4. Named Routes
Regular routes need not use the +connect+ method. You can use any other name here to create a _named route_. For example,
-map.logout '/logout', :controller => 'sessions', :action => 'destroy'
+match 'logout' => 'sessions#destroy', :as => :logout
This will do two things. First, requests to +/logout+ will be sent to the +destroy+ action of the +Sessions+ controller. Second, Rails will maintain the +logout_path+ and +logout_url+ helpers for use within your code.
@@ -702,15 +714,13 @@ h4. Route Requirements
You can use the +:requirements+ option to enforce a format for any parameter in a route:
-map.connect 'photo/:id', :controller => 'photos', :action => 'show',
- :requirements => { :id => /[A-Z]\d{5}/ }
+match 'photo/:id' => 'photos#show', :requirements => { :id => /[A-Z]\d{5}/ }
This route would respond to URLs such as +/photo/A12345+. You can more succinctly express the same route this way:
-map.connect 'photo/:id', :controller => 'photos', :action => 'show',
- :id => /[A-Z]\d{5}/
+match 'photo/:id' => 'photos#show', :id => /[A-Z]\d{5}/
h4. Route Conditions
@@ -718,8 +728,7 @@ h4. Route Conditions
Route conditions (introduced with the +:conditions+ option) are designed to implement restrictions on routes. Currently, the only supported restriction is +:method+:
-map.connect 'photo/:id', :controller => 'photos', :action => 'show',
- :conditions => { :method => :get }
+match 'photo/:id' => 'photos#show', :conditions => { :method => :get }
As with conditions in RESTful routes, you can specify +:get+, +:post+, +:put+, +:delete+, or +:any+ for the acceptable method.
@@ -729,7 +738,7 @@ h4. Route Globbing
Route globbing is a way to specify that a particular parameter should be matched to all the remaining parts of a route. For example
-map.connect 'photo/*other', :controller => 'photos', :action => 'unknown',
+match 'photo/*other' => 'photos#unknown'
This route would match +photo/12+ or +/photo/long/path/to/12+ equally well, creating an array of path segments as the value of +params[:other]+.
@@ -755,7 +764,7 @@ There's one more way in which routing can do different things depending on diffe
For instance, consider the second of the default routes in the boilerplate +routes.rb+ file:
-map.connect ':controller/:action/:id.:format'
+match ':controller(/:action(/:id(.:format)))'
This route matches requests such as +/photo/edit/1.xml+ or +/photo/show/2.rss+. Within the appropriate action code, you can issue different responses depending on the requested format:
@@ -781,11 +790,10 @@ Mime::Type.register "image/jpg", :jpg
h3. The Default Routes
-When you create a new Rails application, +routes.rb+ is initialized with two default routes:
+When you create a new Rails application, +routes.rb+ is initialized with a default route:
-map.connect ':controller/:action/:id'
-map.connect ':controller/:action/:id.:format'
+match ':controller(/:action(/:id(.:format)))'
These routes provide reasonable defaults for many URLs, if you're not using RESTful routing.
@@ -796,31 +804,24 @@ h3. The Empty Route
Don't confuse the default routes with the empty route. The empty route has one specific purpose: to route requests that come in to the root of the web site. For example, if your site is example.com, then requests to +http://example.com+ or +http://example.com/+ will be handled by the empty route.
-h4. Using +map.root+
+h4. Using +root+
-The preferred way to set up the empty route is with the +map.root+ command:
+The preferred way to set up the empty route is with the +root+ command:
-map.root :controller => "pages", :action => "main"
+root :to => 'pages#main'
The use of the +root+ method tells Rails that this route applies to requests for the root of the site.
-For better readability, you can specify an already-created route in your call to +map.root+:
-
-
-map.index 'index', :controller => "pages", :action => "main"
-map.root :index
-
-
-Because of the top-down processing of the file, the named route must be specified _before_ the call to +map.root+.
+Because of the top-down processing of the file, the named route must be specified _before_ the call to +root+.
h4. Connecting the Empty String
You can also specify an empty route by explicitly connecting the empty string:
-map.connect '', :controller => "pages", :action => "main"
+match '' => 'pages#main'
TIP: If the empty route does not seem to be working in your application, make sure that you have deleted the file +public/index.html+ from your Rails tree.
@@ -898,6 +899,7 @@ h3. Changelog
"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/3
+* Febuary 1, 2010: Modifies the routing documentation to match new routing DSL in Rails 3, by Prem Sichanugrist
* October 4, 2008: Added additional detail on specifying verbs for resource member/collection routes, by "Mike Gunderloy":credits.html#mgunderloy
* September 23, 2008: Added section on namespaced controllers and routing, by "Mike Gunderloy":credits.html#mgunderloy
* September 10, 2008: initial version by "Mike Gunderloy":credits.html#mgunderloy
diff --git a/railties/lib/generators/erb.rb b/railties/lib/generators/erb.rb
deleted file mode 100644
index d468d012dc..0000000000
--- a/railties/lib/generators/erb.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require 'rails/generators/named_base'
-
-module Erb
- module Generators
- class Base < Rails::Generators::NamedBase #:nodoc:
- end
- end
-end
diff --git a/railties/lib/generators/erb/mailer/mailer_generator.rb b/railties/lib/generators/erb/mailer/mailer_generator.rb
deleted file mode 100644
index 408c942cef..0000000000
--- a/railties/lib/generators/erb/mailer/mailer_generator.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require 'generators/erb'
-
-module Erb
- module Generators
- class MailerGenerator < Base
- argument :actions, :type => :array, :default => [], :banner => "method method"
-
- def create_view_folder
- empty_directory File.join("app/views", file_path)
- end
-
- def create_view_files
- actions.each do |action|
- @action, @path = action, File.join(file_path, action)
- template "view.text.erb", File.join("app/views", "#{@path}.text.erb")
- end
- end
- end
- end
-end
diff --git a/railties/lib/generators/test_unit/controller/templates/functional_test.rb b/railties/lib/generators/test_unit/controller/templates/functional_test.rb
deleted file mode 100644
index 62fa5d86fd..0000000000
--- a/railties/lib/generators/test_unit/controller/templates/functional_test.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require 'test_helper'
-
-class <%= class_name %>ControllerTest < ActionController::TestCase
- # Replace this with your real tests.
- test "the truth" do
- assert true
- end
-end
diff --git a/railties/lib/generators/test_unit/mailer/templates/fixture b/railties/lib/generators/test_unit/mailer/templates/fixture
deleted file mode 100644
index 171648d6fd..0000000000
--- a/railties/lib/generators/test_unit/mailer/templates/fixture
+++ /dev/null
@@ -1,3 +0,0 @@
-<%= class_name %>#<%= @action %>
-
-Hi, find me in app/views/<%= @path %>
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index 3d3151bd8f..9d02da104d 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -26,6 +26,9 @@
end
module Rails
+ autoload :Info, 'rails/info'
+ autoload :InfoController, 'rails/info_controller'
+
class << self
def application
@@application ||= nil
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index f43e8847ac..0084309ea4 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -1,9 +1,45 @@
require 'fileutils'
-require 'rails/railties_path'
require 'rails/plugin'
require 'rails/engine'
module Rails
+ # In Rails 3.0, a Rails::Application object was introduced which is nothing more than
+ # an Engine but with the responsibility of coordinating the whole boot process.
+ #
+ # Opposite to Rails::Engine, you can only have one Rails::Application instance
+ # in your process and both Rails::Application and YourApplication::Application
+ # points to it.
+ #
+ # In other words, Rails::Application is Singleton and whenever you are accessing
+ # Rails::Application.config or YourApplication::Application.config, you are actually
+ # accessing YourApplication::Application.instance.config.
+ #
+ # == Initialization
+ #
+ # Rails::Application is responsible for executing all railties, engines and plugin
+ # initializers. Besides, it also executed some bootstrap initializers (check
+ # Rails::Application::Bootstrap) and finishing initializers, after all the others
+ # are executed (check Rails::Application::Finisher).
+ #
+ # == Configuration
+ #
+ # Besides providing the same configuration as Rails::Engine and Rails::Railtie,
+ # the application object has several specific configurations, for example
+ # "allow_concurrency", "cache_classes", "consider_all_requests_local", "filter_parameters",
+ # "logger", "metals", "reload_engines", "reload_plugins" and so forth.
+ #
+ # Check Rails::Application::Configuration to see them all.
+ #
+ # == Routes
+ #
+ # The application object is also responsible for holding the routes and reloading routes
+ # whenever the files change in development.
+ #
+ # == Middlewares and metals
+ #
+ # The Application is also responsible for building the middleware stack and setting up
+ # both application and engines metals.
+ #
class Application < Engine
autoload :Bootstrap, 'rails/application/bootstrap'
autoload :Configurable, 'rails/application/configurable'
@@ -45,6 +81,8 @@ def method_missing(*args, &block)
end
end
+ delegate :metal_loader, :to => :config
+
def require_environment!
environment = config.paths.config.environment.to_a.first
require environment if environment
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index d3a0ecb243..44635ff4f6 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -6,7 +6,7 @@ class Configuration < ::Rails::Engine::Configuration
include ::Rails::Configuration::Deprecated
attr_accessor :allow_concurrency, :cache_classes, :cache_store,
- :consider_all_requests_local, :dependency_loading,
+ :cookie_secret, :consider_all_requests_local, :dependency_loading,
:filter_parameters, :log_level, :logger, :metals,
:plugins, :preload_frameworks, :reload_engines, :reload_plugins,
:serve_static_assets, :time_zone, :whiny_nils
@@ -19,10 +19,16 @@ def initialize(*)
@serve_static_assets = true
@time_zone = "UTC"
@consider_all_requests_local = true
+ @session_store = :cookie_store
+ @session_options = {}
end
def middleware
- @@default_middleware_stack ||= default_middleware
+ @middleware ||= default_middleware_stack
+ end
+
+ def metal_loader
+ @metal_loader ||= Rails::Application::MetalLoader.new
end
def paths
@@ -78,7 +84,7 @@ def cache_store
end
def builtin_controller
- File.join(RAILTIES_PATH, "builtin", "rails_info") if Rails.env.development?
+ File.expand_path('../info_routes', __FILE__) if Rails.env.development?
end
def log_level
@@ -94,6 +100,51 @@ def colorize_logging=(val)
Rails::LogSubscriber.colorize_logging = val
self.generators.colorize_logging = val
end
+
+ def session_store(*args)
+ if args.empty?
+ case @session_store
+ when :disabled
+ nil
+ when :active_record_store
+ ActiveRecord::SessionStore
+ when Symbol
+ ActionDispatch::Session.const_get(@session_store.to_s.camelize)
+ else
+ @session_store
+ end
+ else
+ @session_store = args.shift
+ @session_options = args.shift || {}
+ end
+ end
+
+ protected
+
+ def session_options
+ return @session_options unless @session_store == :cookie_store
+ @session_options.merge(:secret => @cookie_secret)
+ end
+
+ def default_middleware_stack
+ ActionDispatch::MiddlewareStack.new.tap do |middleware|
+ middleware.use('::ActionDispatch::Static', lambda { Rails.public_path }, :if => lambda { serve_static_assets })
+ middleware.use('::Rack::Lock', :if => lambda { !allow_concurrency })
+ middleware.use('::Rack::Runtime')
+ middleware.use('::Rails::Rack::Logger')
+ middleware.use('::ActionDispatch::ShowExceptions', lambda { consider_all_requests_local })
+ middleware.use("::ActionDispatch::RemoteIp", lambda { action_dispatch.ip_spoofing_check }, lambda { action_dispatch.trusted_proxies })
+ middleware.use('::Rack::Sendfile', lambda { action_dispatch.x_sendfile_header })
+ middleware.use('::ActionDispatch::Callbacks', lambda { !cache_classes })
+ middleware.use('::ActionDispatch::Cookies')
+ middleware.use(lambda { session_store }, lambda { session_options })
+ middleware.use('::ActionDispatch::Flash', :if => lambda { session_store })
+ middleware.use(lambda { metal_loader.build_middleware(metals) }, :if => lambda { metal_loader.metals.any? })
+ middleware.use('ActionDispatch::ParamsParser')
+ middleware.use('::Rack::MethodOverride')
+ middleware.use('::ActionDispatch::Head')
+ end
+ end
end
end
-end
\ No newline at end of file
+end
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index cb38d5a5db..978490f25f 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -23,7 +23,7 @@ module Finisher
initializer :add_builtin_route do |app|
if Rails.env.development?
- app.routes_reloader.paths << File.join(RAILTIES_PATH, 'builtin', 'routes.rb')
+ app.routes_reloader.paths << File.expand_path('../../info_routes.rb', __FILE__)
end
end
@@ -45,4 +45,4 @@ module Finisher
end
end
end
-end
\ No newline at end of file
+end
diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb
index 6972e25b29..12748da18b 100644
--- a/railties/lib/rails/commands.rb
+++ b/railties/lib/rails/commands.rb
@@ -30,7 +30,7 @@
require 'rails/commands/generate'
when 'c', 'console'
require 'rails/commands/console'
- require APP_PATH
+ require ENV_PATH
Rails::Console.start(Rails::Application)
when 's', 'server'
require 'rails/commands/server'
diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb
index fe2f89ee98..438c976b35 100644
--- a/railties/lib/rails/commands/application.rb
+++ b/railties/lib/rails/commands/application.rb
@@ -8,6 +8,6 @@
require 'rubygems' if ARGV.include?("--dev")
require 'rails/generators'
-require 'generators/rails/app/app_generator'
+require 'rails/generators/rails/app/app_generator'
Rails::Generators::AppGenerator.start
\ No newline at end of file
diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb
index 593e2d8ee3..68982b9f52 100644
--- a/railties/lib/rails/commands/dbconsole.rb
+++ b/railties/lib/rails/commands/dbconsole.rb
@@ -91,6 +91,18 @@ def find_cmd(*commands)
args << config['database']
exec(find_cmd('sqlite3'), *args)
+
+ when "oracle", "oracle_enhanced"
+ logon = ""
+
+ if config['username']
+ logon = config['username']
+ logon << "/#{config['password']}" if config['password'] && include_password
+ logon << "@#{config['database']}" if config['database']
+ end
+
+ exec(find_cmd('sqlplus'), logon)
+
else
abort "Unknown command-line client for #{config['database']}. Submit a Rails patch to add support!"
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 85b4ff8470..85cae75bce 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -3,6 +3,89 @@
require 'pathname'
module Rails
+ # Rails::Engine allows you to wrap a specific Rails application and share it accross
+ # different applications. Since Rails 3.0, every Rails::Application is nothing
+ # more than an Engine, allowing you to share it very easily.
+ #
+ # Any Rails::Engine is also a Rails::Railtie, so the same methods (like rake_tasks and
+ # generators) and configuration available in the latter can also be used in the former.
+ #
+ # == Creating an Engine
+ #
+ # In Rails versions before to 3.0, your gems automatically behaved as Engine, however
+ # this coupled Rails to Rubygems. Since Rails 3.0, if you want a gem to automatically
+ # behave as Engine, you have to specify an Engine for it somewhere inside your plugin
+ # lib folder (similar with how we spceify a Railtie):
+ #
+ # # lib/my_engine.rb
+ # module MyEngine
+ # class Engine < Rails::Engine
+ # engine_name :my_engine
+ # end
+ # end
+ #
+ # Then ensure that this file is loaded at the top of your config/application.rb (or in
+ # your Gemfile) and it will automatically load models, controllers, helpers and metals
+ # inside app, load routes at "config/routes.rb", load locales at "config/locales/*",
+ # load tasks at "lib/tasks/*".
+ #
+ # == Configuration
+ #
+ # Besides the Railtie configuration which is shared across the application, in a
+ # Rails::Engine you can access load_paths, eager_load_paths and load_once_paths,
+ # which differently from a Railtie, are scoped to the current Engine.
+ #
+ # Example:
+ #
+ # class MyEngine < Rails::Engine
+ # # config.middleware is shared configururation
+ # config.middleware.use MyEngine::Middleware
+ #
+ # # Add a load path for this specific Engine
+ # config.load_paths << File.expand_path("../lib/some/path", __FILE__)
+ # end
+ #
+ # == Paths
+ #
+ # Since Rails 3.0, both your Application and Engines do not have hardcoded paths.
+ # This means that you are not required to place your controllers at "app/controllers",
+ # but in any place which you find convenient.
+ #
+ # For example, let's suppose you want to lay your controllers at lib/controllers, all
+ # you need to do is:
+ #
+ # class MyEngine < Rails::Engine
+ # paths.app.controllers = "lib/controllers"
+ # end
+ #
+ # You can also have your controllers being loaded from both "app/controllers" and
+ # "lib/controllers":
+ #
+ # class MyEngine < Rails::Engine
+ # paths.app.controllers << "lib/controllers"
+ # end
+ #
+ # The available paths in an Engine are:
+ #
+ # class MyEngine < Rails::Engine
+ # paths.app = "app"
+ # paths.app.controllers = "app/controllers"
+ # paths.app.helpers = "app/helpers"
+ # paths.app.models = "app/models"
+ # paths.app.metals = "app/metal"
+ # paths.app.views = "app/views"
+ # paths.lib = "lib"
+ # paths.lib.tasks = "lib/tasks"
+ # paths.config = "config"
+ # paths.config.initializers = "config/initializers"
+ # paths.config.locales = "config/locales"
+ # paths.config.routes = "config/routes.rb"
+ # end
+ #
+ # Your Application class adds a couple more paths to this set. And as in your Application,
+ # all folders under "app" are automatically added to the load path. So if you have
+ # "app/observers", it's added by default.
+ #
class Engine < Railtie
autoload :Configurable, "rails/engine/configurable"
autoload :Configuration, "rails/engine/configuration"
@@ -10,11 +93,11 @@ class Engine < Railtie
class << self
attr_accessor :called_from
- alias :engine_name :railtie_name
- alias :engine_names :railtie_names
+ # TODO Remove this. It's deprecated.
+ alias :engine_name :railtie_name
def inherited(base)
- unless abstract_railtie?(base)
+ unless base.abstract_railtie?
base.called_from = begin
# Remove the line number from backtraces making sure we don't leave anything behind
call_stack = caller.map { |p| p.split(':')[0..-2].join(':') }
@@ -41,7 +124,7 @@ def find_root_with_flag(flag, default=nil)
end
end
- delegate :middleware, :paths, :metal_loader, :root, :to => :config
+ delegate :middleware, :paths, :root, :to => :config
def load_tasks
super
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 3c902ce0d4..57462707f4 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -202,6 +202,10 @@ def self.help(command = 'generate')
rails.delete("app")
print_list("rails", rails)
+ groups.delete("active_record") if options[:rails][:orm] == :active_record
+ groups.delete("test_unit") if options[:rails][:test_framework] == :test_unit
+ groups.delete("erb") if options[:rails][:template_engine] == :erb
+
groups.sort.each { |b, n| print_list(b, n) }
end
@@ -238,7 +242,7 @@ def self.lookup(namespaces) #:nodoc:
paths = namespaces_to_paths(namespaces)
paths.each do |raw_path|
- ["rails_generators", "generators"].each do |base|
+ ["rails/generators", "generators"].each do |base|
path = "#{base}/#{raw_path}_generator"
begin
@@ -261,7 +265,7 @@ def self.lookup! #:nodoc:
load_generators_from_railties!
$LOAD_PATH.each do |base|
- Dir[File.join(base, "{generators,rails_generators}", "**", "*_generator.rb")].each do |path|
+ Dir[File.join(base, "{rails/generators,generators}", "**", "*_generator.rb")].each do |path|
begin
require path
rescue Exception => e
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index 9624c35c0b..0da85ea4a4 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -1,4 +1,12 @@
-require 'thor/group'
+begin
+ require 'thor/group'
+rescue LoadError
+ puts "Thor is not available.\nIf you ran this command from a git checkout " \
+ "of Rails, please make sure thor is installed,\nand run this command " \
+ "as `ruby /path/to/rails myapp --dev`"
+ exit
+end
+
require 'rails/generators/actions'
module Rails
@@ -17,7 +25,7 @@ class Base < Thor::Group
def self.source_root
@_rails_source_root ||= begin
if base_name && generator_name
- File.expand_path(File.join("../../generators", base_name, generator_name, 'templates'), File.dirname(__FILE__))
+ File.expand_path(File.join(base_name, generator_name, 'templates'), File.dirname(__FILE__))
end
end
end
diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb
new file mode 100644
index 0000000000..3e6371268f
--- /dev/null
+++ b/railties/lib/rails/generators/erb.rb
@@ -0,0 +1,21 @@
+require 'rails/generators/named_base'
+
+module Erb
+ module Generators
+ class Base < Rails::Generators::NamedBase #:nodoc:
+ protected
+
+ def format
+ :html
+ end
+
+ def handler
+ :erb
+ end
+
+ def filename_with_extensions(name)
+ [name, format, handler].compact.join(".")
+ end
+ end
+ end
+end
diff --git a/railties/lib/generators/erb/controller/controller_generator.rb b/railties/lib/rails/generators/erb/controller/controller_generator.rb
similarity index 65%
rename from railties/lib/generators/erb/controller/controller_generator.rb
rename to railties/lib/rails/generators/erb/controller/controller_generator.rb
index ab7b273662..ac57140c23 100644
--- a/railties/lib/generators/erb/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/erb/controller/controller_generator.rb
@@ -1,19 +1,18 @@
-require 'generators/erb'
+require 'rails/generators/erb'
module Erb
module Generators
class ControllerGenerator < Base
argument :actions, :type => :array, :default => [], :banner => "action action"
- def create_view_files
+ def copy_view_files
base_path = File.join("app/views", class_path, file_name)
empty_directory base_path
actions.each do |action|
@action = action
- @path = File.join(base_path, "#{action}.html.erb")
-
- template 'view.html.erb', @path
+ @path = File.join(base_path, filename_with_extensions(action))
+ template filename_with_extensions(:view), @path
end
end
end
diff --git a/railties/lib/generators/erb/controller/templates/view.html.erb b/railties/lib/rails/generators/erb/controller/templates/view.html.erb
similarity index 100%
rename from railties/lib/generators/erb/controller/templates/view.html.erb
rename to railties/lib/rails/generators/erb/controller/templates/view.html.erb
diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
new file mode 100644
index 0000000000..943d0c9f8d
--- /dev/null
+++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
@@ -0,0 +1,13 @@
+require 'rails/generators/erb/controller/controller_generator'
+
+module Erb
+ module Generators
+ class MailerGenerator < ControllerGenerator
+ protected
+
+ def format
+ :text
+ end
+ end
+ end
+end
diff --git a/railties/lib/generators/erb/mailer/templates/view.text.erb b/railties/lib/rails/generators/erb/mailer/templates/view.text.erb
similarity index 100%
rename from railties/lib/generators/erb/mailer/templates/view.text.erb
rename to railties/lib/rails/generators/erb/mailer/templates/view.text.erb
diff --git a/railties/lib/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
similarity index 50%
rename from railties/lib/generators/erb/scaffold/scaffold_generator.rb
rename to railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
index 846540476f..f607e580a5 100644
--- a/railties/lib/generators/erb/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/erb'
+require 'rails/generators/erb'
require 'rails/generators/resource_helpers'
module Erb
@@ -15,39 +15,27 @@ def create_root_folder
empty_directory File.join("app/views", controller_file_path)
end
- def copy_index_file
- return if options[:singleton]
- copy_view :index
- end
+ def copy_view_files
+ views = available_views
+ views.delete("index") if options[:singleton]
- def copy_edit_file
- copy_view :edit
- end
-
- def copy_show_file
- copy_view :show
- end
-
- def copy_new_file
- copy_view :new
- end
-
- def copy_form_file
- copy_view :_form
+ views.each do |view|
+ filename = filename_with_extensions(view)
+ template filename, File.join("app/views", controller_file_path, filename)
+ end
end
def copy_layout_file
return unless options[:layout]
- template "layout.html.erb",
- File.join("app/views/layouts", controller_class_path, "#{controller_file_name}.html.erb")
+ template filename_with_extensions(:layout),
+ File.join("app/views/layouts", controller_class_path, filename_with_extensions(controller_file_name))
end
- protected
-
- def copy_view(view)
- template "#{view}.html.erb", File.join("app/views", controller_file_path, "#{view}.html.erb")
- end
+ protected
+ def available_views
+ %w(index edit show new _form)
+ end
end
end
end
diff --git a/railties/lib/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
similarity index 100%
rename from railties/lib/generators/erb/scaffold/templates/_form.html.erb
rename to railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
diff --git a/railties/lib/generators/erb/scaffold/templates/edit.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb
similarity index 100%
rename from railties/lib/generators/erb/scaffold/templates/edit.html.erb
rename to railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb
diff --git a/railties/lib/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb
similarity index 89%
rename from railties/lib/generators/erb/scaffold/templates/index.html.erb
rename to railties/lib/rails/generators/erb/scaffold/templates/index.html.erb
index b5c7fd1e58..d30d306d42 100644
--- a/railties/lib/generators/erb/scaffold/templates/index.html.erb
+++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb
@@ -24,4 +24,4 @@
-<%%= link_to 'New <%= singular_name %>', new_<%= singular_name %>_path %>
+<%%= link_to 'New <%= human_name %>', new_<%= singular_name %>_path %>
diff --git a/railties/lib/generators/erb/scaffold/templates/layout.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb
similarity index 100%
rename from railties/lib/generators/erb/scaffold/templates/layout.html.erb
rename to railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb
diff --git a/railties/lib/generators/erb/scaffold/templates/new.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb
similarity index 100%
rename from railties/lib/generators/erb/scaffold/templates/new.html.erb
rename to railties/lib/rails/generators/erb/scaffold/templates/new.html.erb
diff --git a/railties/lib/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb
similarity index 100%
rename from railties/lib/generators/erb/scaffold/templates/show.html.erb
rename to railties/lib/rails/generators/erb/scaffold/templates/show.html.erb
diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb
index 12e918731e..8d1dfbd947 100644
--- a/railties/lib/rails/generators/named_base.rb
+++ b/railties/lib/rails/generators/named_base.rb
@@ -27,6 +27,10 @@ def class_name
@class_name ||= (class_path + [file_name]).map!{ |m| m.camelize }.join('::')
end
+ def human_name
+ @human_name ||= singular_name.humanize
+ end
+
def plural_name
@plural_name ||= singular_name.pluralize
end
diff --git a/railties/lib/generators/rails/app/USAGE b/railties/lib/rails/generators/rails/app/USAGE
similarity index 100%
rename from railties/lib/generators/rails/app/USAGE
rename to railties/lib/rails/generators/rails/app/USAGE
diff --git a/railties/lib/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
similarity index 95%
rename from railties/lib/generators/rails/app/app_generator.rb
rename to railties/lib/rails/generators/rails/app/app_generator.rb
index 92e0d37436..fccae9190a 100644
--- a/railties/lib/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -5,7 +5,7 @@
module Rails::Generators
# We need to store the RAILS_DEV_PATH in a constant, otherwise the path
# can change in Ruby 1.8.7 when we FileUtils.cd.
- RAILS_DEV_PATH = File.expand_path("../../../../..", File.dirname(__FILE__))
+ RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__))
RESERVED_NAMES = %w[generate console server dbconsole
application destroy benchmarker profiler
@@ -178,7 +178,8 @@ def apply_rails_template
end
def bundle_if_dev_or_edge
- run "bundle install" if dev_or_edge?
+ bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
+ run "#{bundle_command} install" if dev_or_edge?
end
protected
@@ -220,6 +221,8 @@ def valid_app_const?
raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers."
elsif RESERVED_NAMES.include?(app_name)
raise Error, "Invalid application name #{app_name}. Please give a name which does not match one of the reserved rails words."
+ elsif Object.const_defined?(app_const_base)
+ raise Error, "Invalid application name #{app_name}, constant #{app_const_base} is already in use. Please choose another application name."
end
end
diff --git a/railties/lib/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
similarity index 100%
rename from railties/lib/generators/rails/app/templates/Gemfile
rename to railties/lib/rails/generators/rails/app/templates/Gemfile
diff --git a/railties/lib/generators/rails/app/templates/README b/railties/lib/rails/generators/rails/app/templates/README
similarity index 96%
rename from railties/lib/generators/rails/app/templates/README
rename to railties/lib/rails/generators/rails/app/templates/README
index b175146797..ded8570c42 100644
--- a/railties/lib/generators/rails/app/templates/README
+++ b/railties/lib/rails/generators/rails/app/templates/README
@@ -36,7 +36,8 @@ link:files/vendor/rails/actionpack/README.html.
== Web Servers
-By default, Rails will try to use Mongrel if it's are installed when started with rails server, otherwise Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails
+By default, Rails will try to use Mongrel if it's installed when started with rails server, otherwise
+Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails
with a variety of other web servers.
Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
@@ -207,7 +208,7 @@ app/views/layouts
app/helpers
Holds view helpers that should be named like weblogs_helper.rb. These are generated
- for you automatically when using rails generate for controllers. Helpers can be used to
+ for you automatically when using rails generate for controllers. Helpers can be used to
wrap functionality for your views into methods.
config
@@ -234,7 +235,7 @@ script
Helper scripts for automation and generation.
test
- Unit and functional tests along with fixtures. When using the rails generate scripts, template
+ Unit and functional tests along with fixtures. When using the rails generate command, template
test files will be generated for you and placed in this directory.
vendor
diff --git a/railties/lib/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile
similarity index 100%
rename from railties/lib/generators/rails/app/templates/Rakefile
rename to railties/lib/rails/generators/rails/app/templates/Rakefile
diff --git a/railties/lib/generators/rails/app/templates/app/controllers/application_controller.rb b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/app/controllers/application_controller.rb
rename to railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb
diff --git a/railties/lib/generators/rails/app/templates/app/helpers/application_helper.rb b/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/app/helpers/application_helper.rb
rename to railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb
diff --git a/railties/lib/generators/rails/app/templates/app/models/.empty_directory b/railties/lib/rails/generators/rails/app/templates/app/models/.empty_directory
similarity index 100%
rename from railties/lib/generators/rails/app/templates/app/models/.empty_directory
rename to railties/lib/rails/generators/rails/app/templates/app/models/.empty_directory
diff --git a/railties/lib/generators/rails/app/templates/app/views/layouts/.empty_directory b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory
similarity index 100%
rename from railties/lib/generators/rails/app/templates/app/views/layouts/.empty_directory
rename to railties/lib/rails/generators/rails/app/templates/app/views/layouts/.empty_directory
diff --git a/railties/lib/generators/rails/app/templates/config.ru b/railties/lib/rails/generators/rails/app/templates/config.ru
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config.ru
rename to railties/lib/rails/generators/rails/app/templates/config.ru
diff --git a/railties/lib/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/application.rb
rename to railties/lib/rails/generators/rails/app/templates/config/application.rb
diff --git a/railties/lib/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/boot.rb
rename to railties/lib/rails/generators/rails/app/templates/config/boot.rb
diff --git a/railties/lib/generators/rails/app/templates/config/databases/frontbase.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/databases/frontbase.yml
rename to railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml
diff --git a/railties/lib/generators/rails/app/templates/config/databases/ibm_db.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/databases/ibm_db.yml
rename to railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml
diff --git a/railties/lib/generators/rails/app/templates/config/databases/mysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/databases/mysql.yml
rename to railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
diff --git a/railties/lib/generators/rails/app/templates/config/databases/oracle.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/databases/oracle.yml
rename to railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml
diff --git a/railties/lib/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/databases/postgresql.yml
rename to railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
diff --git a/railties/lib/generators/rails/app/templates/config/databases/sqlite3.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/databases/sqlite3.yml
rename to railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml
diff --git a/railties/lib/generators/rails/app/templates/config/environment.rb b/railties/lib/rails/generators/rails/app/templates/config/environment.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/environment.rb
rename to railties/lib/rails/generators/rails/app/templates/config/environment.rb
diff --git a/railties/lib/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/environments/development.rb.tt
rename to railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
diff --git a/railties/lib/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
similarity index 76%
rename from railties/lib/generators/rails/app/templates/config/environments/production.rb.tt
rename to railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 917052c3df..f902120453 100644
--- a/railties/lib/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -9,6 +9,15 @@
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
+ # Specifies the header that your server uses for sending files
+ config.action_dispatch.x_sendfile_header = "X-Sendfile"
+
+ # For nginx:
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
+
+ # If you have no front-end server that supports something like X-Sendfile,
+ # just comment this out and Rails will serve the files
+
# See everything in the log (default is :info)
# config.log_level = :debug
diff --git a/railties/lib/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/environments/test.rb.tt
rename to railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
diff --git a/railties/lib/generators/rails/app/templates/config/initializers/backtrace_silencers.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/initializers/backtrace_silencers.rb
rename to railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb
diff --git a/railties/lib/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt
rename to railties/lib/rails/generators/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt
diff --git a/railties/lib/generators/rails/app/templates/config/initializers/inflections.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/initializers/inflections.rb
rename to railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb
diff --git a/railties/lib/generators/rails/app/templates/config/initializers/mime_types.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/initializers/mime_types.rb
rename to railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb
diff --git a/railties/lib/generators/rails/app/templates/config/initializers/session_store.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/initializers/session_store.rb.tt
rename to railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt
diff --git a/railties/lib/generators/rails/app/templates/config/locales/en.yml b/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/locales/en.yml
rename to railties/lib/rails/generators/rails/app/templates/config/locales/en.yml
diff --git a/railties/lib/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/config/routes.rb
rename to railties/lib/rails/generators/rails/app/templates/config/routes.rb
diff --git a/railties/lib/generators/rails/app/templates/db/seeds.rb b/railties/lib/rails/generators/rails/app/templates/db/seeds.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/db/seeds.rb
rename to railties/lib/rails/generators/rails/app/templates/db/seeds.rb
diff --git a/railties/lib/generators/rails/app/templates/doc/README_FOR_APP b/railties/lib/rails/generators/rails/app/templates/doc/README_FOR_APP
similarity index 100%
rename from railties/lib/generators/rails/app/templates/doc/README_FOR_APP
rename to railties/lib/rails/generators/rails/app/templates/doc/README_FOR_APP
diff --git a/railties/lib/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore
similarity index 100%
rename from railties/lib/generators/rails/app/templates/gitignore
rename to railties/lib/rails/generators/rails/app/templates/gitignore
diff --git a/railties/lib/generators/rails/app/templates/public/404.html b/railties/lib/rails/generators/rails/app/templates/public/404.html
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/404.html
rename to railties/lib/rails/generators/rails/app/templates/public/404.html
diff --git a/railties/lib/generators/rails/app/templates/public/422.html b/railties/lib/rails/generators/rails/app/templates/public/422.html
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/422.html
rename to railties/lib/rails/generators/rails/app/templates/public/422.html
diff --git a/railties/lib/generators/rails/app/templates/public/500.html b/railties/lib/rails/generators/rails/app/templates/public/500.html
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/500.html
rename to railties/lib/rails/generators/rails/app/templates/public/500.html
diff --git a/railties/lib/generators/rails/app/templates/public/favicon.ico b/railties/lib/rails/generators/rails/app/templates/public/favicon.ico
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/favicon.ico
rename to railties/lib/rails/generators/rails/app/templates/public/favicon.ico
diff --git a/railties/lib/generators/rails/app/templates/public/images/rails.png b/railties/lib/rails/generators/rails/app/templates/public/images/rails.png
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/images/rails.png
rename to railties/lib/rails/generators/rails/app/templates/public/images/rails.png
diff --git a/railties/lib/generators/rails/app/templates/public/index.html b/railties/lib/rails/generators/rails/app/templates/public/index.html
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/index.html
rename to railties/lib/rails/generators/rails/app/templates/public/index.html
diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/application.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/application.js
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/javascripts/application.js
rename to railties/lib/rails/generators/rails/app/templates/public/javascripts/application.js
diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/controls.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/controls.js
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/javascripts/controls.js
rename to railties/lib/rails/generators/rails/app/templates/public/javascripts/controls.js
diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/dragdrop.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/dragdrop.js
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/javascripts/dragdrop.js
rename to railties/lib/rails/generators/rails/app/templates/public/javascripts/dragdrop.js
diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/effects.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/effects.js
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/javascripts/effects.js
rename to railties/lib/rails/generators/rails/app/templates/public/javascripts/effects.js
diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/prototype.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/javascripts/prototype.js
rename to railties/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js
diff --git a/railties/lib/generators/rails/app/templates/public/javascripts/rails.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js
similarity index 96%
rename from railties/lib/generators/rails/app/templates/public/javascripts/rails.js
rename to railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js
index f7ddba390a..7342e1b830 100644
--- a/railties/lib/generators/rails/app/templates/public/javascripts/rails.js
+++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/rails.js
@@ -15,8 +15,7 @@ document.observe("dom:loaded", function() {
params = element.serialize(true);
} else {
method = element.readAttribute('data-method') || 'get';
- // TODO: data-url support is going away, just use href
- url = element.readAttribute('data-url') || element.readAttribute('href');
+ url = element.readAttribute('href');
params = {};
}
diff --git a/railties/lib/generators/rails/app/templates/public/robots.txt b/railties/lib/rails/generators/rails/app/templates/public/robots.txt
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/robots.txt
rename to railties/lib/rails/generators/rails/app/templates/public/robots.txt
diff --git a/railties/lib/generators/rails/app/templates/public/stylesheets/.empty_directory b/railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory
similarity index 100%
rename from railties/lib/generators/rails/app/templates/public/stylesheets/.empty_directory
rename to railties/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory
diff --git a/railties/lib/generators/rails/app/templates/script/rails b/railties/lib/rails/generators/rails/app/templates/script/rails
similarity index 100%
rename from railties/lib/generators/rails/app/templates/script/rails
rename to railties/lib/rails/generators/rails/app/templates/script/rails
diff --git a/railties/lib/generators/rails/app/templates/test/fixtures/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory
similarity index 100%
rename from railties/lib/generators/rails/app/templates/test/fixtures/.empty_directory
rename to railties/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory
diff --git a/railties/lib/generators/rails/app/templates/test/functional/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/functional/.empty_directory
similarity index 100%
rename from railties/lib/generators/rails/app/templates/test/functional/.empty_directory
rename to railties/lib/rails/generators/rails/app/templates/test/functional/.empty_directory
diff --git a/railties/lib/generators/rails/app/templates/test/integration/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/integration/.empty_directory
similarity index 100%
rename from railties/lib/generators/rails/app/templates/test/integration/.empty_directory
rename to railties/lib/rails/generators/rails/app/templates/test/integration/.empty_directory
diff --git a/railties/lib/generators/rails/app/templates/test/performance/browsing_test.rb b/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/test/performance/browsing_test.rb
rename to railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb
diff --git a/railties/lib/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb
similarity index 100%
rename from railties/lib/generators/rails/app/templates/test/test_helper.rb
rename to railties/lib/rails/generators/rails/app/templates/test/test_helper.rb
diff --git a/railties/lib/generators/rails/app/templates/test/unit/.empty_directory b/railties/lib/rails/generators/rails/app/templates/test/unit/.empty_directory
similarity index 100%
rename from railties/lib/generators/rails/app/templates/test/unit/.empty_directory
rename to railties/lib/rails/generators/rails/app/templates/test/unit/.empty_directory
diff --git a/railties/lib/generators/rails/controller/USAGE b/railties/lib/rails/generators/rails/controller/USAGE
similarity index 100%
rename from railties/lib/generators/rails/controller/USAGE
rename to railties/lib/rails/generators/rails/controller/USAGE
diff --git a/railties/lib/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb
similarity index 76%
rename from railties/lib/generators/rails/controller/controller_generator.rb
rename to railties/lib/rails/generators/rails/controller/controller_generator.rb
index 91470be833..9788c0d0bc 100644
--- a/railties/lib/generators/rails/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb
@@ -8,6 +8,12 @@ def create_controller_files
template 'controller.rb', File.join('app/controllers', class_path, "#{file_name}_controller.rb")
end
+ def add_routes
+ actions.reverse.each do |action|
+ route %{get "#{file_name}/#{action}"}
+ end
+ end
+
hook_for :template_engine, :test_framework, :helper
end
end
diff --git a/railties/lib/generators/rails/controller/templates/controller.rb b/railties/lib/rails/generators/rails/controller/templates/controller.rb
similarity index 100%
rename from railties/lib/generators/rails/controller/templates/controller.rb
rename to railties/lib/rails/generators/rails/controller/templates/controller.rb
diff --git a/railties/lib/generators/rails/generator/USAGE b/railties/lib/rails/generators/rails/generator/USAGE
similarity index 100%
rename from railties/lib/generators/rails/generator/USAGE
rename to railties/lib/rails/generators/rails/generator/USAGE
diff --git a/railties/lib/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/generator/generator_generator.rb
rename to railties/lib/rails/generators/rails/generator/generator_generator.rb
diff --git a/railties/lib/generators/rails/generator/templates/%file_name%_generator.rb.tt b/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt
similarity index 100%
rename from railties/lib/generators/rails/generator/templates/%file_name%_generator.rb.tt
rename to railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt
diff --git a/railties/lib/generators/rails/generator/templates/USAGE.tt b/railties/lib/rails/generators/rails/generator/templates/USAGE.tt
similarity index 100%
rename from railties/lib/generators/rails/generator/templates/USAGE.tt
rename to railties/lib/rails/generators/rails/generator/templates/USAGE.tt
diff --git a/railties/lib/generators/rails/generator/templates/templates/.empty_directory b/railties/lib/rails/generators/rails/generator/templates/templates/.empty_directory
similarity index 100%
rename from railties/lib/generators/rails/generator/templates/templates/.empty_directory
rename to railties/lib/rails/generators/rails/generator/templates/templates/.empty_directory
diff --git a/railties/lib/generators/rails/helper/USAGE b/railties/lib/rails/generators/rails/helper/USAGE
similarity index 100%
rename from railties/lib/generators/rails/helper/USAGE
rename to railties/lib/rails/generators/rails/helper/USAGE
diff --git a/railties/lib/generators/rails/helper/helper_generator.rb b/railties/lib/rails/generators/rails/helper/helper_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/helper/helper_generator.rb
rename to railties/lib/rails/generators/rails/helper/helper_generator.rb
diff --git a/railties/lib/generators/rails/helper/templates/helper.rb b/railties/lib/rails/generators/rails/helper/templates/helper.rb
similarity index 100%
rename from railties/lib/generators/rails/helper/templates/helper.rb
rename to railties/lib/rails/generators/rails/helper/templates/helper.rb
diff --git a/railties/lib/generators/rails/integration_test/USAGE b/railties/lib/rails/generators/rails/integration_test/USAGE
similarity index 100%
rename from railties/lib/generators/rails/integration_test/USAGE
rename to railties/lib/rails/generators/rails/integration_test/USAGE
diff --git a/railties/lib/generators/rails/integration_test/integration_test_generator.rb b/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/integration_test/integration_test_generator.rb
rename to railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb
diff --git a/railties/lib/generators/rails/mailer/USAGE b/railties/lib/rails/generators/rails/mailer/USAGE
similarity index 100%
rename from railties/lib/generators/rails/mailer/USAGE
rename to railties/lib/rails/generators/rails/mailer/USAGE
diff --git a/railties/lib/generators/rails/mailer/mailer_generator.rb b/railties/lib/rails/generators/rails/mailer/mailer_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/mailer/mailer_generator.rb
rename to railties/lib/rails/generators/rails/mailer/mailer_generator.rb
diff --git a/railties/lib/generators/rails/mailer/templates/mailer.rb b/railties/lib/rails/generators/rails/mailer/templates/mailer.rb
similarity index 100%
rename from railties/lib/generators/rails/mailer/templates/mailer.rb
rename to railties/lib/rails/generators/rails/mailer/templates/mailer.rb
diff --git a/railties/lib/generators/rails/metal/USAGE b/railties/lib/rails/generators/rails/metal/USAGE
similarity index 100%
rename from railties/lib/generators/rails/metal/USAGE
rename to railties/lib/rails/generators/rails/metal/USAGE
diff --git a/railties/lib/generators/rails/metal/metal_generator.rb b/railties/lib/rails/generators/rails/metal/metal_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/metal/metal_generator.rb
rename to railties/lib/rails/generators/rails/metal/metal_generator.rb
diff --git a/railties/lib/generators/rails/metal/templates/metal.rb b/railties/lib/rails/generators/rails/metal/templates/metal.rb
similarity index 100%
rename from railties/lib/generators/rails/metal/templates/metal.rb
rename to railties/lib/rails/generators/rails/metal/templates/metal.rb
diff --git a/railties/lib/generators/rails/migration/USAGE b/railties/lib/rails/generators/rails/migration/USAGE
similarity index 100%
rename from railties/lib/generators/rails/migration/USAGE
rename to railties/lib/rails/generators/rails/migration/USAGE
diff --git a/railties/lib/generators/rails/migration/migration_generator.rb b/railties/lib/rails/generators/rails/migration/migration_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/migration/migration_generator.rb
rename to railties/lib/rails/generators/rails/migration/migration_generator.rb
diff --git a/railties/lib/generators/rails/model/USAGE b/railties/lib/rails/generators/rails/model/USAGE
similarity index 100%
rename from railties/lib/generators/rails/model/USAGE
rename to railties/lib/rails/generators/rails/model/USAGE
diff --git a/railties/lib/generators/rails/model/model_generator.rb b/railties/lib/rails/generators/rails/model/model_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/model/model_generator.rb
rename to railties/lib/rails/generators/rails/model/model_generator.rb
diff --git a/railties/lib/generators/rails/model_subclass/model_subclass_generator.rb b/railties/lib/rails/generators/rails/model_subclass/model_subclass_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/model_subclass/model_subclass_generator.rb
rename to railties/lib/rails/generators/rails/model_subclass/model_subclass_generator.rb
diff --git a/railties/lib/generators/rails/observer/USAGE b/railties/lib/rails/generators/rails/observer/USAGE
similarity index 100%
rename from railties/lib/generators/rails/observer/USAGE
rename to railties/lib/rails/generators/rails/observer/USAGE
diff --git a/railties/lib/generators/rails/observer/observer_generator.rb b/railties/lib/rails/generators/rails/observer/observer_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/observer/observer_generator.rb
rename to railties/lib/rails/generators/rails/observer/observer_generator.rb
diff --git a/railties/lib/generators/rails/performance_test/USAGE b/railties/lib/rails/generators/rails/performance_test/USAGE
similarity index 100%
rename from railties/lib/generators/rails/performance_test/USAGE
rename to railties/lib/rails/generators/rails/performance_test/USAGE
diff --git a/railties/lib/generators/rails/performance_test/performance_test_generator.rb b/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/performance_test/performance_test_generator.rb
rename to railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb
diff --git a/railties/lib/generators/rails/plugin/USAGE b/railties/lib/rails/generators/rails/plugin/USAGE
similarity index 100%
rename from railties/lib/generators/rails/plugin/USAGE
rename to railties/lib/rails/generators/rails/plugin/USAGE
diff --git a/railties/lib/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
similarity index 94%
rename from railties/lib/generators/rails/plugin/plugin_generator.rb
rename to railties/lib/rails/generators/rails/plugin/plugin_generator.rb
index 8f01dcd589..40ed2062d3 100644
--- a/railties/lib/generators/rails/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/rails/generator/generator_generator'
+require 'rails/generators/rails/generator/generator_generator'
module Rails
module Generators
diff --git a/railties/lib/generators/rails/plugin/templates/MIT-LICENSE.tt b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt
similarity index 100%
rename from railties/lib/generators/rails/plugin/templates/MIT-LICENSE.tt
rename to railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt
diff --git a/railties/lib/generators/rails/plugin/templates/README.tt b/railties/lib/rails/generators/rails/plugin/templates/README.tt
similarity index 100%
rename from railties/lib/generators/rails/plugin/templates/README.tt
rename to railties/lib/rails/generators/rails/plugin/templates/README.tt
diff --git a/railties/lib/generators/rails/plugin/templates/Rakefile.tt b/railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt
similarity index 100%
rename from railties/lib/generators/rails/plugin/templates/Rakefile.tt
rename to railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt
diff --git a/railties/lib/generators/rails/plugin/templates/init.rb b/railties/lib/rails/generators/rails/plugin/templates/init.rb
similarity index 100%
rename from railties/lib/generators/rails/plugin/templates/init.rb
rename to railties/lib/rails/generators/rails/plugin/templates/init.rb
diff --git a/railties/lib/generators/rails/plugin/templates/install.rb b/railties/lib/rails/generators/rails/plugin/templates/install.rb
similarity index 100%
rename from railties/lib/generators/rails/plugin/templates/install.rb
rename to railties/lib/rails/generators/rails/plugin/templates/install.rb
diff --git a/railties/lib/generators/rails/plugin/templates/lib/%file_name%.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/lib/%file_name%.rb.tt
similarity index 100%
rename from railties/lib/generators/rails/plugin/templates/lib/%file_name%.rb.tt
rename to railties/lib/rails/generators/rails/plugin/templates/lib/%file_name%.rb.tt
diff --git a/railties/lib/generators/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt
similarity index 100%
rename from railties/lib/generators/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt
rename to railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt
diff --git a/railties/lib/generators/rails/plugin/templates/uninstall.rb b/railties/lib/rails/generators/rails/plugin/templates/uninstall.rb
similarity index 100%
rename from railties/lib/generators/rails/plugin/templates/uninstall.rb
rename to railties/lib/rails/generators/rails/plugin/templates/uninstall.rb
diff --git a/railties/lib/generators/rails/resource/USAGE b/railties/lib/rails/generators/rails/resource/USAGE
similarity index 100%
rename from railties/lib/generators/rails/resource/USAGE
rename to railties/lib/rails/generators/rails/resource/USAGE
diff --git a/railties/lib/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb
similarity index 89%
rename from railties/lib/generators/rails/resource/resource_generator.rb
rename to railties/lib/rails/generators/rails/resource/resource_generator.rb
index 5acb839f39..1e78945a7e 100644
--- a/railties/lib/generators/rails/resource/resource_generator.rb
+++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb
@@ -1,5 +1,5 @@
require 'rails/generators/resource_helpers'
-require 'generators/rails/model/model_generator'
+require 'rails/generators/rails/model/model_generator'
module Rails
module Generators
@@ -16,6 +16,7 @@ class ResourceGenerator < ModelGenerator #metagenerator
class_option :singleton, :type => :boolean, :desc => "Supply to create a singleton controller"
def add_resource_route
+ return if options[:actions].present?
route "resource#{:s unless options[:singleton]} :#{pluralize?(file_name)}"
end
diff --git a/railties/lib/generators/rails/scaffold/USAGE b/railties/lib/rails/generators/rails/scaffold/USAGE
similarity index 100%
rename from railties/lib/generators/rails/scaffold/USAGE
rename to railties/lib/rails/generators/rails/scaffold/USAGE
diff --git a/railties/lib/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
similarity index 81%
rename from railties/lib/generators/rails/scaffold/scaffold_generator.rb
rename to railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
index fdea5bf52b..779f933785 100644
--- a/railties/lib/generators/rails/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/rails/resource/resource_generator'
+require 'rails/generators/rails/resource/resource_generator'
module Rails
module Generators
diff --git a/railties/lib/generators/rails/scaffold_controller/USAGE b/railties/lib/rails/generators/rails/scaffold_controller/USAGE
similarity index 100%
rename from railties/lib/generators/rails/scaffold_controller/USAGE
rename to railties/lib/rails/generators/rails/scaffold_controller/USAGE
diff --git a/railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/scaffold_controller/scaffold_controller_generator.rb
rename to railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
diff --git a/railties/lib/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
similarity index 96%
rename from railties/lib/generators/rails/scaffold_controller/templates/controller.rb
rename to railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
index 874e96a2b4..bbdce669dc 100644
--- a/railties/lib/generators/rails/scaffold_controller/templates/controller.rb
+++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
@@ -46,7 +46,7 @@ def create
respond_to do |format|
if @<%= orm_instance.save %>
- format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully created.') }
+ format.html { redirect_to(@<%= file_name %>, :notice => '<%= human_name %> was successfully created.') }
format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> }
else
format.html { render :action => "new" }
@@ -62,7 +62,7 @@ def update
respond_to do |format|
if @<%= orm_instance.update_attributes("params[:#{file_name}]") %>
- format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully updated.') }
+ format.html { redirect_to(@<%= file_name %>, :notice => '<%= human_name %> was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
diff --git a/railties/lib/generators/rails/session_migration/USAGE b/railties/lib/rails/generators/rails/session_migration/USAGE
similarity index 100%
rename from railties/lib/generators/rails/session_migration/USAGE
rename to railties/lib/rails/generators/rails/session_migration/USAGE
diff --git a/railties/lib/generators/rails/session_migration/session_migration_generator.rb b/railties/lib/rails/generators/rails/session_migration/session_migration_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/session_migration/session_migration_generator.rb
rename to railties/lib/rails/generators/rails/session_migration/session_migration_generator.rb
diff --git a/railties/lib/generators/rails/stylesheets/USAGE b/railties/lib/rails/generators/rails/stylesheets/USAGE
similarity index 100%
rename from railties/lib/generators/rails/stylesheets/USAGE
rename to railties/lib/rails/generators/rails/stylesheets/USAGE
diff --git a/railties/lib/generators/rails/stylesheets/stylesheets_generator.rb b/railties/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb
similarity index 100%
rename from railties/lib/generators/rails/stylesheets/stylesheets_generator.rb
rename to railties/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb
diff --git a/railties/lib/generators/rails/stylesheets/templates/scaffold.css b/railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css
similarity index 100%
rename from railties/lib/generators/rails/stylesheets/templates/scaffold.css
rename to railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css
diff --git a/railties/lib/generators/test_unit.rb b/railties/lib/rails/generators/test_unit.rb
similarity index 100%
rename from railties/lib/generators/test_unit.rb
rename to railties/lib/rails/generators/test_unit.rb
diff --git a/railties/lib/generators/test_unit/controller/controller_generator.rb b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb
similarity index 72%
rename from railties/lib/generators/test_unit/controller/controller_generator.rb
rename to railties/lib/rails/generators/test_unit/controller/controller_generator.rb
index b57a6e794f..20f3bd8965 100644
--- a/railties/lib/generators/test_unit/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb
@@ -1,8 +1,9 @@
-require 'generators/test_unit'
+require 'rails/generators/test_unit'
module TestUnit
module Generators
class ControllerGenerator < Base
+ argument :actions, :type => :array, :default => [], :banner => "action action"
check_class_collision :suffix => "ControllerTest"
def create_test_files
diff --git a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb
new file mode 100644
index 0000000000..0d4185846d
--- /dev/null
+++ b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb
@@ -0,0 +1,18 @@
+require 'test_helper'
+
+class <%= class_name %>ControllerTest < ActionController::TestCase
+<% if actions.empty? -%>
+ # Replace this with your real tests.
+ test "the truth" do
+ assert true
+ end
+<% else -%>
+<% for action in actions -%>
+ test "should get <%= action %>" do
+ get :<%= action %>
+ assert_response :success
+ end
+
+<% end -%>
+<% end -%>
+end
diff --git a/railties/lib/generators/test_unit/helper/helper_generator.rb b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb
similarity index 88%
rename from railties/lib/generators/test_unit/helper/helper_generator.rb
rename to railties/lib/rails/generators/test_unit/helper/helper_generator.rb
index 9ecfaa45ab..4ea80bf7be 100644
--- a/railties/lib/generators/test_unit/helper/helper_generator.rb
+++ b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/test_unit'
+require 'rails/generators/test_unit'
module TestUnit
module Generators
diff --git a/railties/lib/generators/test_unit/helper/templates/helper_test.rb b/railties/lib/rails/generators/test_unit/helper/templates/helper_test.rb
similarity index 100%
rename from railties/lib/generators/test_unit/helper/templates/helper_test.rb
rename to railties/lib/rails/generators/test_unit/helper/templates/helper_test.rb
diff --git a/railties/lib/generators/test_unit/integration/integration_generator.rb b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb
similarity index 88%
rename from railties/lib/generators/test_unit/integration/integration_generator.rb
rename to railties/lib/rails/generators/test_unit/integration/integration_generator.rb
index d9d9b3bf1d..32d0fac029 100644
--- a/railties/lib/generators/test_unit/integration/integration_generator.rb
+++ b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/test_unit'
+require 'rails/generators/test_unit'
module TestUnit
module Generators
diff --git a/railties/lib/generators/test_unit/integration/templates/integration_test.rb b/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb
similarity index 100%
rename from railties/lib/generators/test_unit/integration/templates/integration_test.rb
rename to railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb
diff --git a/railties/lib/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
similarity index 59%
rename from railties/lib/generators/test_unit/mailer/mailer_generator.rb
rename to railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
index a0d73db1b0..1a49286d41 100644
--- a/railties/lib/generators/test_unit/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/test_unit'
+require 'rails/generators/test_unit'
module TestUnit
module Generators
@@ -9,13 +9,6 @@ class MailerGenerator < Base
def create_test_files
template "functional_test.rb", File.join('test/functional', class_path, "#{file_name}_test.rb")
end
-
- def create_fixtures_files
- actions.each do |action|
- @action, @path = action, File.join(file_path, action)
- template "fixture", File.join("test/fixtures", @path)
- end
- end
end
end
end
diff --git a/railties/lib/generators/test_unit/mailer/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
similarity index 51%
rename from railties/lib/generators/test_unit/mailer/templates/functional_test.rb
rename to railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
index a2b1f1ed05..80ac7f0feb 100644
--- a/railties/lib/generators/test_unit/mailer/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
@@ -3,12 +3,11 @@
class <%= class_name %>Test < ActionMailer::TestCase
<% for action in actions -%>
test "<%= action %>" do
- @expected.subject = <%= action.to_s.humanize.inspect %>
- @expected.to = "to@example.org"
- @expected.from = "from@example.com"
- @expected.body = read_fixture("<%= action %>")
-
- assert_equal @expected, <%= class_name %>.<%= action %>
+ mail = <%= class_name %>.<%= action %>
+ assert_equal <%= action.to_s.humanize.inspect %>, mail.subject
+ assert_equal ["to@example.org"], mail.to
+ assert_equal ["from@example.com"], mail.from
+ assert_match "Hi", mail.body.encoded
end
<% end -%>
diff --git a/railties/lib/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb
similarity index 94%
rename from railties/lib/generators/test_unit/model/model_generator.rb
rename to railties/lib/rails/generators/test_unit/model/model_generator.rb
index 469306e6c5..609b815683 100644
--- a/railties/lib/generators/test_unit/model/model_generator.rb
+++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/test_unit'
+require 'rails/generators/test_unit'
module TestUnit
module Generators
diff --git a/railties/lib/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
similarity index 100%
rename from railties/lib/generators/test_unit/model/templates/fixtures.yml
rename to railties/lib/rails/generators/test_unit/model/templates/fixtures.yml
diff --git a/railties/lib/generators/test_unit/model/templates/unit_test.rb b/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb
similarity index 100%
rename from railties/lib/generators/test_unit/model/templates/unit_test.rb
rename to railties/lib/rails/generators/test_unit/model/templates/unit_test.rb
diff --git a/railties/lib/generators/test_unit/observer/observer_generator.rb b/railties/lib/rails/generators/test_unit/observer/observer_generator.rb
similarity index 88%
rename from railties/lib/generators/test_unit/observer/observer_generator.rb
rename to railties/lib/rails/generators/test_unit/observer/observer_generator.rb
index 14181f4e49..6cc1158c21 100644
--- a/railties/lib/generators/test_unit/observer/observer_generator.rb
+++ b/railties/lib/rails/generators/test_unit/observer/observer_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/test_unit'
+require 'rails/generators/test_unit'
module TestUnit
module Generators
diff --git a/railties/lib/generators/test_unit/observer/templates/unit_test.rb b/railties/lib/rails/generators/test_unit/observer/templates/unit_test.rb
similarity index 100%
rename from railties/lib/generators/test_unit/observer/templates/unit_test.rb
rename to railties/lib/rails/generators/test_unit/observer/templates/unit_test.rb
diff --git a/railties/lib/generators/test_unit/performance/performance_generator.rb b/railties/lib/rails/generators/test_unit/performance/performance_generator.rb
similarity index 88%
rename from railties/lib/generators/test_unit/performance/performance_generator.rb
rename to railties/lib/rails/generators/test_unit/performance/performance_generator.rb
index 0d9c646b26..99edda5461 100644
--- a/railties/lib/generators/test_unit/performance/performance_generator.rb
+++ b/railties/lib/rails/generators/test_unit/performance/performance_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/test_unit'
+require 'rails/generators/test_unit'
module TestUnit
module Generators
diff --git a/railties/lib/generators/test_unit/performance/templates/performance_test.rb b/railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb
similarity index 100%
rename from railties/lib/generators/test_unit/performance/templates/performance_test.rb
rename to railties/lib/rails/generators/test_unit/performance/templates/performance_test.rb
diff --git a/railties/lib/generators/test_unit/plugin/plugin_generator.rb b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb
similarity index 84%
rename from railties/lib/generators/test_unit/plugin/plugin_generator.rb
rename to railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb
index 05adf58c4f..4d65cd7d89 100644
--- a/railties/lib/generators/test_unit/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/test_unit'
+require 'rails/generators/test_unit'
module TestUnit
module Generators
diff --git a/railties/lib/generators/test_unit/plugin/templates/%file_name%_test.rb.tt b/railties/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt
similarity index 100%
rename from railties/lib/generators/test_unit/plugin/templates/%file_name%_test.rb.tt
rename to railties/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt
diff --git a/railties/lib/generators/test_unit/plugin/templates/test_helper.rb b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb
similarity index 100%
rename from railties/lib/generators/test_unit/plugin/templates/test_helper.rb
rename to railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb
diff --git a/railties/lib/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
similarity index 93%
rename from railties/lib/generators/test_unit/scaffold/scaffold_generator.rb
rename to railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
index a95916ae13..c0315c7fe6 100644
--- a/railties/lib/generators/test_unit/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/test_unit'
+require 'rails/generators/test_unit'
require 'rails/generators/resource_helpers'
module TestUnit
diff --git a/railties/lib/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
similarity index 71%
rename from railties/lib/generators/test_unit/scaffold/templates/functional_test.rb
rename to railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
index 9380aa49b6..4f8ddbffcf 100644
--- a/railties/lib/generators/test_unit/scaffold/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
@@ -1,6 +1,10 @@
require 'test_helper'
class <%= controller_class_name %>ControllerTest < ActionController::TestCase
+ setup do
+ @<%= file_name %> = <%= table_name %>(:one)
+ end
+
<% unless options[:singleton] -%>
test "should get index" do
get :index
@@ -16,30 +20,30 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase
test "should create <%= file_name %>" do
assert_difference('<%= class_name %>.count') do
- post :create, :<%= file_name %> => <%= table_name %>(:one).attributes
+ post :create, :<%= file_name %> => @<%= file_name %>.attributes
end
assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
end
test "should show <%= file_name %>" do
- get :show, :id => <%= table_name %>(:one).to_param
+ get :show, :id => @<%= file_name %>.to_param
assert_response :success
end
test "should get edit" do
- get :edit, :id => <%= table_name %>(:one).to_param
+ get :edit, :id => @<%= file_name %>.to_param
assert_response :success
end
test "should update <%= file_name %>" do
- put :update, :id => <%= table_name %>(:one).to_param, :<%= file_name %> => <%= table_name %>(:one).attributes
+ put :update, :id => @<%= file_name %>.to_param, :<%= file_name %> => @<%= file_name %>.attributes
assert_redirected_to <%= file_name %>_path(assigns(:<%= file_name %>))
end
test "should destroy <%= file_name %>" do
assert_difference('<%= class_name %>.count', -1) do
- delete :destroy, :id => <%= table_name %>(:one).to_param
+ delete :destroy, :id => @<%= file_name %>.to_param
end
assert_redirected_to <%= table_name %>_path
diff --git a/railties/builtin/rails_info/rails/info.rb b/railties/lib/rails/info.rb
similarity index 100%
rename from railties/builtin/rails_info/rails/info.rb
rename to railties/lib/rails/info.rb
diff --git a/railties/builtin/rails_info/rails/info_controller.rb b/railties/lib/rails/info_controller.rb
similarity index 100%
rename from railties/builtin/rails_info/rails/info_controller.rb
rename to railties/lib/rails/info_controller.rb
diff --git a/railties/builtin/routes.rb b/railties/lib/rails/info_routes.rb
similarity index 100%
rename from railties/builtin/routes.rb
rename to railties/lib/rails/info_routes.rb
diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb
index 98f329cc17..0997be1b6f 100644
--- a/railties/lib/rails/plugin.rb
+++ b/railties/lib/rails/plugin.rb
@@ -2,6 +2,21 @@
require 'active_support/core_ext/array/conversions'
module Rails
+ # Rails::Plugin is nothing more than a Rails::Engine, but since it's loaded too late
+ # in the boot process, it does not have the same configuration powers as a bare
+ # Rails::Engine.
+ #
+ # Opposite to Rails::Railtie and Rails::Engine, you are not supposed to inherit from
+ # Rails::Plugin. Rails::Plugin is automatically configured to be an engine by simply
+ # placing inside vendor/plugins. Since this is done automatically, you actually cannot
+ # declare a Rails::Engine inside your Plugin, otherwise it would cause the same files
+ # to be loaded twice. This means that if you want to ship an Engine as gem it cannot
+ # be used as plugin and vice-versa.
+ #
+ # Besides this conceptual difference, the only difference between Rails::Engine and
+ # Rails::Plugin is that plugins automatically load the file "init.rb" at the plugin
+ # root during the boot process.
+ #
class Plugin < Engine
def self.inherited(base)
raise "You cannot inherit from Rails::Plugin"
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index 37c802fb60..0d68abb323 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -3,13 +3,183 @@
require 'active_support/inflector'
module Rails
+ # Railtie is the core of the Rails Framework and provides several hooks to extend
+ # Rails and/or modify the initialization process.
+ #
+ # Every major component of Rails (Action Mailer, Action Controller,
+ # Action View, Active Record and Active Resource) are all Railties, so each of
+ # them is responsible to set their own initialization. This makes, for example,
+ # Rails absent of any ActiveRecord hook, allowing any other ORM framework to hook in.
+ #
+ # Developing a Rails extension does _not_ require any implementation of
+ # Railtie, but if you need to interact with the Rails framework during
+ # or after boot, then Railtie is what you need to do that interaction.
+ #
+ # For example, the following would need you to implement Railtie in your
+ # plugin:
+ #
+ # * creating initializers
+ # * configuring a Rails framework or the Application, like setting a generator
+ # * adding Rails config.* keys to the environment
+ # * setting up a subscriber to the Rails +ActiveSupport::Notifications+
+ # * adding rake tasks into rails
+ #
+ # == Creating your Railtie
+ #
+ # Implementing Railtie in your Rails extension is done by creating a class
+ # Railtie that has your extension name and making sure that this gets loaded
+ # during boot time of the Rails stack.
+ #
+ # You can do this however you wish, but here is an example if you want to provide
+ # it for a gem that can be used with or without Rails:
+ #
+ # * Create a file (say, lib/my_gem/railtie.rb) which contains class Railtie inheriting from
+ # Rails::Railtie and is namespaced to your gem:
+ #
+ # # lib/my_gem/railtie.rb
+ # module MyGem
+ # class Railtie < Rails::Railtie
+ # railtie_name :mygem
+ # end
+ # end
+ #
+ # * Require your own gem as well as rails in this file:
+ #
+ # # lib/my_gem/railtie.rb
+ # require 'my_gem'
+ # require 'rails'
+ #
+ # module MyGem
+ # class Railtie < Rails::Railtie
+ # railtie_name :mygem
+ # end
+ # end
+ #
+ # * Make sure your Gem loads the railtie.rb file if Rails is loaded first, an easy
+ # way to check is by checking for the Rails constant which will exist if Rails
+ # has started:
+ #
+ # # lib/my_gem.rb
+ # module MyGem
+ # require 'lib/my_gem/railtie' if defined?(Rails)
+ # end
+ #
+ # * Or instead of doing the require automatically, you can ask your users to require
+ # it for you in their Gemfile:
+ #
+ # # #{USER_RAILS_ROOT}/Gemfile
+ # gem "my_gem", :require_as => ["my_gem", "my_gem/railtie"]
+ #
+ # == Initializers
+ #
+ # To add an initialization step from your Railtie to Rails boot process, you just need
+ # to create an initializer block:
+ #
+ # class MyRailtie < Rails::Railtie
+ # initializer "my_railtie.configure_rails_initialization" do
+ # # some initialization behavior
+ # end
+ # end
+ #
+ # If specified, the block can also receive the application object, in case you
+ # need to access some application specific configuration:
+ #
+ # class MyRailtie < Rails::Railtie
+ # initializer "my_railtie.configure_rails_initialization" do |app|
+ # if app.config.cache_classes
+ # # some initialization behavior
+ # end
+ # end
+ # end
+ #
+ # Finally, you can also pass :before and :after as option to initializer, in case
+ # you want to couple it with a specific step in the initialization process.
+ #
+ # == Configuration
+ #
+ # Inside the Railtie class, you can access a config object which contains configuration
+ # shared by all railties and the application:
+ #
+ # class MyRailtie < Rails::Railtie
+ # # Customize the ORM
+ # config.generators.orm :my_railtie_orm
+ #
+ # # Add a middleware
+ # config.middlewares.use MyRailtie::Middleware
+ #
+ # # Add a to_prepare block which is executed once in production
+ # # and before which request in development
+ # config.to_prepare do
+ # MyRailtie.setup!
+ # end
+ # end
+ #
+ # == Loading rake tasks and generators
+ #
+ # If your railtie has rake tasks, you can tell Rails to load them through the method
+ # rake tasks:
+ #
+ # class MyRailtie < Railtie
+ # rake_tasks do
+ # load "path/to/my_railtie.tasks"
+ # end
+ # end
+ #
+ # By default, Rails load generators from your load path. However, if you want to place
+ # your generators at a different location, you can specify in your Railtie a block which
+ # will load them during normal generators lookup:
+ #
+ # class MyRailtie < Railtie
+ # generators do
+ # require "path/to/my_railtie_generator"
+ # end
+ # end
+ #
+ # == Adding your subscriber
+ #
+ # Since version 3.0, Rails ships with a notification system which is used for several
+ # purposes, including logging. If you are sending notifications in your Railtie, you may
+ # want to add a subscriber to consume such notifications for logging purposes.
+ #
+ # The subscriber is added under the railtie_name namespace and only consumes notifications
+ # under the given namespace. For example, let's suppose your railtie is publishing the
+ # following "something_expensive" instrumentation:
+ #
+ # ActiveSupport::Notifications.instrument "my_railtie.something_expensive" do
+ # # something expensive
+ # end
+ #
+ # You can log this instrumentation with your own Rails::Subscriber:
+ #
+ # class MyRailtie::Subscriber < Rails::Subscriber
+ # def something_expensive(event)
+ # info("Something expensive took %.1fms" % event.duration)
+ # end
+ # end
+ #
+ # By registering it:
+ #
+ # class MyRailtie < Railtie
+ # subscriber MyRailtie::Subscriber.new
+ # end
+ #
+ # Take a look in Rails::Subscriber docs for more information.
+ #
+ # == Application, Plugin and Engine
+ #
+ # A Rails::Engine is nothing more than a Railtie with some initializers already set.
+ # And since Rails::Application and Rails::Plugin are engines, the same configuration
+ # described here can be used in all three.
+ #
+ # Be sure to look at the documentation of those specific classes for more information.
+ #
class Railtie
autoload :Configurable, "rails/railtie/configurable"
autoload :Configuration, "rails/railtie/configuration"
include Initializable
- ABSTRACT_RAILTIES = %w(Rails::Plugin Rails::Engine Rails::Application)
+ ABSTRACT_RAILTIES = %w(Rails::Railtie Rails::Plugin Rails::Engine Rails::Application)
class << self
def subclasses
@@ -17,23 +187,18 @@ def subclasses
end
def inherited(base)
- unless abstract_railtie?(base)
+ unless base.abstract_railtie?
base.send(:include, self::Configurable)
subclasses << base
end
end
- def railtie_name(railtie_name = nil)
- @railtie_name = railtie_name if railtie_name
- @railtie_name ||= default_name
+ def railtie_name(*)
+ ActiveSupport::Deprecation.warn "railtie_name is deprecated and has no effect", caller
end
- def railtie_names
- subclasses.map { |p| p.railtie_name }
- end
-
- def log_subscriber(log_subscriber)
- Rails::LogSubscriber.add(railtie_name, log_subscriber)
+ def log_subscriber(name, log_subscriber)
+ Rails::LogSubscriber.add(name, log_subscriber)
end
def rake_tasks(&blk)
@@ -48,14 +213,8 @@ def generators(&blk)
@generators
end
- protected
-
- def abstract_railtie?(base)
- ABSTRACT_RAILTIES.include?(base.name)
- end
-
- def default_name
- ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name))
+ def abstract_railtie?
+ ABSTRACT_RAILTIES.include?(name)
end
end
diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb
index 828ccec3d0..16eccaccc4 100644
--- a/railties/lib/rails/railtie/configuration.rb
+++ b/railties/lib/rails/railtie/configuration.rb
@@ -3,11 +3,8 @@
module Rails
class Railtie
class Configuration
- attr_accessor :cookie_secret
-
def initialize
- @session_store = :cookie_store
- @session_options = {}
+ @@options ||= {}
end
# Holds generators configuration:
@@ -48,76 +45,18 @@ def to_prepare(&blk)
end
def respond_to?(name)
- super || name.to_s =~ config_key_regexp
- end
-
- def metal_loader
- @metal_loader ||= Rails::Application::MetalLoader.new
- end
-
- def session_store(*args)
- if args.empty?
- case @session_store
- when :disabled
- nil
- when :active_record_store
- ActiveRecord::SessionStore
- when Symbol
- ActionDispatch::Session.const_get(@session_store.to_s.camelize)
- else
- @session_store
- end
- else
- @session_store = args.shift
- @session_options = args.shift || {}
- end
+ super || @@options.key?(name.to_sym)
end
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 session_options
- return @session_options unless @session_store == :cookie_store
- @session_options.merge(:secret => @cookie_secret)
- end
-
- def config_key_regexp
- bits = config_keys.map { |n| Regexp.escape(n.to_s) }.join('|')
- /^(#{bits})(?:=)?$/
- end
-
- def config_keys
- (Railtie.railtie_names + Engine.engine_names).map { |n| n.to_s }.uniq
- end
-
- def options
- @@options ||= Hash.new { |h,k| h[k] = ActiveSupport::OrderedOptions.new }
- end
-
- def default_middleware
- require 'action_dispatch'
- ActionDispatch::MiddlewareStack.new.tap do |middleware|
- middleware.use('::ActionDispatch::Static', lambda { Rails.public_path }, :if => lambda { serve_static_assets })
- middleware.use('::Rack::Lock', :if => lambda { !allow_concurrency })
- middleware.use('::Rack::Runtime')
- middleware.use('::Rails::Rack::Logger')
- middleware.use('::ActionDispatch::ShowExceptions', lambda { consider_all_requests_local })
- middleware.use("::ActionDispatch::RemoteIp", lambda { action_dispatch.ip_spoofing_check }, lambda { action_dispatch.trusted_proxies })
- middleware.use('::Rack::Sendfile', lambda { action_dispatch.x_sendfile_header })
- middleware.use('::ActionDispatch::Callbacks', lambda { !cache_classes })
- middleware.use('::ActionDispatch::Cookies')
- middleware.use(lambda { session_store }, lambda { session_options })
- middleware.use('::ActionDispatch::Flash', :if => lambda { session_store })
- middleware.use(lambda { metal_loader.build_middleware(metals) }, :if => lambda { metal_loader.metals.any? })
- middleware.use('ActionDispatch::ParamsParser')
- middleware.use('::Rack::MethodOverride')
- middleware.use('::ActionDispatch::Head')
+ if name.to_s =~ /=$/
+ @@options[$`.to_sym] = args.first
+ elsif @@options.key?(name)
+ @@options[name]
+ else
+ super
end
end
end
diff --git a/railties/lib/rails/railties_path.rb b/railties/lib/rails/railties_path.rb
deleted file mode 100644
index e291fc23ea..0000000000
--- a/railties/lib/rails/railties_path.rb
+++ /dev/null
@@ -1 +0,0 @@
-RAILTIES_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake
index abf9b33ae5..f2fee45594 100644
--- a/railties/lib/rails/tasks/documentation.rake
+++ b/railties/lib/rails/tasks/documentation.rake
@@ -66,13 +66,14 @@ namespace :doc do
task :plugins => plugins.collect { |plugin| "doc:plugins:#{plugin}" }
desc "Remove plugin documentation"
- task :clobber_plugins do
+ task :clobber_plugins do
rm_rf 'doc/plugins' rescue nil
end
desc "Generate Rails guides"
task :guides do
- require File.join(RAILTIES_PATH, "guides/rails_guides")
+ # FIXME: Reaching outside lib directory is a bad idea
+ require File.expand_path('../../../../guides/rails_guides', __FILE__)
RailsGuides::Generator.new(Rails.root.join("doc/guides")).generate
end
@@ -92,7 +93,7 @@ namespace :doc do
files.include("#{plugin_base}/lib/**/*.rb")
if File.exist?("#{plugin_base}/README")
- files.include("#{plugin_base}/README")
+ files.include("#{plugin_base}/README")
options << "--main '#{plugin_base}/README'"
end
files.include("#{plugin_base}/CHANGELOG") if File.exist?("#{plugin_base}/CHANGELOG")
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index dbe2ac54ed..738f7f5301 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -2,18 +2,18 @@ namespace :rails do
namespace :freeze do
desc "The rails:freeze:gems is deprecated, please use bundle install instead"
task :gems do
- puts "The rails:freeze:gems is deprecated, please use bundle install instead"
+ abort "The rails:freeze:gems is deprecated, please use bundle install instead"
end
desc 'The freeze:edge command has been deprecated, specify the path setting in your app Gemfile instead and bundle install'
task :edge do
- puts 'The freeze:edge command has been deprecated, specify the path setting in your app Gemfile instead and bundle install'
+ abort 'The freeze:edge command has been deprecated, specify the path setting in your app Gemfile instead and bundle install'
end
end
desc 'The unfreeze command has been deprecated, please use bundler commands instead'
task :unfreeze do
- puts 'The unfreeze command has been deprecated, please use bundler commands instead'
+ abort 'The unfreeze command has been deprecated, please use bundler commands instead'
end
desc "Update both configs, scripts and public/javascripts from Rails"
@@ -25,7 +25,7 @@ namespace :rails do
template = File.expand_path(template) if template !~ %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://}
require 'rails/generators'
- require 'generators/rails/app/app_generator'
+ require 'rails/generators/rails/app/app_generator'
generator = Rails::Generators::AppGenerator.new [ Rails.root ], {}, :destination_root => Rails.root
generator.apply template, :verbose => false
end
@@ -38,10 +38,11 @@ namespace :rails do
def app_generator
@app_generator ||= begin
require 'rails/generators'
- require 'generators/rails/app/app_generator'
+ require 'rails/generators/rails/app/app_generator'
gen = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true },
:destination_root => Rails.root
- gen.send(:valid_app_const?)
+ File.exists?(Rails.root.join("config", "application.rb")) ?
+ gen.send(:app_const) : gen.send(:valid_app_const?)
gen
end
end
diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake
index 48fce92215..0926707a04 100644
--- a/railties/lib/rails/tasks/misc.rake
+++ b/railties/lib/rails/tasks/misc.rake
@@ -15,8 +15,6 @@ end
desc 'Explain the current environment'
task :about do
- $LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info"
- require 'rails/info'
puts Rails::Info
end
@@ -26,12 +24,12 @@ namespace :time do
task :all do
build_time_zone_list(:all)
end
-
+
desc 'Displays names of US time zones recognized by the Rails TimeZone class, grouped by offset. Results can be filtered with optional OFFSET parameter, e.g., OFFSET=-6'
task :us do
build_time_zone_list(:us_zones)
end
-
+
desc 'Displays names of time zones recognized by the Rails TimeZone class with the same offset as the system local time'
task :local do
require 'active_support'
@@ -41,7 +39,7 @@ namespace :time do
offset = jan_offset < jul_offset ? jan_offset : jul_offset
build_time_zone_list(:all, offset)
end
-
+
# to find UTC -06:00 zones, OFFSET can be set to either -6, -6:00 or 21600
def build_time_zone_list(method, offset = ENV['OFFSET'])
require 'active_support'
diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb
index 2ed5353755..6522c94ad6 100644
--- a/railties/lib/rails/test_help.rb
+++ b/railties/lib/rails/test_help.rb
@@ -4,14 +4,18 @@
require 'test/unit'
require 'active_support/core_ext/kernel/requires'
+require 'active_support/test_case'
+require 'action_controller/test_case'
+require 'action_dispatch/testing/integration'
-# TODO: Figure out how to get the Rails::BacktraceFilter into minitest/unit
if defined?(Test::Unit::Util::BacktraceFilter) && ENV['BACKTRACE'].nil?
require 'rails/backtrace_cleaner'
Test::Unit::Util::BacktraceFilter.module_eval { include Rails::BacktraceFilterForTestUnit }
end
if defined?(ActiveRecord)
+ require 'active_record/test_case'
+
class ActiveSupport::TestCase
include ActiveRecord::TestFixtures
self.fixture_path = "#{Rails.root}/test/fixtures/"
diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb
index d99325a6d8..e3fafc4b9d 100644
--- a/railties/lib/rails/test_unit/railtie.rb
+++ b/railties/lib/rails/test_unit/railtie.rb
@@ -1,7 +1,5 @@
module Rails
class TestUnitRailtie < Rails::Railtie
- railtie_name :test_unit
-
config.generators do |c|
c.test_framework :test_unit, :fixture => true,
:fixture_replacement => nil
diff --git a/railties/railties.gemspec b/railties/railties.gemspec
index b9d2739539..aea07efe96 100644
--- a/railties/railties.gemspec
+++ b/railties/railties.gemspec
@@ -13,7 +13,7 @@
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'rails'
- s.files = Dir['CHANGELOG', 'README', 'bin/**/*', 'builtin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}']
+ s.files = Dir['CHANGELOG', 'README', 'bin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}']
s.require_path = 'lib'
s.bindir = 'bin'
s.executables = ['rails']
diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb
index aa66dbb9be..d04a2aa1f3 100644
--- a/railties/test/abstract_unit.rb
+++ b/railties/test/abstract_unit.rb
@@ -1,7 +1,6 @@
ORIG_ARGV = ARGV.dup
require File.expand_path("../../../load_paths", __FILE__)
-$:.unshift File.expand_path("../../builtin/rails_info", __FILE__)
require 'stringio'
require 'test/unit'
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 54cd751f4e..68ca2acaad 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -140,7 +140,7 @@ def teardown
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|
@@ -172,16 +172,27 @@ def teardown
assert $prepared
end
- test "config.action_dispatch.x_sendfile_header defaults to X-Sendfile" do
+ def make_basic_app
require "rails"
require "action_controller/railtie"
- class MyApp < Rails::Application
- config.cookie_secret = "3b7cd727ee24e8444053437c36cc66c4"
- config.session_store :cookie_store, :key => "_myapp_session"
+ app = Class.new(Rails::Application)
+
+ yield app if block_given?
+
+ app.config.session_store :disabled
+ app.initialize!
+
+ app.routes.draw do
+ match "/" => "omg#index"
end
- MyApp.initialize!
+ require 'rack/test'
+ extend Rack::Test::Methods
+ end
+
+ test "config.action_dispatch.x_sendfile_header defaults to ''" do
+ make_basic_app
class ::OmgController < ActionController::Base
def index
@@ -189,44 +200,53 @@ def index
end
end
- MyApp.routes.draw do
- match "/" => "omg#index"
+ get "/"
+ assert_equal File.read(__FILE__), last_response.body
+ end
+
+ test "config.action_dispatch.x_sendfile_header can be set" do
+ make_basic_app do |app|
+ app.config.action_dispatch.x_sendfile_header = "X-Sendfile"
end
- require 'rack/test'
- extend Rack::Test::Methods
+ class ::OmgController < ActionController::Base
+ def index
+ send_file __FILE__
+ end
+ end
get "/"
assert_equal File.expand_path(__FILE__), last_response.headers["X-Sendfile"]
end
test "config.action_dispatch.x_sendfile_header is sent to Rack::Sendfile" do
- require "rails"
- require "action_controller/railtie"
-
- class MyApp < Rails::Application
- config.cookie_secret = "3b7cd727ee24e8444053437c36cc66c4"
- config.session_store :cookie_store, :key => "_myapp_session"
- config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File'
+ make_basic_app do |app|
+ app.config.action_dispatch.x_sendfile_header = 'X-Lighttpd-Send-File'
end
- MyApp.initialize!
-
class ::OmgController < ActionController::Base
def index
send_file __FILE__
end
end
- MyApp.routes.draw do
- match "/" => "omg#index"
- end
-
- require 'rack/test'
- extend Rack::Test::Methods
-
get "/"
assert_equal File.expand_path(__FILE__), last_response.headers["X-Lighttpd-Send-File"]
end
+
+ test "protect from forgery is the default in a new app" do
+ make_basic_app
+
+ class ::OmgController < ActionController::Base
+ protect_from_forgery
+
+ def index
+ render :inline => "<%= csrf_meta_tag %>"
+ end
+ end
+
+ get "/"
+ assert last_response.body =~ /csrf\-param/
+ end
end
end
diff --git a/railties/test/application/paths_test.rb b/railties/test/application/paths_test.rb
index 511b8b629a..589e515d05 100644
--- a/railties/test/application/paths_test.rb
+++ b/railties/test/application/paths_test.rb
@@ -51,8 +51,6 @@ def assert_not_in_load_path(*path)
assert_path @paths.config.environment, "config", "environments", "development.rb"
assert_equal root("app", "controllers"), @paths.app.controllers.to_a.first
- assert_equal Pathname.new(File.dirname(__FILE__)).join("..", "..", "builtin", "rails_info").expand_path,
- Pathname.new(@paths.app.controllers.to_a[1]).expand_path
end
test "booting up Rails yields a list of paths that are eager" do
@@ -80,21 +78,5 @@ def assert_not_in_load_path(*path)
assert_not_in_load_path "tmp"
assert_not_in_load_path "tmp", "cache"
end
-
- test "controller paths include builtin in development mode" do
- Rails.env.replace "development"
- assert Rails::Application::Configuration.new("/").paths.app.controllers.paths.any? { |p| p =~ /builtin/ }
- end
-
- test "controller paths does not have builtin_directories in test mode" do
- Rails.env.replace "test"
- assert !Rails::Application::Configuration.new("/").paths.app.controllers.paths.any? { |p| p =~ /builtin/ }
- end
-
- test "controller paths does not have builtin_directories in production mode" do
- Rails.env.replace "production"
- assert !Rails::Application::Configuration.new("/").paths.app.controllers.paths.any? { |p| p =~ /builtin/ }
- end
-
end
end
diff --git a/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb b/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb
index 7a4edb8bcb..a7d079a1bc 100644
--- a/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb
+++ b/railties/test/fixtures/lib/generators/active_record/fixjour_generator.rb
@@ -1,4 +1,4 @@
-require 'generators/active_record'
+require 'rails/generators/active_record'
module ActiveRecord
module Generators
diff --git a/railties/test/fixtures/lib/rails_generators/foobar/foobar_generator.rb b/railties/test/fixtures/lib/rails/generators/foobar/foobar_generator.rb
similarity index 100%
rename from railties/test/fixtures/lib/rails_generators/foobar/foobar_generator.rb
rename to railties/test/fixtures/lib/rails/generators/foobar/foobar_generator.rb
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index 3585e6e7c0..44e0640552 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -1,8 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/app/app_generator'
-
-# TODO This line shouldn't be required
-require 'generators/rails/model/model_generator'
+require 'rails/generators/rails/app/app_generator'
class ActionsTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 412034029e..95ca2acf2c 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -1,6 +1,6 @@
require 'abstract_unit'
require 'generators/generators_test_helper'
-require 'generators/rails/app/app_generator'
+require 'rails/generators/rails/app/app_generator'
class AppGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
@@ -9,6 +9,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def setup
super
Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
+ @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
end
def teardown
@@ -65,6 +66,13 @@ def test_invalid_application_name_raises_an_error
assert_equal "Invalid application name 43-things. Please give a name which does not start with numbers.\n", content
end
+ def test_application_name_raises_an_error_if_name_already_used_constant
+ %w{ String Hash Class Module Set Symbol }.each do |ruby_class|
+ content = capture(:stderr){ run_generator [File.join(destination_root, ruby_class)] }
+ assert_equal "Invalid application name #{ruby_class}, constant #{ruby_class} is already in use. Please choose another application name.\n", content
+ end
+ end
+
def test_invalid_application_name_is_fixed
run_generator [File.join(destination_root, "things-43")]
assert_file "things-43/config/environment.rb", /Things43::Application\.initialize!/
@@ -161,14 +169,14 @@ def test_file_is_added_for_backwards_compatibility
end
def test_dev_option
- generator([destination_root], :dev => true).expects(:run).with("bundle install")
+ generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install")
silence(:stdout){ generator.invoke }
rails_path = File.expand_path('../../..', Rails.root)
assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/
end
def test_edge_option
- generator([destination_root], :edge => true).expects(:run).with("bundle install")
+ generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install")
silence(:stdout){ generator.invoke }
assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$/
end
diff --git a/railties/test/generators/controller_generator_test.rb b/railties/test/generators/controller_generator_test.rb
index 79a4e5bf17..be99dc068d 100644
--- a/railties/test/generators/controller_generator_test.rb
+++ b/railties/test/generators/controller_generator_test.rb
@@ -1,10 +1,12 @@
require 'generators/generators_test_helper'
-require 'generators/rails/controller/controller_generator'
+require 'rails/generators/rails/controller/controller_generator'
class ControllerGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
arguments %w(Account foo bar)
+ setup :copy_routes
+
def test_help_does_not_show_invoked_generators_options_if_they_already_exist
content = run_generator ["--help"]
assert_no_match /Helper options\:/, content
@@ -23,8 +25,6 @@ def test_check_class_collision
Object.send :remove_const, :ObjectController
end
- # No need to spec content since it's already spec'ed on helper generator.
- #
def test_invokes_helper
run_generator
assert_file "app/helpers/account_helper.rb"
@@ -49,8 +49,13 @@ def test_does_not_invoke_test_framework_if_required
def test_invokes_default_template_engine
run_generator
- assert_file "app/views/account/foo.html.erb", /app\/views\/account\/foo/
- assert_file "app/views/account/bar.html.erb", /app\/views\/account\/bar/
+ assert_file "app/views/account/foo.html.erb", %r(app/views/account/foo\.html\.erb)
+ assert_file "app/views/account/bar.html.erb", %r(app/views/account/bar\.html\.erb)
+ end
+
+ def test_add_routes
+ run_generator
+ assert_file "config/routes.rb", /get "account\/foo"/, /get "account\/bar"/
end
def test_invokes_default_template_engine_even_with_no_action
diff --git a/railties/test/generators/generator_generator_test.rb b/railties/test/generators/generator_generator_test.rb
index f3fd688e4f..26f975a191 100644
--- a/railties/test/generators/generator_generator_test.rb
+++ b/railties/test/generators/generator_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/generator/generator_generator'
+require 'rails/generators/rails/generator/generator_generator'
class GeneratorGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb
index 32be99b144..d8bdb344f2 100644
--- a/railties/test/generators/generators_test_helper.rb
+++ b/railties/test/generators/generators_test_helper.rb
@@ -26,4 +26,11 @@ def self.included(base)
end
end
end
+
+ def copy_routes
+ routes = File.expand_path("../../../lib/rails/generators/rails/app/templates/config/routes.rb", __FILE__)
+ destination = File.join(destination_root, "config")
+ FileUtils.mkdir_p(destination)
+ FileUtils.cp File.expand_path(routes), destination
+ end
end
\ No newline at end of file
diff --git a/railties/test/generators/helper_generator_test.rb b/railties/test/generators/helper_generator_test.rb
index 6d7168738e..f0bfebd57f 100644
--- a/railties/test/generators/helper_generator_test.rb
+++ b/railties/test/generators/helper_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/helper/helper_generator'
+require 'rails/generators/rails/helper/helper_generator'
ObjectHelper = Class.new
AnotherObjectHelperTest = Class.new
diff --git a/railties/test/generators/integration_test_generator_test.rb b/railties/test/generators/integration_test_generator_test.rb
index d7fc324c88..cf282a0911 100644
--- a/railties/test/generators/integration_test_generator_test.rb
+++ b/railties/test/generators/integration_test_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/integration_test/integration_test_generator'
+require 'rails/generators/rails/integration_test/integration_test_generator'
class IntegrationTestGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb
index e6fc1bbb5c..81d6afa221 100644
--- a/railties/test/generators/mailer_generator_test.rb
+++ b/railties/test/generators/mailer_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/mailer/mailer_generator'
+require 'rails/generators/rails/mailer/mailer_generator'
class MailerGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
@@ -28,20 +28,22 @@ def test_check_class_collision
def test_invokes_default_test_framework
run_generator
- assert_file "test/functional/notifier_test.rb", /class NotifierTest < ActionMailer::TestCase/
- assert_file "test/fixtures/notifier/foo", /app\/views\/notifier\/foo/
- assert_file "test/fixtures/notifier/bar", /app\/views\/notifier\/bar/
+ assert_file "test/functional/notifier_test.rb" do |test|
+ assert_match /class NotifierTest < ActionMailer::TestCase/, test
+ assert_match /test "foo"/, test
+ assert_match /test "bar"/, test
+ end
end
def test_invokes_default_template_engine
run_generator
assert_file "app/views/notifier/foo.text.erb" do |view|
- assert_match /app\/views\/notifier\/foo/, view
+ assert_match %r(app/views/notifier/foo\.text\.erb), view
assert_match /<%= @greeting %>/, view
end
assert_file "app/views/notifier/bar.text.erb" do |view|
- assert_match /app\/views\/notifier\/bar/, view
+ assert_match %r(app/views/notifier/bar\.text\.erb), view
assert_match /<%= @greeting %>/, view
end
end
diff --git a/railties/test/generators/metal_generator_test.rb b/railties/test/generators/metal_generator_test.rb
index e3a2384885..615122c882 100644
--- a/railties/test/generators/metal_generator_test.rb
+++ b/railties/test/generators/metal_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/metal/metal_generator'
+require 'rails/generators/rails/metal/metal_generator'
class MetalGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb
index 811a712fd5..762f84d579 100644
--- a/railties/test/generators/migration_generator_test.rb
+++ b/railties/test/generators/migration_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/migration/migration_generator'
+require 'rails/generators/rails/migration/migration_generator'
class MigrationGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb
index 79ce9a2a7b..f5cfd8eeca 100644
--- a/railties/test/generators/model_generator_test.rb
+++ b/railties/test/generators/model_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/model/model_generator'
+require 'rails/generators/rails/model/model_generator'
class ModelGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb
index f327fb1282..e73dd237fb 100644
--- a/railties/test/generators/named_base_test.rb
+++ b/railties/test/generators/named_base_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/scaffold_controller/scaffold_controller_generator'
+require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
# Mock out what we need from AR::Base.
module ActiveRecord
@@ -15,6 +15,20 @@ class NamedBaseTest < Rails::Generators::TestCase
include GeneratorsTestHelper
tests Rails::Generators::ScaffoldControllerGenerator
+ def test_named_generator_with_underscore
+ g = generator ['line_item']
+ assert_name g, 'line_item', :name
+ assert_name g, %w(), :class_path
+ assert_name g, 'LineItem', :class_name
+ assert_name g, 'line_item', :file_path
+ assert_name g, 'line_item', :file_name
+ assert_name g, 'Line item', :human_name
+ assert_name g, 'line_item', :singular_name
+ assert_name g, 'line_items', :plural_name
+ assert_name g, 'line_item', :i18n_scope
+ assert_name g, 'line_items', :table_name
+ end
+
def test_named_generator_attributes
g = generator ['admin/foo']
assert_name g, 'admin/foo', :name
@@ -22,6 +36,7 @@ def test_named_generator_attributes
assert_name g, 'Admin::Foo', :class_name
assert_name g, 'admin/foo', :file_path
assert_name g, 'foo', :file_name
+ assert_name g, 'Foo', :human_name
assert_name g, 'foo', :singular_name
assert_name g, 'foos', :plural_name
assert_name g, 'admin.foo', :i18n_scope
@@ -36,6 +51,7 @@ def test_named_generator_attributes_as_ruby
assert_name g, 'admin/foo', :file_path
assert_name g, 'foo', :file_name
assert_name g, 'foo', :singular_name
+ assert_name g, 'Foo', :human_name
assert_name g, 'foos', :plural_name
assert_name g, 'admin.foo', :i18n_scope
assert_name g, 'admin_foos', :table_name
@@ -45,6 +61,8 @@ def test_named_generator_attributes_without_pluralized
ActiveRecord::Base.pluralize_table_names = false
g = generator ['admin/foo']
assert_name g, 'admin_foo', :table_name
+ ensure
+ ActiveRecord::Base.pluralize_table_names = true
end
def test_scaffold_plural_names
diff --git a/railties/test/generators/observer_generator_test.rb b/railties/test/generators/observer_generator_test.rb
index 058a19228d..45fe8dfbd3 100644
--- a/railties/test/generators/observer_generator_test.rb
+++ b/railties/test/generators/observer_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/observer/observer_generator'
+require 'rails/generators/rails/observer/observer_generator'
class ObserverGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/performance_test_generator_test.rb b/railties/test/generators/performance_test_generator_test.rb
index c95063a127..8fda83b36f 100644
--- a/railties/test/generators/performance_test_generator_test.rb
+++ b/railties/test/generators/performance_test_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/performance_test/performance_test_generator'
+require 'rails/generators/rails/performance_test/performance_test_generator'
class PerformanceTestGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb
index 065dbe1423..c1f646f7c1 100644
--- a/railties/test/generators/plugin_generator_test.rb
+++ b/railties/test/generators/plugin_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/plugin/plugin_generator'
+require 'rails/generators/rails/plugin/plugin_generator'
class PluginGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb
index 959934bd71..96fd7a0a72 100644
--- a/railties/test/generators/resource_generator_test.rb
+++ b/railties/test/generators/resource_generator_test.rb
@@ -1,19 +1,11 @@
require 'generators/generators_test_helper'
-require 'generators/rails/resource/resource_generator'
+require 'rails/generators/rails/resource/resource_generator'
class ResourceGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
arguments %w(account)
- def setup
- super
- routes = Rails::Generators::ResourceGenerator.source_root
- routes = File.join(routes, "..", "..", "app", "templates", "config", "routes.rb")
- destination = File.join(destination_root, "config")
-
- FileUtils.mkdir_p(destination)
- FileUtils.cp File.expand_path(routes), destination
- end
+ setup :copy_routes
def test_help_with_inherited_options
content = run_generator ["--help"]
diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb
index f971598d18..77ed63b1bb 100644
--- a/railties/test/generators/scaffold_controller_generator_test.rb
+++ b/railties/test/generators/scaffold_controller_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/scaffold_controller/scaffold_controller_generator'
+require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
module Unknown
module Generators
diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb
index a7e9c8a231..6cf2efca45 100644
--- a/railties/test/generators/scaffold_generator_test.rb
+++ b/railties/test/generators/scaffold_generator_test.rb
@@ -1,19 +1,11 @@
require 'generators/generators_test_helper'
-require 'generators/rails/scaffold/scaffold_generator'
+require 'rails/generators/rails/scaffold/scaffold_generator'
class ScaffoldGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
arguments %w(product_line title:string price:integer)
- def setup
- super
- routes = Rails::Generators::ResourceGenerator.source_root
- routes = File.join(routes, "..", "..", "app", "templates", "config", "routes.rb")
- destination = File.join(destination_root, "config")
-
- FileUtils.mkdir_p(destination)
- FileUtils.cp File.expand_path(routes), destination
- end
+ setup :copy_routes
def test_scaffold_on_invoke
run_generator
diff --git a/railties/test/generators/session_migration_generator_test.rb b/railties/test/generators/session_migration_generator_test.rb
index de28b4c75b..9fee948d7c 100644
--- a/railties/test/generators/session_migration_generator_test.rb
+++ b/railties/test/generators/session_migration_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/session_migration/session_migration_generator'
+require 'rails/generators/rails/session_migration/session_migration_generator'
class SessionMigrationGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators/stylesheets_generator_test.rb b/railties/test/generators/stylesheets_generator_test.rb
index 718fcb1fa7..aaeb686daa 100644
--- a/railties/test/generators/stylesheets_generator_test.rb
+++ b/railties/test/generators/stylesheets_generator_test.rb
@@ -1,5 +1,5 @@
require 'generators/generators_test_helper'
-require 'generators/rails/stylesheets/stylesheets_generator'
+require 'rails/generators/rails/stylesheets/stylesheets_generator'
class StylesheetsGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb
index dd17f8f756..16f8f43b99 100644
--- a/railties/test/generators_test.rb
+++ b/railties/test/generators_test.rb
@@ -1,6 +1,6 @@
require 'generators/generators_test_helper'
-require 'generators/rails/model/model_generator'
-require 'generators/test_unit/model/model_generator'
+require 'rails/generators/rails/model/model_generator'
+require 'rails/generators/test_unit/model/model_generator'
require 'mocha'
class GeneratorsTest < Rails::Generators::TestCase
@@ -104,11 +104,25 @@ def test_rails_generators_help_with_builtin_information
def test_rails_generators_with_others_information
output = capture(:stdout){ Rails::Generators.help }
- assert_match /ActiveRecord:/, output
assert_match /Fixjour:/, output
+ assert_match /^ fixjour$/, output
+ end
+
+ def test_rails_generators_does_not_show_activerecord_info_if_its_the_default
+ output = capture(:stdout){ Rails::Generators.help }
+ assert_no_match /ActiveRecord:/, output
+ assert_no_match /^ active_record:model$/, output
+ assert_no_match /^ active_record:fixjour$/, output
+ end
+
+ def test_rails_generators_shows_activerecord_info_if_its_not_the_default
+ Rails::Generators.options[:rails][:orm] = :data_mapper
+ output = capture(:stdout){ Rails::Generators.help }
+ assert_match /ActiveRecord:/, output
assert_match /^ active_record:model$/, output
assert_match /^ active_record:fixjour$/, output
- assert_match /^ fixjour$/, output
+ ensure
+ Rails::Generators.options[:rails][:orm] = :active_record
end
def test_no_color_sets_proper_shell
diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb
index d904d7b461..05ec359f61 100644
--- a/railties/test/rails_info_controller_test.rb
+++ b/railties/test/rails_info_controller_test.rb
@@ -1,9 +1,6 @@
require 'abstract_unit'
require 'action_controller'
-require 'rails/info'
-require 'rails/info_controller'
-
module ActionController
class Base
include ActionController::Testing
diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb
index 9fefb285b4..546bf5e143 100644
--- a/railties/test/railties/railtie_test.rb
+++ b/railties/test/railties/railtie_test.rb
@@ -32,28 +32,25 @@ class Foo < Rails::Railtie ; end
end
test "config name is available for the railtie" do
- class Foo < Rails::Railtie ; config.foo.greetings = "hello" ; end
+ class Foo < Rails::Railtie
+ config.foo = ActiveSupport::OrderedOptions.new
+ config.foo.greetings = "hello"
+ end
assert_equal "hello", Foo.config.foo.greetings
end
test "railtie configurations are available in the application" do
- class Foo < Rails::Railtie ; config.foo.greetings = "hello" ; end
+ class Foo < Rails::Railtie
+ config.foo = ActiveSupport::OrderedOptions.new
+ config.foo.greetings = "hello"
+ end
require "#{app_path}/config/application"
assert_equal "hello", AppTemplate::Application.config.foo.greetings
end
- test "railtie config merges are deep" do
- class Foo < Rails::Railtie ; config.foo.greetings = 'hello' ; end
- class Bar < Rails::Railtie
- config.foo.bar = "bar"
- end
- assert_equal "hello", Bar.config.foo.greetings
- assert_equal "bar", Bar.config.foo.bar
- end
-
test "railtie can add log subscribers" do
begin
- class Foo < Rails::Railtie ; log_subscriber(Rails::LogSubscriber.new) ; end
+ class Foo < Rails::Railtie ; log_subscriber(:foo, Rails::LogSubscriber.new) ; end
assert_kind_of Rails::LogSubscriber, Rails::LogSubscriber.log_subscribers[0]
ensure
Rails::LogSubscriber.log_subscribers.clear