aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikel Lindsaar <raasdnil@gmail.com>2010-04-25 17:07:55 +1000
committerMikel Lindsaar <raasdnil@gmail.com>2010-04-25 17:07:55 +1000
commite1b255aca456a5b456111b09237805fd32d15111 (patch)
treea87c8b8989449a9dbdf1c6897901f6957ec021dc
parent60ab54113fa833a1258d687673561b9474964149 (diff)
parenta5955196f2ed8a69c49a1a8c0c617ab91cb8d716 (diff)
downloadrails-e1b255aca456a5b456111b09237805fd32d15111.tar.gz
rails-e1b255aca456a5b456111b09237805fd32d15111.tar.bz2
rails-e1b255aca456a5b456111b09237805fd32d15111.zip
Merge branch 'master' of github.com:lifo/docrails
-rw-r--r--actionmailer/lib/action_mailer/old_api.rb1
-rw-r--r--actionpack/CHANGELOG2
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/caching.rb5
-rw-r--r--actionpack/lib/action_controller/caching/pages.rb12
-rw-r--r--actionpack/lib/action_controller/deprecated/base.rb9
-rw-r--r--actionpack/lib/action_controller/test_case.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb1
-rw-r--r--actionpack/lib/action_dispatch/routing/deprecated_mapper.rb1
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb6
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/test_process.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb2
-rw-r--r--actionpack/lib/action_view/test_case.rb1
-rw-r--r--actionpack/test/controller/caching_test.rb20
-rw-r--r--actionpack/test/controller/log_subscriber_test.rb8
-rw-r--r--actionpack/test/controller/mime_responds_test.rb1
-rw-r--r--actionpack/test/controller/new_base/content_type_test.rb18
-rw-r--r--actionpack/test/controller/test_test.rb16
-rw-r--r--actionpack/test/dispatch/routing_test.rb9
-rw-r--r--actionpack/test/template/erb_util_test.rb4
-rw-r--r--actionpack/test/template/form_options_helper_test.rb4
-rw-r--r--actionpack/test/template/url_helper_test.rb8
-rw-r--r--activemodel/lib/active_model/observing.rb27
-rw-r--r--activemodel/test/cases/observing_test.rb2
-rw-r--r--activerecord/CHANGELOG5
-rw-r--r--activerecord/lib/active_record.rb4
-rw-r--r--activerecord/lib/active_record/observer.rb26
-rw-r--r--activerecord/lib/active_record/railtie.rb10
-rw-r--r--activerecord/lib/rails/generators/active_record.rb5
-rwxr-xr-xactiverecord/test/cases/base_test.rb5
-rw-r--r--activerecord/test/cases/callbacks_observers_test.rb37
-rw-r--r--activerecord/test/cases/fixtures_test.rb2
-rw-r--r--activerecord/test/cases/lifecycle_test.rb54
-rw-r--r--activerecord/test/cases/xml_serialization_test.rb3
-rw-r--r--activerecord/test/fixtures/binaries.yml3
-rw-r--r--activesupport/lib/active_support/cache/memory_store.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/benchmark.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/string/conversions.rb22
-rw-r--r--activesupport/lib/active_support/core_ext/string/multibyte.rb7
-rw-r--r--activesupport/lib/active_support/locale/en.yml5
-rw-r--r--activesupport/lib/active_support/railtie.rb35
-rw-r--r--activesupport/lib/active_support/rescuable.rb1
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb5
-rw-r--r--activesupport/test/caching_test.rb7
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb12
-rw-r--r--activesupport/test/time_zone_test.rb11
-rw-r--r--railties/guides/source/active_support_core_extensions.textile4
-rw-r--r--railties/guides/source/command_line.textile42
-rw-r--r--railties/guides/source/getting_started.textile36
-rw-r--r--railties/guides/source/initialization.textile4
-rw-r--r--railties/guides/source/performance_testing.textile20
-rw-r--r--railties/guides/source/rails_on_rack.textile22
-rw-r--r--railties/guides/source/testing.textile30
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt4
-rw-r--r--railties/test/generators/migration_generator_test.rb13
-rw-r--r--railties/test/railties/i18n_railtie_test.rb86
59 files changed, 476 insertions, 232 deletions
diff --git a/actionmailer/lib/action_mailer/old_api.rb b/actionmailer/lib/action_mailer/old_api.rb
index b2111209c7..79d024a350 100644
--- a/actionmailer/lib/action_mailer/old_api.rb
+++ b/actionmailer/lib/action_mailer/old_api.rb
@@ -1,3 +1,4 @@
+require 'active_support/concern'
require 'active_support/core_ext/object/try'
require 'active_support/core_ext/object/blank'
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 388169d981..064e06bf92 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
+* Add support for shorthand routes like /projects/status(.:format) #4423 [Diego Carrion]
+
* Changed translate helper so that it doesn’t mark every translation as safe HTML. Only keys with a "_html" suffix and keys named "html" are considered to be safe HTML. All other translations are left untouched. [Craig Davey]
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index ed5b7e1e93..a5abe9be10 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -23,6 +23,6 @@ Gem::Specification.new do |s|
s.add_dependency('activemodel', version)
s.add_dependency('rack', '~> 1.1.0')
s.add_dependency('rack-test', '~> 0.5.0')
- s.add_dependency('rack-mount', '~> 0.6.0')
+ s.add_dependency('rack-mount', '~> 0.6.3')
s.add_dependency('erubis', '~> 2.6.5')
end
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index b3fa129929..0da0ca1893 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -63,8 +63,9 @@ module ActionController #:nodoc:
included do
extend ConfigMethods
- @@perform_caching = true
- cattr_accessor :perform_caching
+ delegate :perform_caching, :perform_caching=, :to => :config
+ singleton_class.delegate :perform_caching, :perform_caching=, :to => :config
+ self.perform_caching = true
end
diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb
index 21a424e6f0..20df3a1a69 100644
--- a/actionpack/lib/action_controller/caching/pages.rb
+++ b/actionpack/lib/action_controller/caching/pages.rb
@@ -44,8 +44,8 @@ module ActionController #:nodoc:
# For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>Rails.root + "/public"</tt>). Changing
# this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
# web server to look in the new location for cached files.
- @@page_cache_directory = ''
- cattr_accessor :page_cache_directory
+ singleton_class.delegate :page_cache_directory, :page_cache_directory=, :to => :config
+ self.page_cache_directory = ''
##
# :singleton-method:
@@ -53,8 +53,8 @@ module ActionController #:nodoc:
# order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
# If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
# extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
- @@page_cache_extension = '.html'
- cattr_accessor :page_cache_extension
+ singleton_class.delegate :page_cache_extension, :page_cache_extension=, :to => :config
+ self.page_cache_extension = '.html'
end
module ClassMethods
@@ -116,7 +116,7 @@ module ActionController #:nodoc:
# Expires the page that was cached with the +options+ as a key. Example:
# expire_page :controller => "lists", :action => "show"
def expire_page(options = {})
- return unless perform_caching
+ return unless self.class.perform_caching
if options.is_a?(Hash)
if options[:action].is_a?(Array)
@@ -135,7 +135,7 @@ module ActionController #:nodoc:
# If no options are provided, the requested url is used. Example:
# cache_page "I'm the cached content", :controller => "lists", :action => "show"
def cache_page(content = nil, options = nil)
- return unless perform_caching && caching_allowed
+ return unless self.class.perform_caching && caching_allowed
path = case options
when Hash
diff --git a/actionpack/lib/action_controller/deprecated/base.rb b/actionpack/lib/action_controller/deprecated/base.rb
index b817bf42bc..57203ce95f 100644
--- a/actionpack/lib/action_controller/deprecated/base.rb
+++ b/actionpack/lib/action_controller/deprecated/base.rb
@@ -146,12 +146,15 @@ module ActionController
extend DeprecatedBehavior
- deprecated_config_writer :session_store
deprecated_config_writer :session_options
- deprecated_config_accessor :perform_caching
- deprecated_config_accessor :relative_url_root, "relative_url_root is ineffective. Please stop using it"
+ deprecated_config_writer :session_store
+
deprecated_config_accessor :assets_dir
+ deprecated_config_accessor :asset_path
+ deprecated_config_accessor :helpers_path
deprecated_config_accessor :javascripts_dir
+ deprecated_config_accessor :page_cache_directory
+ deprecated_config_accessor :relative_url_root, "relative_url_root is ineffective. Please stop using it"
deprecated_config_accessor :stylesheets_dir
delegate :consider_all_requests_local, :consider_all_requests_local=,
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index dfd8e75bcc..b3758218a2 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -1,5 +1,6 @@
require 'rack/session/abstract/id'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/object/to_query'
module ActionController
module TemplateAssertions
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 362e5ec970..8b730a97ee 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -1,6 +1,7 @@
require 'digest/md5'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/class/attribute_accessors'
module ActionDispatch # :nodoc:
# Represents an HTTP response generated by a controller action. One can use
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index 1524b00d5b..09fb1f998a 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -1,3 +1,4 @@
+require 'active_support/core_ext/hash/conversions.rb'
require 'action_dispatch/http/request'
module ActionDispatch
diff --git a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb
index e8c2e74314..1b676669e2 100644
--- a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/object/with_options'
module ActionDispatch
module Routing
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 53585740ce..ef2826a4e8 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -66,8 +66,8 @@ module ActionDispatch
path = normalize_path(path)
if using_match_shorthand?(path, options)
- options[:to] ||= path[1..-1].sub(%r{/([^/]*)$}, '#\1')
- options[:as] ||= path[1..-1].gsub("/", "_")
+ options[:to] ||= path[1..-1].sub(%r{/([^/]*)$}, '#\1').sub(%r{\(.*\)}, '')
+ options[:as] ||= path[1..-1].gsub("/", "_").sub(%r{\(.*\)}, '')
end
[ path, options ]
@@ -80,7 +80,7 @@ module ActionDispatch
# match "account/overview"
def using_match_shorthand?(path, options)
- path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w\/]+$}
+ path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w+/?]+(\(.*\))*$}
end
def normalize_path(path)
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index f1965f38b9..fdbff74071 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -1,5 +1,6 @@
require 'rack/mount'
require 'forwardable'
+require 'active_support/core_ext/object/to_query'
require 'action_dispatch/routing/deprecated_mapper'
module ActionDispatch
diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb
index d4eecac2de..79f309cae7 100644
--- a/actionpack/lib/action_dispatch/testing/test_process.rb
+++ b/actionpack/lib/action_dispatch/testing/test_process.rb
@@ -3,13 +3,13 @@ require 'action_dispatch/middleware/flash'
module ActionDispatch
module TestProcess
def assigns(key = nil)
- assigns = {}
+ assigns = {}.with_indifferent_access
@controller.instance_variable_names.each do |ivar|
next if ActionController::Base.protected_instance_variables.include?(ivar)
assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar)
end
- key.nil? ? assigns : assigns[key.to_s]
+ key.nil? ? assigns : assigns[key]
end
def session
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 105f4565e6..8f8db548c3 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -444,7 +444,7 @@ module ActionView
body << content_tag(:optgroup, options_for_select(group[1], selected_key), :label => group[0])
end
- body
+ body.html_safe
end
# Returns a string of option tags for pretty much any time zone in the
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 0b748d700b..4ffc5ea127 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -504,7 +504,7 @@ module ActionView
"document.write('#{content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
string << sprintf("%%%x", c)
end
- "<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>"
+ "<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>".html_safe
elsif encode == "hex"
email_address_encoded = ''
email_address_obfuscated.each_byte do |c|
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index ddea9cfd92..beda7743bf 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/object/blank'
+require 'action_controller'
require 'action_controller/test_case'
require 'action_view'
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 217260fdcd..115cc91467 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -53,16 +53,16 @@ class PageCachingTest < ActionController::TestCase
def setup
super
- ActionController::Base.perform_caching = true
-
@request = ActionController::TestRequest.new
@request.host = 'hostname.com'
@request.env.delete('PATH_INFO')
- @response = ActionController::TestResponse.new
@controller = PageCachingTestController.new
+ @controller.perform_caching = true
@controller.cache_store = :file_store, FILE_STORE_PATH
+ @response = ActionController::TestResponse.new
+
@params = {:controller => 'posts', :action => 'index', :only_path => true}
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
@@ -71,7 +71,7 @@ class PageCachingTest < ActionController::TestCase
def teardown
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
- ActionController::Base.perform_caching = false
+ @controller.perform_caching = false
end
def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
@@ -538,9 +538,9 @@ end
class FragmentCachingTest < ActionController::TestCase
def setup
super
- ActionController::Base.perform_caching = true
@store = ActiveSupport::Cache::MemoryStore.new
@controller = FragmentCachingTestController.new
+ @controller.perform_caching = true
@controller.cache_store = @store
@params = {:controller => 'posts', :action => 'index'}
@request = ActionController::TestRequest.new
@@ -564,7 +564,7 @@ class FragmentCachingTest < ActionController::TestCase
end
def test_read_fragment_with_caching_disabled
- ActionController::Base.perform_caching = false
+ @controller.perform_caching = false
@store.write('views/name', 'value')
assert_nil @controller.read_fragment('name')
end
@@ -576,7 +576,7 @@ class FragmentCachingTest < ActionController::TestCase
end
def test_fragment_exist_with_caching_disabled
- ActionController::Base.perform_caching = false
+ @controller.perform_caching = false
@store.write('views/name', 'value')
assert !@controller.fragment_exist?('name')
assert !@controller.fragment_exist?('other_name')
@@ -590,7 +590,7 @@ class FragmentCachingTest < ActionController::TestCase
def test_write_fragment_with_caching_disabled
assert_nil @store.read('views/name')
- ActionController::Base.perform_caching = false
+ @controller.perform_caching = false
assert_equal 'value', @controller.write_fragment('name', 'value')
assert_nil @store.read('views/name')
end
@@ -614,7 +614,7 @@ class FragmentCachingTest < ActionController::TestCase
end
def test_fragment_for_with_disabled_caching
- ActionController::Base.perform_caching = false
+ @controller.perform_caching = false
@store.write('views/expensive', 'fragment content')
fragment_computed = false
@@ -688,9 +688,9 @@ end
class FunctionalFragmentCachingTest < ActionController::TestCase
def setup
super
- ActionController::Base.perform_caching = true
@store = ActiveSupport::Cache::MemoryStore.new
@controller = FunctionalCachingController.new
+ @controller.perform_caching = true
@controller.cache_store = @store
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb
index 20d3e77b6e..b11eba2f89 100644
--- a/actionpack/test/controller/log_subscriber_test.rb
+++ b/actionpack/test/controller/log_subscriber_test.rb
@@ -143,7 +143,7 @@ class ACLogSubscriberTest < ActionController::TestCase
end
def test_with_fragment_cache
- ActionController::Base.perform_caching = true
+ @controller.config.perform_caching = true
get :with_fragment_cache
wait
@@ -151,11 +151,11 @@ class ACLogSubscriberTest < ActionController::TestCase
assert_match /Exist fragment\? views\/foo/, logs[1]
assert_match /Write fragment views\/foo/, logs[2]
ensure
- ActionController::Base.perform_caching = true
+ @controller.config.perform_caching = true
end
def test_with_page_cache
- ActionController::Base.perform_caching = true
+ @controller.config.perform_caching = true
get :with_page_cache
wait
@@ -163,7 +163,7 @@ class ACLogSubscriberTest < ActionController::TestCase
assert_match /Write page/, logs[1]
assert_match /\/index\.html/, logs[1]
ensure
- ActionController::Base.perform_caching = true
+ @controller.config.perform_caching = true
end
def logs
diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb
index 53cd3f0801..c8ba8bcaf3 100644
--- a/actionpack/test/controller/mime_responds_test.rb
+++ b/actionpack/test/controller/mime_responds_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'controller/fake_models'
+require 'active_support/core_ext/hash/conversions'
class RespondToController < ActionController::Base
layout :set_layout
diff --git a/actionpack/test/controller/new_base/content_type_test.rb b/actionpack/test/controller/new_base/content_type_test.rb
index 700b71a7f3..33c2e442f0 100644
--- a/actionpack/test/controller/new_base/content_type_test.rb
+++ b/actionpack/test/controller/new_base/content_type_test.rb
@@ -21,17 +21,11 @@ module ContentType
self.view_paths = [ActionView::FixtureResolver.new(
"content_type/implied/i_am_html_erb.html.erb" => "Hello world!",
- "content_type/implied/i_am_xml_erb.xml.erb" => "<xml>Hello world!</xml>",
+ "content_type/implied/i_am_xml_erb.xml.erb" => "<xml>Hello world!</xml>",
"content_type/implied/i_am_html_builder.html.builder" => "xml.p 'Hello'",
- "content_type/implied/i_am_xml_builder.xml.builder" => "xml.awesome 'Hello'",
- "content_type/implied/i_am_rjs_in_html.html.erb" => "<%= render 'i_am_rjs_partial' %>",
- "content_type/implied/_i_am_rjs_partial.js.rjs" => ""
+ "content_type/implied/i_am_xml_builder.xml.builder" => "xml.awesome 'Hello'",
+ "content_type/implied/i_am_js_rjs.js.rjs" => "page.alert 'hello'"
)]
-
- def i_am_html_erb() end
- def i_am_xml_erb() end
- def i_am_html_builder() end
- def i_am_xml_builder() end
end
class CharsetController < ActionController::Base
@@ -94,10 +88,10 @@ module ContentType
assert_header "Content-Type", "application/xml; charset=utf-8"
end
- test "sets Content-Type as text/html when rendering *.html.erb with a RJS partial" do
- get "/content_type/implied/i_am_rjs_in_html"
+ test "sets Content-Type as text/javascript when rendering *.js" do
+ get "/content_type/implied/i_am_js_rjs", "format" => "js"
- assert_header "Content-Type", "text/html; charset=utf-8"
+ assert_header "Content-Type", "text/javascript; charset=utf-8"
end
end
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index 6f1ce2fef7..f9fc7a0976 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -113,6 +113,11 @@ XML
render :nothing => true
end
+ def test_assigns
+ @foo = "foo"
+ render :nothing => true
+ end
+
private
def rescue_action(e)
raise e
@@ -230,6 +235,17 @@ XML
assert_equal "OK", @response.body
end
+ def test_assigns
+ process :test_assigns
+ # assigns can be accessed using assigns(key)
+ # or assigns[key], where key is a string or
+ # a symbol
+ assert_equal "foo", assigns(:foo)
+ assert_equal "foo", assigns("foo")
+ assert_equal "foo", assigns[:foo]
+ assert_equal "foo", assigns["foo"]
+ end
+
def test_assert_tag_tag
process :test_html_output
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 8940990712..5bca476b27 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -54,6 +54,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
match "/local/:action", :controller => "local"
+ match "/projects/status(.:format)"
+
constraints(:ip => /192\.168\.1\.\d\d\d/) do
get 'admin' => "queenbee#index"
end
@@ -426,6 +428,13 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_projects_status
+ with_test_routes do
+ assert_equal '/projects/status', url_for(:controller => 'projects', :action => 'status', :only_path => true)
+ assert_equal '/projects/status.json', url_for(:controller => 'projects', :action => 'status', :format => 'json', :only_path => true)
+ end
+ end
+
def test_projects
with_test_routes do
get '/projects'
diff --git a/actionpack/test/template/erb_util_test.rb b/actionpack/test/template/erb_util_test.rb
index 06155b1f30..d3129d0e1a 100644
--- a/actionpack/test/template/erb_util_test.rb
+++ b/actionpack/test/template/erb_util_test.rb
@@ -4,12 +4,12 @@ class ErbUtilTest < Test::Unit::TestCase
include ERB::Util
ERB::Util::HTML_ESCAPE.each do |given, expected|
- define_method "test_html_escape_#{expected.gsub /\W/, ''}" do
+ define_method "test_html_escape_#{expected.gsub(/\W/, '')}" do
assert_equal expected, html_escape(given)
end
unless given == '"'
- define_method "test_json_escape_#{expected.gsub /\W/, ''}" do
+ define_method "test_json_escape_#{expected.gsub(/\W/, '')}" do
assert_equal ERB::Util::JSON_ESCAPE[given], json_escape(given)
end
end
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 5799e3db53..98503c32fd 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -207,6 +207,10 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_grouped_options_for_select_returns_html_safe_string
+ assert grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]]).html_safe?
+ end
+
def test_optgroups_with_with_options_with_hash
assert_dom_equal(
"<optgroup label=\"Europe\"><option value=\"Denmark\">Denmark</option>\n<option value=\"Germany\">Germany</option></optgroup><optgroup label=\"North America\"><option value=\"United States\">United States</option>\n<option value=\"Canada\">Canada</option></optgroup>",
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index de63030714..4474949749 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -356,11 +356,15 @@ class UrlHelperTest < ActiveSupport::TestCase
end
def test_mail_to_with_javascript
- assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript")
+ snippet = mail_to("me@domain.com", "My email", :encode => "javascript")
+ assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", snippet
+ assert snippet.html_safe?
end
def test_mail_to_with_javascript_unicode
- assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%75%6e%69%63%6f%64%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%22%3e%c3%ba%6e%69%63%6f%64%65%3c%2f%61%3e%27%29%3b'))</script>", mail_to("unicode@example.com", "únicode", :encode => "javascript")
+ snippet = mail_to("unicode@example.com", "únicode", :encode => "javascript")
+ assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%75%6e%69%63%6f%64%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%22%3e%c3%ba%6e%69%63%6f%64%65%3c%2f%61%3e%27%29%3b'))</script>", snippet
+ assert snippet.html_safe
end
def test_mail_with_options
diff --git a/activemodel/lib/active_model/observing.rb b/activemodel/lib/active_model/observing.rb
index ed6fb47c7e..74a33d45ab 100644
--- a/activemodel/lib/active_model/observing.rb
+++ b/activemodel/lib/active_model/observing.rb
@@ -1,4 +1,3 @@
-require 'observer'
require 'singleton'
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/module/aliasing'
@@ -8,10 +7,6 @@ module ActiveModel
module Observing
extend ActiveSupport::Concern
- included do
- extend Observable
- end
-
module ClassMethods
# Activates the observers assigned. Examples:
#
@@ -41,6 +36,26 @@ module ActiveModel
observers.each { |o| instantiate_observer(o) }
end
+ def add_observer(observer)
+ unless observer.respond_to? :update
+ raise ArgumentError, "observer needs to respond to `update'"
+ end
+ @observer_instances ||= []
+ @observer_instances << observer
+ end
+
+ def notify_observers(*arg)
+ if defined? @observer_instances
+ for observer in @observer_instances
+ observer.update(*arg)
+ end
+ end
+ end
+
+ def count_observers
+ @observer_instances.size
+ end
+
protected
def instantiate_observer(observer) #:nodoc:
# string/symbol
@@ -56,7 +71,6 @@ module ActiveModel
# Notify observers when the observed class is subclassed.
def inherited(subclass)
super
- changed
notify_observers :observed_class_inherited, subclass
end
end
@@ -70,7 +84,6 @@ module ActiveModel
# notify_observers(:after_save)
# end
def notify_observers(method)
- self.class.changed
self.class.notify_observers(method, self)
end
end
diff --git a/activemodel/test/cases/observing_test.rb b/activemodel/test/cases/observing_test.rb
index e23bda0528..63686843b6 100644
--- a/activemodel/test/cases/observing_test.rb
+++ b/activemodel/test/cases/observing_test.rb
@@ -121,13 +121,11 @@ class ObserverTest < ActiveModel::TestCase
foo = Foo.new
FooObserver.instance.stub = stub
FooObserver.instance.stub.expects(:event_with).with(foo)
- Foo.send(:changed)
Foo.send(:notify_observers, :on_spec, foo)
end
test "skips nonexistent observer event" do
foo = Foo.new
- Foo.send(:changed)
Foo.send(:notify_observers, :whatever, foo)
end
end
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 8ecef6574f..c0c4df5035 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,3 +1,8 @@
+*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
+
+* Observers can prevent records from saving by returning false, just like before_save and friends. #4087 [Mislav Marohnić]
+
+
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
* Add Relation extensions. [Pratik Naik]
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 8a1aa50e24..6a6485f35e 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -29,7 +29,9 @@ activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
require 'active_support'
+require 'active_support/i18n'
require 'active_model'
+require 'arel'
module ActiveRecord
extend ActiveSupport::Autoload
@@ -117,4 +119,4 @@ ActiveSupport.on_load(:active_record) do
Arel::Table.engine = Arel::Sql::Engine.new(self)
end
-I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' \ No newline at end of file
+I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb
index 0fbb1f0261..ed0f039597 100644
--- a/activerecord/lib/active_record/observer.rb
+++ b/activerecord/lib/active_record/observer.rb
@@ -96,7 +96,8 @@ module ActiveRecord
end
def self.method_added(method)
- self.observed_methods += [method] if ActiveRecord::Callbacks::CALLBACKS.include?(method.to_sym)
+ method = method.to_sym
+ observed_methods << method if ActiveRecord::Callbacks::CALLBACKS.include?(method)
end
protected
@@ -104,16 +105,27 @@ module ActiveRecord
observed_classes.sum([]) { |klass| klass.send(:subclasses) }
end
+ def observe_callbacks?
+ self.class.observed_methods.any?
+ end
+
def add_observer!(klass)
super
+ define_callbacks klass if observe_callbacks?
+ end
+
+ def define_callbacks(klass)
+ existing_methods = klass.instance_methods.map(&:to_sym)
+ observer = self
+ observer_name = observer.class.name.underscore.gsub('/', '__')
- # Check if a notifier callback was already added to the given class. If
- # it was not, add it.
self.class.observed_methods.each do |method|
- callback = :"_notify_observers_for_#{method}"
- if (klass.instance_methods & [callback, callback.to_s]).empty?
- klass.class_eval "def #{callback}; notify_observers(:#{method}); end"
- klass.send(method, callback)
+ callback = :"_notify_#{observer_name}_for_#{method}"
+ unless existing_methods.include? callback
+ klass.send(:define_method, callback) do # def _notify_user_observer_for_before_save
+ observer.update(method, self) # observer.update(:before_save, self)
+ end # end
+ klass.send(method, callback) # before_save :_notify_user_observer_for_before_save
end
end
end
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 04c4a9c153..878a4dac09 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -70,9 +70,7 @@ module ActiveRecord
end
end
- initializer "active_record.load_observers" do
- ActiveSupport.on_load(:active_record) { instantiate_observers }
-
+ initializer "active_record.add_observer_hook", :after=>"active_record.set_configs" do |app|
ActiveSupport.on_load(:active_record) do
ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do
ActiveRecord::Base.instantiate_observers
@@ -80,6 +78,12 @@ module ActiveRecord
end
end
+ initializer "active_record.instantiate_observers", :after=>"active_record.initialize_database" do
+ ActiveSupport.on_load(:active_record) do
+ instantiate_observers
+ end
+ end
+
initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
ActiveSupport.on_load(:active_record) do
unless app.config.cache_classes
diff --git a/activerecord/lib/rails/generators/active_record.rb b/activerecord/lib/rails/generators/active_record.rb
index 1ca838b4f2..d2b1e86857 100644
--- a/activerecord/lib/rails/generators/active_record.rb
+++ b/activerecord/lib/rails/generators/active_record.rb
@@ -19,10 +19,11 @@ module ActiveRecord
# Implement the required interface for Rails::Generators::Migration.
#
def self.next_migration_number(dirname) #:nodoc:
+ next_migration_number = current_migration_number(dirname) + 1
if ActiveRecord::Base.timestamped_migrations
- Time.now.utc.strftime("%Y%m%d%H%M%S")
+ [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
else
- "%.3d" % (current_migration_number(dirname) + 1)
+ "%.3d" % next_migration_number
end
end
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 1c3655b587..2f4243a6aa 100755
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -2054,7 +2054,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_base_subclasses_is_public_method
- assert ActiveRecord::Base.public_methods.include?("subclasses")
+ assert ActiveRecord::Base.public_methods.map(&:to_sym).include?(:subclasses)
end
def test_find_on_abstract_base_class_doesnt_use_type_condition
@@ -2095,7 +2095,8 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal written_on_in_current_timezone, xml.elements["//written-on"].text
assert_equal "datetime" , xml.elements["//written-on"].attributes['type']
- assert_equal "--- Have a nice day\n" , xml.elements["//content"].text
+ assert_match(/^--- Have a nice day\n/ , xml.elements["//content"].text)
+ assert_equal 'Have a nice day' , YAML.load(xml.elements["//content"].text)
assert_equal "yaml" , xml.elements["//content"].attributes['type']
assert_equal "david@loudthinking.com", xml.elements["//author-email-address"].text
diff --git a/activerecord/test/cases/callbacks_observers_test.rb b/activerecord/test/cases/callbacks_observers_test.rb
deleted file mode 100644
index 52ce384844..0000000000
--- a/activerecord/test/cases/callbacks_observers_test.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require "cases/helper"
-
-class Comment < ActiveRecord::Base
- attr_accessor :callers
-
- before_validation :record_callers
-
- after_validation do
- record_callers
- end
-
- def record_callers
- callers << self.class if callers
- end
-end
-
-class CommentObserver < ActiveRecord::Observer
- attr_accessor :callers
-
- def after_validation(model)
- callers << self.class if callers
- end
-end
-
-class CallbacksObserversTest < ActiveRecord::TestCase
- def test_model_callbacks_fire_before_observers_are_notified
- callers = []
-
- comment = Comment.new
- comment.callers = callers
-
- CommentObserver.instance.callers = callers
-
- comment.valid?
- assert_equal [Comment, Comment, CommentObserver], callers, "model callbacks did not fire before observers were notified"
- end
-end
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index e78b522b65..d24283fe4e 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -26,7 +26,7 @@ class FixturesTest < ActiveRecord::TestCase
FIXTURES = %w( accounts binaries companies customers
developers developers_projects entrants
movies projects subscribers topics tasks )
- MATCH_ATTRIBUTE_NAME = /[a-zA-Z][-_\w]*/
+ MATCH_ATTRIBUTE_NAME = /[a-zA-Z][-\w]*/
def test_clean_fixtures
FIXTURES.each do |name|
diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb
index fcad3e90d3..233338498f 100644
--- a/activerecord/test/cases/lifecycle_test.rb
+++ b/activerecord/test/cases/lifecycle_test.rb
@@ -3,9 +3,18 @@ require 'models/topic'
require 'models/developer'
require 'models/reply'
require 'models/minimalistic'
+require 'models/comment'
class SpecialDeveloper < Developer; end
+class SalaryChecker < ActiveRecord::Observer
+ observe :special_developer
+
+ def before_save(developer)
+ return developer.salary > 80000
+ end
+end
+
class TopicaAuditor < ActiveRecord::Observer
observe :topic
@@ -57,6 +66,28 @@ class MultiObserver < ActiveRecord::Observer
end
end
+class ValidatedComment < Comment
+ attr_accessor :callers
+
+ before_validation :record_callers
+
+ after_validation do
+ record_callers
+ end
+
+ def record_callers
+ callers << self.class if callers
+ end
+end
+
+class ValidatedCommentObserver < ActiveRecord::Observer
+ attr_accessor :callers
+
+ def after_validation(model)
+ callers << self.class if callers
+ end
+end
+
class LifecycleTest < ActiveRecord::TestCase
fixtures :topics, :developers, :minimalistics
@@ -125,4 +156,27 @@ class LifecycleTest < ActiveRecord::TestCase
def test_invalid_observer
assert_raise(ArgumentError) { Topic.observers = Object.new; Topic.instantiate_observers }
end
+
+ test "model callbacks fire before observers are notified" do
+ callers = []
+
+ comment = ValidatedComment.new
+ comment.callers = ValidatedCommentObserver.instance.callers = callers
+
+ comment.valid?
+ assert_equal [ValidatedComment, ValidatedComment, ValidatedCommentObserver], callers,
+ "model callbacks did not fire before observers were notified"
+ end
+
+ test "able to save developer" do
+ SalaryChecker.instance # activate
+ developer = SpecialDeveloper.new :name => 'Roger', :salary => 100000
+ assert developer.save, "developer with normal salary failed to save"
+ end
+
+ test "unable to save developer with low salary" do
+ SalaryChecker.instance # activate
+ developer = SpecialDeveloper.new :name => 'Rookie', :salary => 50000
+ assert !developer.save, "allowed to save a developer with too low salary"
+ end
end
diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb
index 2849ff11b7..b1c75ec8cd 100644
--- a/activerecord/test/cases/xml_serialization_test.rb
+++ b/activerecord/test/cases/xml_serialization_test.rb
@@ -4,6 +4,7 @@ require 'models/post'
require 'models/author'
require 'models/tagging'
require 'models/comment'
+require 'models/company_in_module'
class XmlSerializationTest < ActiveRecord::TestCase
def test_should_serialize_default_root
@@ -79,7 +80,7 @@ class DefaultXmlSerializationTest < ActiveRecord::TestCase
end
def test_should_serialize_yaml
- assert_match %r{<preferences type=\"yaml\">--- \n:gem: ruby\n</preferences>}, @xml
+ assert_match %r{<preferences type=\"yaml\">---\s?\n:gem: ruby\n</preferences>}, @xml
end
end
diff --git a/activerecord/test/fixtures/binaries.yml b/activerecord/test/fixtures/binaries.yml
index d150c5708e..ec8f2facdc 100644
--- a/activerecord/test/fixtures/binaries.yml
+++ b/activerecord/test/fixtures/binaries.yml
@@ -1,6 +1,7 @@
flowers:
id: 1
- data: !binary | /9j/4AAQSkZJRgABAQEASABIAAD/2wBDAA0JCQoKCg4LCw4UDQsNFBcRDg4R
+ data: !binary |-
+ /9j/4AAQSkZJRgABAQEASABIAAD/2wBDAA0JCQoKCg4LCw4UDQsNFBcRDg4R
FxsVFRUVFRsbFRcXFxcVGxoeICEgHhonJyoqJyc1NTU1NTY2NjY2NjY2Njb/
2wBDAQ4NDRERERcRERcXExQTFx0ZGhoZHSYdHR4dHSYsJCAgICAkLCgrJiYm
KygvLywsLy82NjY2NjY2NjY2NjY2Njb/wAARCACvAIMDAREAAhEBAxEB/8QA
diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb
index e6085d97ec..379922f986 100644
--- a/activesupport/lib/active_support/cache/memory_store.rb
+++ b/activesupport/lib/active_support/cache/memory_store.rb
@@ -21,6 +21,12 @@ module ActiveSupport
@data = {}
end
+ def read_multi(*names)
+ results = {}
+ names.each { |n| results[n] = read(n) }
+ results
+ end
+
def read(name, options = nil)
super do
@data[name]
@@ -45,7 +51,7 @@ module ActiveSupport
end
end
- def exist?(name,options = nil)
+ def exist?(name, options = nil)
super do
@data.has_key?(name)
end
diff --git a/activesupport/lib/active_support/core_ext/benchmark.rb b/activesupport/lib/active_support/core_ext/benchmark.rb
index ae57b152e8..2d110155a5 100644
--- a/activesupport/lib/active_support/core_ext/benchmark.rb
+++ b/activesupport/lib/active_support/core_ext/benchmark.rb
@@ -1,18 +1,6 @@
require 'benchmark'
class << Benchmark
- # Earlier Ruby had a slower implementation.
- if RUBY_VERSION < '1.8.7'
- remove_method :realtime
-
- def realtime
- r0 = Time.now
- yield
- r1 = Time.now
- r1.to_f - r0.to_f
- end
- end
-
def ms
1000 * realtime { yield }
end
diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb
index 52946f9037..4cc36147f8 100644
--- a/activesupport/lib/active_support/core_ext/string/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/string/conversions.rb
@@ -3,7 +3,27 @@ require 'active_support/core_ext/time/publicize_conversion_methods'
require 'active_support/core_ext/time/calculations'
class String
- # 'a'.ord == 'a'[0] for Ruby 1.9 forward compatibility.
+ # Returns the codepoint of the first character of the string, assuming a
+ # single-byte character encoding:
+ #
+ # "a".ord # => 97
+ # "à".ord # => 224, in ISO-8859-1
+ #
+ # This method is defined in Ruby 1.8 for Ruby 1.9 forward compatibility on
+ # these character encodings.
+ #
+ # <tt>ActiveSupport::Multibyte::Chars#ord</tt> is forward compatible with
+ # Ruby 1.9 on UTF8 strings:
+ #
+ # "a".mb_chars.ord # => 97
+ # "à".mb_chars.ord # => 224, in UTF8
+ #
+ # Note that the 224 is different in both examples. In ISO-8859-1 "à" is
+ # represented as a single byte, 224. In UTF8 it is represented with two
+ # bytes, namely 195 and 160, but its Unicode codepoint is 224. If we
+ # call +ord+ on the UTF8 string "à" the return value will be 195. That is
+ # not an error, because UTF8 is unsupported, the call itself would be
+ # bogus.
def ord
self[0]
end unless method_defined?(:ord)
diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb
index 13208c6ee2..42e053d0f8 100644
--- a/activesupport/lib/active_support/core_ext/string/multibyte.rb
+++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb
@@ -49,13 +49,6 @@ class String
def is_utf8?
ActiveSupport::Multibyte::Chars.consumes?(self)
end
-
- unless '1.8.7 and later'.respond_to?(:chars)
- def chars
- ActiveSupport::Deprecation.warn('String#chars has been deprecated in favor of String#mb_chars.', caller)
- mb_chars
- end
- end
else
def mb_chars #:nodoc
self
diff --git a/activesupport/lib/active_support/locale/en.yml b/activesupport/lib/active_support/locale/en.yml
index e604c9ee8c..49ad192bf1 100644
--- a/activesupport/lib/active_support/locale/en.yml
+++ b/activesupport/lib/active_support/locale/en.yml
@@ -15,7 +15,10 @@ en:
month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
# Used in date_select and datime_select.
- order: [ :year, :month, :day ]
+ order:
+ - :year
+ - :month
+ - :day
time:
formats:
diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb
index b8d54ff839..0243157e35 100644
--- a/activesupport/lib/active_support/railtie.rb
+++ b/activesupport/lib/active_support/railtie.rb
@@ -33,6 +33,7 @@ module I18n
config.i18n = ActiveSupport::OrderedOptions.new
config.i18n.railties_load_path = []
config.i18n.load_path = []
+ config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
initializer "i18n.initialize" do
ActiveSupport.on_load(:i18n) do
@@ -53,6 +54,8 @@ module I18n
app.config.i18n.load_path.unshift(*value)
when :load_path
I18n.load_path += value
+ when :fallbacks
+ init_fallbacks(value) if value && validate_fallbacks(value)
else
I18n.send("#{setting}=", value)
end
@@ -60,5 +63,37 @@ module I18n
I18n.reload!
end
+
+ class << self
+ protected
+
+ def init_fallbacks(fallbacks)
+ include_fallbacks_module
+ args = case fallbacks
+ when ActiveSupport::OrderedOptions
+ [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact
+ when Hash, Array
+ Array.wrap(fallbacks)
+ else # TrueClass
+ []
+ end
+ I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
+ end
+
+ def include_fallbacks_module
+ I18n.backend.class.send(:include, I18n::Backend::Fallbacks)
+ end
+
+ def validate_fallbacks(fallbacks)
+ case fallbacks
+ when ActiveSupport::OrderedOptions
+ !fallbacks.empty?
+ when TrueClass, Array, Hash
+ true
+ else
+ raise "Unexpected fallback type #{fallbacks.inspect}"
+ end
+ end
+ end
end
end \ No newline at end of file
diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb
index e4c1651acf..cd6f92cdfe 100644
--- a/activesupport/lib/active_support/rescuable.rb
+++ b/activesupport/lib/active_support/rescuable.rb
@@ -1,3 +1,4 @@
+require 'active_support/concern'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/proc'
require 'active_support/core_ext/string/inflections'
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 03b324764b..9db6bbafca 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/object/try'
# The TimeZone class serves as a wrapper around TZInfo::Timezone instances. It allows us to do the following:
#
@@ -205,8 +206,8 @@ module ActiveSupport
if @utc_offset
@utc_offset
else
- @current_period ||= tzinfo.current_period
- @current_period.utc_offset
+ @current_period ||= tzinfo.try(:current_period)
+ @current_period.try(:utc_offset)
end
end
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index d96f8e1de5..e62e7ef9aa 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -185,6 +185,13 @@ class MemoryStoreTest < ActiveSupport::TestCase
@cache.write('foo', bar)
assert_nothing_raised { bar.gsub!(/.*/, 'baz') }
end
+
+ def test_multi_get
+ @cache.write('foo', 1)
+ @cache.write('goo', 2)
+ result = @cache.read_multi('foo', 'goo')
+ assert_equal({'foo' => 1, 'goo' => 2}, result)
+ end
end
uses_memcached 'memcached backed store' do
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 234e41c772..58ca215970 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -230,18 +230,6 @@ class CoreExtStringMultibyteTest < ActiveSupport::TestCase
assert !BYTE_STRING.is_utf8?
end
- if RUBY_VERSION < '1.8.7'
- def test_core_ext_adds_chars
- assert UNICODE_STRING.respond_to?(:chars)
- end
-
- def test_chars_warns_about_deprecation
- assert_deprecated("String#chars") do
- ''.chars
- end
- end
- end
-
if RUBY_VERSION < '1.9'
def test_mb_chars_returns_self_when_kcode_not_set
with_kcode('none') do
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index 68027f7c94..3b7fbb7808 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -274,6 +274,17 @@ class TimeZoneTest < Test::Unit::TestCase
assert_raise(ArgumentError) { ActiveSupport::TimeZone[false] }
end
+ def test_unknown_zone_shouldnt_have_tzinfo_nor_utc_offset
+ zone = ActiveSupport::TimeZone.create("bogus")
+ assert_nil zone.tzinfo
+ assert_nil zone.utc_offset
+ end
+
+ def test_unknown_zone_with_utc_offset
+ zone = ActiveSupport::TimeZone.create("bogus", -21_600)
+ assert_equal(-21_600, zone.utc_offset)
+ end
+
def test_new
assert_equal ActiveSupport::TimeZone["Central Time (US & Canada)"], ActiveSupport::TimeZone.new("Central Time (US & Canada)")
end
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index 398d2b2392..32738fe070 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -2662,10 +2662,6 @@ h3. Extensions to +Process+
...
-h3. Extensions to +Pathname+
-
-...
-
h3. Extensions to +File+
h4. +atomic_write+
diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile
index ebae320ebc..ab024d7fc3 100644
--- a/railties/guides/source/command_line.textile
+++ b/railties/guides/source/command_line.textile
@@ -64,12 +64,13 @@ Without any prodding of any kind, +rails server+ will run our new shiny Rails ap
<shell>
$ cd commandsapp
$ rails server
-=> Booting WEBrick...
-=> Rails 2.2.0 application started on http://0.0.0.0:3000
-=> Ctrl-C to shutdown server; call with --help for options
-[2008-11-04 10:11:38] INFO WEBrick 1.3.1
-[2008-11-04 10:11:38] INFO ruby 1.8.5 (2006-12-04) [i486-linux]
-[2008-11-04 10:11:38] INFO WEBrick::HTTPServer#start: pid=18994 port=3000
+=> Booting WEBrick
+=> Rails 3.0.0 application starting in development on http://0.0.0.0:3000
+=> Call with -d to detach
+=> Ctrl-C to shutdown server
+[2010-04-18 03:20:33] INFO WEBrick 1.3.1
+[2010-04-18 03:20:33] INFO ruby 1.8.7 (2010-01-10) [x86_64-linux]
+[2010-04-18 03:20:33] INFO WEBrick::HTTPServer#start: pid=26086 port=3000
</shell>
With just three commands we whipped up a Rails server listening on port 3000. Go to your browser and open "http://localhost:3000":http://localhost:3000, you will see a basic rails app running.
@@ -237,7 +238,7 @@ The migration requires that we *migrate*, that is, run some Ruby code (living in
<shell>
$ rake db:migrate
-(in /Users/mikel/rails_programs/commandsapp)
+(in /home/foobar/commandsapp)
== CreateHighScores: migrating ===============================================
-- create_table(:high_scores)
-> 0.0026s
@@ -320,21 +321,20 @@ h4. +about+
Check it: Version numbers for Ruby, RubyGems, Rails, the Rails subcomponents, your application's folder, the current Rails environment name, your app's database adapter, and schema version! +about+ is useful when you need to ask for help, check if a security patch might affect you, or when you need some stats for an existing Rails installation.
<shell>
-$ rails about
+$ rake about
About your application's environment
-Ruby version 1.8.6 (i486-linux)
-RubyGems version 1.3.1
-Rails version 2.2.0
-Active Record version 2.2.0
-Action Pack version 2.2.0
-Active Resource version 2.2.0
-Action Mailer version 2.2.0
-Active Support version 2.2.0
-Edge Rails revision unknown
-Application root /home/commandsapp
+Ruby version 1.8.7 (x86_64-linux)
+RubyGems version 1.3.6
+Rack version 1.1
+Rails version 3.0.0
+Active Record version 3.0.0
+Action Pack version 3.0.0
+Active Resource version 3.0.0
+Action Mailer version 3.0.0
+Active Support version 3.0.0
+Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::RemoteIp, Rack::Sendfile, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::MethodOverride, ActionDispatch::Head
+Application root /home/foobar/commandsapp
Environment development
-Database adapter sqlite3
-Database schema version 20081217073400
</shell>
h3. The Rails Advanced Command Line
@@ -526,7 +526,7 @@ You can get a list of Rake tasks available to you, which will often depend on yo
<shell>
rake --tasks
-(in /home/developer/commandsapp)
+(in /home/foobar/commandsapp)
rake db:abort_if_pending_migrations # Raises an error if there are pending migrations
rake db:charset # Retrieves the charset for the current environment's database
rake db:collation # Retrieves the collation for the current environment's database
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index cbace177f9..6052ac737a 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -87,7 +87,7 @@ Action View manages the views of your Rails application. It can create both HTML
h5. Action Dispatch
-Action Dispatch handles routing of web requests and dispatches them as you want, either to your application, any other Rack application.
+Action Dispatch handles routing of web requests and dispatches them as you want, either to your application or any other Rack application.
h5. Action Mailer
@@ -356,19 +356,18 @@ The scaffold generator will build 15 files in your application, along with some
|_.File |_.Purpose|
|db/migrate/20100207214725_create_posts.rb.rb |Migration to create the posts table in your database (your name will include a different timestamp)|
|app/models/post.rb |The Post model|
-|test/unit/post_test.rb |Unit testing harness for the posts model|
|test/fixtures/posts.yml |Dummy posts for use in testing|
|app/controllers/posts_controller.rb |The Posts controller|
|app/views/posts/index.html.erb |A view to display an index of all posts |
|app/views/posts/edit.html.erb |A view to edit an existing post|
|app/views/posts/show.html.erb |A view to display a single post|
|app/views/posts/new.html.erb |A view to create a new post|
-|app/views/posts/_form.html.erb |A view to control the overall look and feel of the other posts views|
-|app/views/layouts/posts.html.erb |A view to control the overall look and feel of the other posts views|
+|app/views/posts/_form.html.erb |A partial to control the overall look and feel of the form used in edit and new views|
+|app/helpers/posts_helper.rb |Helper functions to be used from the post views|
+|test/unit/post_test.rb |Unit testing harness for the posts model|
|test/functional/posts_controller_test.rb |Functional testing harness for the posts controller|
-|app/helpers/posts_helper.rb |Helper functions to be used from the posts views|
-|config/routes.rb |Edited to include routing information for posts|
|test/unit/helpers/posts_helper_test.rb |Unit testing harness for the posts helper|
+|config/routes.rb |Edited to include routing information for posts|
|public/stylesheets/scaffold.css |Cascading style sheet to make the scaffolded views look better|
h4. Running a Migration
@@ -395,7 +394,7 @@ class CreatePosts < ActiveRecord::Migration
end
</ruby>
-The above migration creates two methods, +up+, called when you run this migration into the database, and +down+ in case you need to reverse the changes made by this migration at a later date. The +up+ command in this case creates a +posts+ table with two string columns and a text column. It also is creating two timestamp fields to track record creation and updating. More information about Rails migrations can be found in the "Rails Database Migrations":migrations.html guide.
+The above migration creates two methods, +up+, called when you run this migration into the database, and +down+ in case you need to reverse the changes made by this migration at a later date. The +up+ command in this case creates a +posts+ table with two string columns and a text column. It also creates two timestamp fields to track record creation and updating. More information about Rails migrations can be found in the "Rails Database Migrations":migrations.html guide.
At this point, you can use a rake command to run the migration:
@@ -504,7 +503,7 @@ def index
end
</ruby>
-This code sets the +@posts+ instance variable to an array of all posts in the database. +Post.all+ calls the +Post+ model to return all of the posts that are currently in the database, with no limiting conditions.
++Post.all+ calls the +Post+ model to return all of the posts currently in the database. The result of this call is an array containing the posts which has been saved in an instance variable called +@posts+.
TIP: For more information on finding records with Active Record, see "Active Record Query Interface":active_record_querying.html.
@@ -551,19 +550,19 @@ TIP: For more details on the rendering process, see "Layouts and Rendering in Ra
h4. Customizing the Layout
-The view is only part of the story of how HTML is displayed in your web browser. Rails also has the concept of +layouts+, which are containers for views. When Rails renders a view to the browser, it does so by putting the view's HTML into a layout's HTML. The +rails generate scaffold+ command automatically created a default layout, +app/views/layouts/posts.html.erb+, for the posts. Open this layout in your editor and modify the +body+ tag:
+The view is only part of the story of how HTML is displayed in your web browser. Rails also has the concept of +layouts+, which are containers for views. When Rails renders a view to the browser, it does so by putting the view's HTML into a layout's HTML. In previous versions of Rails, the +rails generate scaffold+ command would automatically create a controller specific layout, like +app/views/layouts/posts.html.erb+, for the posts controller. However this has been changed in Rails 3.0. A application specific +layout+ is used for all the controllers and can be found in +app/views/layouts/application.html.erb+. Open this layout in your editor and modify the +body+ tag:
<erb>
<!DOCTYPE html>
<html>
<head>
- <title>Posts: <%= controller.action_name %></title>
- <%= stylesheet_link_tag 'scaffold' %>
+ <title>Blog</title>
+ <%= stylesheet_link_tag :all %>
+ <%= javascript_include_tag :defaults %>
+ <%= csrf_meta_tag %>
</head>
<body style="background: #EEEEEE;">
-<p class="notice"><%= notice %></p>
-
<%= yield %>
</body>
@@ -603,7 +602,16 @@ If you take a look at +views/posts/_form.html.erb+ file, you will see the follow
<erb>
<%= form_for(@post) do |f| %>
- <%= f.error_messages %>
+ <% if @post.errors.any? %>
+ <div id="errorExplanation">
+ <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
+ <ul>
+ <% @post.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
<div class="field">
<%= f.label :name %><br />
diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile
index e9480408f8..9182f89f5b 100644
--- a/railties/guides/source/initialization.textile
+++ b/railties/guides/source/initialization.textile
@@ -148,7 +148,7 @@ Here the only two gems we need are +rails+ and +sqlite3-ruby+, so it seems. This
* mime-types-1.16.gem
* polyglot-0.3.1.gem
* rack-1.1.0.gem
-* rack-mount-0.6.1.gem
+* rack-mount-0.6.3.gem
* rack-test-0.5.3.gem
* rails-3.0.0.beta1.gem
* railties-3.0.0.beta1.gem
@@ -3707,4 +3707,4 @@ The _activesupport/lib/active_support/ruby/shim.rb_ file requires methods that h
For more information see the ActiveSupport Extensions guide TODO: link to relevant sections for each method.
-And "the REXML security fix detailed here":[http://weblog.rubyonrails.org/2008/8/23/dos-vulnerabilities-in-rexml] \ No newline at end of file
+And "the REXML security fix detailed here":[http://weblog.rubyonrails.org/2008/8/23/dos-vulnerabilities-in-rexml]
diff --git a/railties/guides/source/performance_testing.textile b/railties/guides/source/performance_testing.textile
index f74b68b0ef..c02fabc0b2 100644
--- a/railties/guides/source/performance_testing.textile
+++ b/railties/guides/source/performance_testing.textile
@@ -246,16 +246,16 @@ Sample output of +BrowsingTest#test_homepage_wall_time.csv+:
<shell>
measurement,created_at,app,rails,ruby,platform
-0.00738224999999992,2009-01-08T03:40:29Z,,2.3.0.master.0744148,ruby-1.8.6.110,i686-darwin9.0.0
-0.00755874999999984,2009-01-08T03:46:18Z,,2.3.0.master.0744148,ruby-1.8.6.110,i686-darwin9.0.0
-0.00762099999999993,2009-01-08T03:49:25Z,,2.3.0.master.0744148,ruby-1.8.6.110,i686-darwin9.0.0
-0.00603075000000008,2009-01-08T04:03:29Z,,2.3.0.master.0744148,ruby-1.8.6.111,i686-darwin9.1.0
-0.00619899999999995,2009-01-08T04:03:53Z,,2.3.0.master.0744148,ruby-1.8.6.111,i686-darwin9.1.0
-0.00755449999999991,2009-01-08T04:04:55Z,,2.3.0.master.0744148,ruby-1.8.6.110,i686-darwin9.0.0
-0.00595999999999997,2009-01-08T04:05:06Z,,2.3.0.master.0744148,ruby-1.8.6.111,i686-darwin9.1.0
-0.00740450000000004,2009-01-09T03:54:47Z,,2.3.0.master.859e150,ruby-1.8.6.110,i686-darwin9.0.0
-0.00603150000000008,2009-01-09T03:54:57Z,,2.3.0.master.859e150,ruby-1.8.6.111,i686-darwin9.1.0
-0.00771250000000012,2009-01-09T15:46:03Z,,2.3.0.master.859e150,ruby-1.8.6.110,i686-darwin9.0.0
+0.00738224999999992,2009-01-08T03:40:29Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
+0.00755874999999984,2009-01-08T03:46:18Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
+0.00762099999999993,2009-01-08T03:49:25Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
+0.00603075000000008,2009-01-08T04:03:29Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
+0.00619899999999995,2009-01-08T04:03:53Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
+0.00755449999999991,2009-01-08T04:04:55Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
+0.00595999999999997,2009-01-08T04:05:06Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
+0.00740450000000004,2009-01-09T03:54:47Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
+0.00603150000000008,2009-01-09T03:54:57Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
+0.00771250000000012,2009-01-09T15:46:03Z,,3.0.0,ruby-1.8.7.249,x86_64-linux
</shell>
h5(#output-profiling). Profiling
diff --git a/railties/guides/source/rails_on_rack.textile b/railties/guides/source/rails_on_rack.textile
index d0d86e99f2..512be43668 100644
--- a/railties/guides/source/rails_on_rack.textile
+++ b/railties/guides/source/rails_on_rack.textile
@@ -247,7 +247,7 @@ class Poller
if env["PATH_INFO"] =~ /^\/poller/
[200, {"Content-Type" => "text/html"}, ["Hello, World!"]]
else
- [404, {"Content-Type" => "text/html"}, ["Not Found"]]
+ [404, {"Content-Type" => "text/html", "X-Cascade" => "pass"}, ["Not Found"]]
end
end
end
@@ -257,23 +257,13 @@ Metal applications within +app/metal+ folders in plugins will also be discovered
Metal applications are an optimization. You should make sure to "understand the related performance implications":http://weblog.rubyonrails.org/2008/12/20/performance-of-rails-metal before using it.
-h4. Execution Order
-
-All Metal Applications are executed by +Rails::Rack::Metal+ middleware, which is a part of the +ActionController::MiddlewareStack+ chain.
+WARNING: To continue the Metal chain execution, return an +X-Cascade+ HTTP header with a value of +pass+.
-Here's the primary method responsible for running the Metal applications:
+h4. Execution Order
-<ruby>
-def call(env)
- @metals.keys.each do |app|
- result = app.call(env)
- return result unless result[0].to_i == 404
- end
- @app.call(env)
-end
-</ruby>
+All Metal Applications are executed in alphabetical order of their filenames, so +aaa.rb+ will come before +bbb.rb+ in the metal chain.
-In the code above, +@metals+ is an ordered hash of metal applications. Due to the default alphabetical ordering, +aaa.rb+ will come before +bbb.rb+ in the metal chain.
+You can override the default ordering in your environment. Simply add a line like the following to +config/application.rb+
It is, however, possible to override the default ordering in your environment. Simply add a line like the following to +config/environment.rb+
@@ -283,8 +273,6 @@ config.metals = ["Bbb", "Aaa"]
Each string in the array should be the name of your metal class. If you do this then be warned that any metal applications not listed will not be loaded.
-WARNING: Metal applications cannot return the HTTP Status +404+ to a client, as it is used for continuing the Metal chain execution. Please use normal Rails controllers or a custom middleware if returning +404+ is a requirement.
-
h3. Resources
h4. Learning Rack
diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile
index c4f7ff8e92..206ed6e75c 100644
--- a/railties/guides/source/testing.textile
+++ b/railties/guides/source/testing.textile
@@ -108,7 +108,7 @@ tag is considered Ruby code. When this fixture is loaded, the +size+ attribute o
h5. Fixtures in Action
-Rails by default automatically loads all fixtures from the 'test/fixtures' folder for your unit and functional test. Loading involves three steps:
+Rails by default automatically loads all fixtures from the +test/fixtures+ folder for your unit and functional test. Loading involves three steps:
* Remove any existing data from the table corresponding to the fixture
* Load the fixture data into the table
@@ -142,7 +142,7 @@ In Rails, unit tests are what you write to test your models.
For this guide we will be using Rails _scaffolding_. It will create the model, a migration, controller and views for the new resource in a single operation. It will also create a full test suite following Rails best practices. I will be using examples from this generated code and would be supplementing it with additional examples where necessary.
-NOTE: For more information on Rails _scaffolding_, refer to "Getting Started with Rails":getting_started.html
+NOTE: For more information on Rails <i>scaffolding</i>, refer to "Getting Started with Rails":getting_started.html
When you use +rails generate scaffold+, for a resource among other things it creates a test stub in the +test/unit+ folder:
@@ -221,9 +221,9 @@ $ rake db:migrate
$ rake db:test:load
</shell>
-Above +rake db:migrate+ runs any pending migrations on the _development_ environment and updates +db/schema.rb+. +rake db:test:load+ recreates the test database from the current db/schema.rb. On subsequent attempts it is a good to first run +db:test:prepare+ as it first checks for pending migrations and warns you appropriately.
+Above +rake db:migrate+ runs any pending migrations on the _development_ environment and updates +db/schema.rb+. +rake db:test:load+ recreates the test database from the current +db/schema.rb+. On subsequent attempts it is a good to first run +db:test:prepare+ as it first checks for pending migrations and warns you appropriately.
-NOTE: +db:test:prepare+ will fail with an error if db/schema.rb doesn't exists.
+NOTE: +db:test:prepare+ will fail with an error if +db/schema.rb+ doesn't exists.
h5. Rake Tasks for Preparing your Application for Testing
@@ -256,7 +256,7 @@ This will run all the test methods from the test case.
You can also run a particular test method from the test case by using the +-n+ switch with the +test method name+.
-<pre>
+<shell>
$ ruby unit/post_test.rb -n test_truth
Loaded suite unit/post_test
@@ -265,7 +265,7 @@ Started
Finished in 0.023513 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
-</pre>
+</shell>
The +.+ (dot) above indicates a passing test. When a test fails you see an +F+; when a test throws an error you see an +E+ in its place. The last line of the output is the summary.
@@ -280,7 +280,7 @@ end
Let us run this newly added test.
-<pre>
+<shell>
$ ruby unit/post_test.rb -n test_should_not_save_post_without_title
Loaded suite -e
Started
@@ -292,7 +292,7 @@ test_should_not_save_post_without_title(PostTest) [/test/unit/post_test.rb:6]:
<false> is not true.
1 tests, 1 assertions, 1 failures, 0 errors
-</pre>
+</shell>
In the output, +F+ denotes a failure. You can see the corresponding trace shown under +1)+ along with the name of the failing test. The next few lines contain the stack trace followed by a message which mentions the actual value and the expected value by the assertion. The default assertion messages provide just enough information to help pinpoint the error. To make the assertion failure message more readable every assertion provides an optional message parameter, as shown here:
@@ -305,12 +305,12 @@ end
Running this test shows the friendlier assertion message:
-<pre>
+<shell>
1) Failure:
test_should_not_save_post_without_title(PostTest) [/test/unit/post_test.rb:6]:
Saved the post without a title.
<false> is not true.
-</pre>
+</shell>
Now to get this test to pass we can add a model level validation for the _title_ field.
@@ -322,7 +322,7 @@ end
Now the test should pass. Let us verify by running the test again:
-<pre>
+<shell>
$ ruby unit/post_test.rb -n test_should_not_save_post_without_title
Loaded suite unit/post_test
Started
@@ -330,7 +330,7 @@ Started
Finished in 0.193608 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
-</pre>
+</shell>
Now if you noticed we first wrote a test which fails for a desired functionality, then we wrote some code which adds the functionality and finally we ensured that our test passes. This approach to software development is referred to as _Test-Driven Development_ (TDD).
@@ -348,7 +348,7 @@ end
Now you can see even more output in the console from running the tests:
-<pre>
+<shell>
$ ruby unit/post_test.rb -n test_should_report_error
Loaded suite -e
Started
@@ -361,7 +361,7 @@ NameError: undefined local variable or method `some_undefined_variable' for #<Po
/test/unit/post_test.rb:6:in `test_should_report_error'
1 tests, 0 assertions, 0 failures, 1 errors
-</pre>
+</shell>
Notice the 'E' in the output. It denotes a test with error.
@@ -446,7 +446,7 @@ test "should get index" do
end
</ruby>
-In the +test_should_get_index+ test, Rails simulates a request on the action called index, making sure the request was successful and also ensuring that it assigns a valid +posts+ instance variable.
+In the +test_should_get_index+ test, Rails simulates a request on the action called +index+, making sure the request was successful and also ensuring that it assigns a valid +posts+ instance variable.
The +get+ method kicks off the web request and populates the results into the response. It accepts 4 arguments:
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index f902120453..b9fb13b640 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -39,4 +39,8 @@
# Enable threaded mode
# config.threadsafe!
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation can not be found)
+ config.i18n.fallbacks = true
end
diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb
index 762f84d579..6ea722e239 100644
--- a/railties/test/generators/migration_generator_test.rb
+++ b/railties/test/generators/migration_generator_test.rb
@@ -10,6 +10,19 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
assert_migration "db/migrate/#{migration}.rb", /class ChangeTitleBodyFromPosts < ActiveRecord::Migration/
end
+ def test_migrations_generated_simultaneously
+ migrations = ["change_title_body_from_posts", "change_email_from_comments"]
+
+ first_migration_number, second_migration_number = migrations.collect do |migration|
+ run_generator [migration]
+ file_name = migration_file_name "db/migrate/#{migration}.rb"
+
+ File.basename(file_name).split('_').first
+ end
+
+ assert_not_equal first_migration_number, second_migration_number
+ end
+
def test_migration_with_class_name
migration = "ChangeTitleBodyFromPosts"
run_generator [migration]
diff --git a/railties/test/railties/i18n_railtie_test.rb b/railties/test/railties/i18n_railtie_test.rb
new file mode 100644
index 0000000000..51684aa838
--- /dev/null
+++ b/railties/test/railties/i18n_railtie_test.rb
@@ -0,0 +1,86 @@
+require "isolation/abstract_unit"
+
+module RailtiesTest
+ class I18nRailtieTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ boot_rails
+ FileUtils.rm_rf("#{app_path}/config/environments")
+ require "rails/all"
+ @old_path = I18n.load_path
+ end
+
+ def teardown
+ I18n.load_path = @old_path || []
+ I18n.backend = nil
+ end
+
+ def load_app
+ require "#{app_path}/config/environment"
+ end
+
+ def assert_fallbacks(fallbacks)
+ fallbacks.each do |locale, expected|
+ actual = I18n.fallbacks[locale]
+ assert_equal expected, actual, "expected fallbacks for #{locale.inspect} to be #{expected.inspect}, but were #{actual.inspect}"
+ end
+ end
+
+ def assert_no_fallbacks
+ assert !I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks)
+ end
+
+ test "config.i18n.load_path gets added to I18n.load_path" do
+ I18n.load_path = ['existing/path/to/locales']
+ I18n::Railtie.config.i18n.load_path = ['new/path/to/locales']
+ load_app
+
+ assert I18n.load_path.include?('existing/path/to/locales')
+ assert I18n.load_path.include?('new/path/to/locales')
+ end
+
+ test "not using config.i18n.fallbacks does not initialize I18n.fallbacks" do
+ I18n.backend = Class.new { include I18n::Backend::Base }.new # can't uninclude modules, so use a tmp backend class
+ load_app
+ assert_no_fallbacks
+ end
+
+ test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings" do
+ I18n::Railtie.config.i18n.fallbacks = true
+ load_app
+ assert_fallbacks :de => [:de, :en]
+ end
+
+ test "config.i18n.fallbacks.defaults = [:'en-US'] initializes fallbacks with en-US as a fallback default" do
+ I18n::Railtie.config.i18n.fallbacks.defaults = [:'en-US']
+ load_app
+ assert_fallbacks :de => [:de, :'en-US', :en]
+ end
+
+ test "config.i18n.fallbacks.map = { :ca => :'es-ES' } initializes fallbacks with a mapping ca => es-ES" do
+ I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' }
+ load_app
+ assert_fallbacks :ca => [:ca, :"es-ES", :es, :en]
+ end
+
+ test "[shortcut] config.i18n.fallbacks = [:'en-US'] initializes fallbacks with en-US as a fallback default" do
+ I18n::Railtie.config.i18n.fallbacks = [:'en-US']
+ load_app
+ assert_fallbacks :de => [:de, :'en-US', :en]
+ end
+
+ test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping de-AT => de-DE" do
+ I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' }
+ load_app
+ assert_fallbacks :ca => [:ca, :"es-ES", :es, :en]
+ end
+
+ test "[shortcut] config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] initializes fallbacks with the given arguments" do
+ I18n::Railtie.config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }]
+ load_app
+ assert_fallbacks :ca => [:ca, :"es-ES", :es, :'en-US', :en]
+ end
+ end
+end \ No newline at end of file