aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2010-05-19 23:29:39 +0200
committerXavier Noria <fxn@hashref.com>2010-05-19 23:29:39 +0200
commit7f07cc364a7ee7ceae21b29b54467fde0db93389 (patch)
tree7c9dd8aaeda68731756ee108a8318239b04c80f0
parentb9fcd8d71f94702463b97545bb70ce4727c5b47e (diff)
parent61001e766de974a8864c0bc2cf915888d277a0ea (diff)
downloadrails-7f07cc364a7ee7ceae21b29b54467fde0db93389.tar.gz
rails-7f07cc364a7ee7ceae21b29b54467fde0db93389.tar.bz2
rails-7f07cc364a7ee7ceae21b29b54467fde0db93389.zip
Merge remote branch 'rails/master'
-rw-r--r--Gemfile17
-rw-r--r--actionmailer/test/base_test.rb4
-rw-r--r--actionmailer/test/old_base/asset_host_test.rb8
-rw-r--r--actionmailer/test/old_base/mail_render_test.rb2
-rw-r--r--actionmailer/test/old_base/mail_service_test.rb27
-rw-r--r--actionmailer/test/test_helper_test.rb4
-rw-r--r--actionpack/CHANGELOG2
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb35
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb54
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb122
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb184
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb4
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb5
-rw-r--r--actionpack/lib/action_view.rb6
-rw-r--r--actionpack/lib/action_view/base.rb3
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb7
-rw-r--r--actionpack/lib/action_view/template.rb195
-rw-r--r--actionpack/lib/action_view/template/error.rb18
-rw-r--r--actionpack/lib/action_view/template/handlers/erb.rb139
-rw-r--r--actionpack/lib/action_view/template/resolver.rb5
-rw-r--r--actionpack/test/abstract/translation_test.rb8
-rw-r--r--actionpack/test/abstract_unit.rb5
-rw-r--r--actionpack/test/activerecord/active_record_store_test.rb8
-rw-r--r--actionpack/test/controller/assert_select_test.rb4
-rw-r--r--actionpack/test/controller/capture_test.rb2
-rw-r--r--actionpack/test/controller/cookie_test.rb55
-rw-r--r--actionpack/test/controller/filters_test.rb14
-rw-r--r--actionpack/test/controller/flash_test.rb11
-rw-r--r--actionpack/test/controller/integration_test.rb4
-rw-r--r--actionpack/test/controller/new_base/bare_metal_test.rb4
-rw-r--r--actionpack/test/controller/render_test.rb4
-rw-r--r--actionpack/test/controller/send_file_test.rb4
-rw-r--r--actionpack/test/dispatch/response_test.rb4
-rw-r--r--actionpack/test/dispatch/routing_test.rb12
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb66
-rw-r--r--actionpack/test/dispatch/session/mem_cache_store_test.rb7
-rw-r--r--actionpack/test/dispatch/session/test_session_test.rb12
-rw-r--r--actionpack/test/fixtures/test/content_for.erb3
-rw-r--r--actionpack/test/fixtures/test/content_for_concatenated.erb2
-rw-r--r--actionpack/test/fixtures/test/content_for_with_parameter.erb2
-rw-r--r--actionpack/test/fixtures/test/non_erb_block_content_for.builder2
-rw-r--r--actionpack/test/template/number_helper_i18n_test.rb17
-rw-r--r--actionpack/test/template/render_test.rb10
-rw-r--r--actionpack/test/template/template_test.rb130
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb11
-rw-r--r--activemodel/test/cases/attribute_methods_test.rb2
-rw-r--r--activemodel/test/cases/callbacks_test.rb2
-rw-r--r--activemodel/test/cases/dirty_test.rb4
-rw-r--r--activemodel/test/cases/serializeration/xml_serialization_test.rb9
-rw-r--r--activemodel/test/cases/validations/numericality_validation_test.rb2
-rw-r--r--activerecord/lib/active_record/autosave_association.rb23
-rwxr-xr-xactiverecord/lib/active_record/base.rb23
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb57
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb45
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb4
-rw-r--r--activerecord/lib/active_record/session_store.rb2
-rw-r--r--activerecord/test/cases/active_schema_test_mysql.rb5
-rw-r--r--activerecord/test/cases/aggregations_test.rb20
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb4
-rw-r--r--activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb2
-rw-r--r--activerecord/test/cases/associations/eager_test.rb2
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb13
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb4
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb8
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb18
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb4
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb2
-rw-r--r--activerecord/test/cases/autosave_association_test.rb8
-rwxr-xr-xactiverecord/test/cases/base_test.rb100
-rw-r--r--activerecord/test/cases/column_definition_test.rb6
-rw-r--r--activerecord/test/cases/defaults_test.rb4
-rw-r--r--activerecord/test/cases/dirty_test.rb4
-rw-r--r--activerecord/test/cases/finder_respond_to_test.rb22
-rw-r--r--activerecord/test/cases/finder_test.rb2
-rw-r--r--activerecord/test/cases/inheritance_test.rb14
-rw-r--r--activerecord/test/cases/method_scoping_test.rb14
-rw-r--r--activerecord/test/cases/migration_test.rb48
-rw-r--r--activerecord/test/cases/modules_test.rb2
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb80
-rw-r--r--activerecord/test/cases/pk_test.rb4
-rw-r--r--activerecord/test/cases/pooled_connections_test.rb6
-rw-r--r--activerecord/test/cases/query_cache_test.rb2
-rw-r--r--activerecord/test/cases/relations_test.rb6
-rw-r--r--activerecord/test/cases/reserved_word_test_mysql.rb2
-rw-r--r--activerecord/test/cases/schema_test_postgresql.rb4
-rw-r--r--activerecord/test/cases/timestamp_test.rb16
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb78
-rw-r--r--activerecord/test/models/ship.rb3
-rw-r--r--activerecord/test/models/ship_part.rb2
-rw-r--r--activeresource/test/cases/base/schema_test.rb12
-rw-r--r--activeresource/test/cases/base_test.rb12
-rw-r--r--activesupport/CHANGELOG4
-rw-r--r--activesupport/lib/active_support/core_ext/array/random_access.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb11
-rw-r--r--activesupport/lib/active_support/core_ext/string/encoding.rb11
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb11
-rw-r--r--activesupport/lib/active_support/ruby/shim.rb1
-rw-r--r--activesupport/test/buffered_logger_test.rb12
-rw-r--r--activesupport/test/callbacks_test.rb2
-rw-r--r--activesupport/test/core_ext/array_ext_test.rb4
-rw-r--r--activesupport/test/core_ext/class/attribute_accessor_test.rb8
-rw-r--r--activesupport/test/core_ext/class/class_inheritable_attributes_test.rb4
-rw-r--r--activesupport/test/core_ext/class/delegating_attributes_test.rb8
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb8
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb4
-rw-r--r--activesupport/test/core_ext/duration_test.rb4
-rw-r--r--activesupport/test/core_ext/module/attribute_accessor_test.rb8
-rw-r--r--activesupport/test/core_ext/module/synchronization_test.rb6
-rw-r--r--activesupport/test/core_ext/module_test.rb10
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb22
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb8
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb12
-rw-r--r--activesupport/test/multibyte_chars_test.rb6
-rw-r--r--activesupport/test/time_zone_test.rb2
-rw-r--r--railties/guides/source/getting_started.textile21
-rw-r--r--railties/lib/rails.rb1
-rw-r--r--railties/lib/rails/application/configuration.rb18
-rw-r--r--railties/lib/rails/dispatcher.rb24
-rw-r--r--railties/test/application/configuration_test.rb7
-rw-r--r--railties/test/application/initializers/frameworks_test.rb4
-rw-r--r--railties/test/application/middleware_test.rb5
-rw-r--r--railties/test/application/rackup_test.rb4
127 files changed, 1359 insertions, 872 deletions
diff --git a/Gemfile b/Gemfile
index e94afc828e..23e76d225c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,17 +6,18 @@ gem "rails", :path => File.dirname(__FILE__)
gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
-group :mri do
+mri = !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
+if mri && RUBY_VERSION < '1.9'
+ gem "system_timer"
+ gem "ruby-debug", ">= 0.10.3"
+end
+
+if mri || RUBY_ENGINE == "rbx"
gem 'json'
gem 'yajl-ruby'
gem "nokogiri", ">= 1.4.0"
-
- if RUBY_VERSION < '1.9'
- gem "system_timer"
- gem "ruby-debug", ">= 0.10.3"
- elsif RUBY_VERSION < '1.9.2' && !ENV['CI']
- gem "ruby-debug19"
- end
+elsif RUBY_ENGINE == "jruby"
+ gem "jruby-debug"
end
# AR
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index 5506d62d6a..54bf3de6af 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -491,8 +491,8 @@ class BaseTest < ActiveSupport::TestCase
# Class level API with method missing
test "should respond to action methods" do
- assert BaseMailer.respond_to?(:welcome)
- assert BaseMailer.respond_to?(:implicit_multipart)
+ assert_respond_to BaseMailer, :welcome
+ assert_respond_to BaseMailer, :implicit_multipart
assert !BaseMailer.respond_to?(:mail)
assert !BaseMailer.respond_to?(:headers)
end
diff --git a/actionmailer/test/old_base/asset_host_test.rb b/actionmailer/test/old_base/asset_host_test.rb
index 0ec0242f55..cc13c8a4d7 100644
--- a/actionmailer/test/old_base/asset_host_test.rb
+++ b/actionmailer/test/old_base/asset_host_test.rb
@@ -26,7 +26,7 @@ class AssetHostTest < Test::Unit::TestCase
def test_asset_host_as_string
mail = AssetHostMailer.email_with_asset
- assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.to_s.strip
+ assert_equal %Q{<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />}, mail.body.to_s.strip
end
def test_asset_host_as_one_arguement_proc
@@ -38,7 +38,7 @@ class AssetHostTest < Test::Unit::TestCase
end
}
mail = AssetHostMailer.email_with_asset
- assert_equal "<img alt=\"Somelogo\" src=\"http://images.example.com/images/somelogo.png\" />", mail.body.to_s.strip
+ assert_equal %Q{<img alt="Somelogo" src="http://images.example.com/images/somelogo.png" />}, mail.body.to_s.strip
end
def test_asset_host_as_two_arguement_proc
@@ -51,6 +51,6 @@ class AssetHostTest < Test::Unit::TestCase
}
mail = nil
assert_nothing_raised { mail = AssetHostMailer.email_with_asset }
- assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.to_s.strip
+ assert_equal %Q{<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />}, mail.body.to_s.strip
end
-end \ No newline at end of file
+end
diff --git a/actionmailer/test/old_base/mail_render_test.rb b/actionmailer/test/old_base/mail_render_test.rb
index 405d43d7d3..08951833a5 100644
--- a/actionmailer/test/old_base/mail_render_test.rb
+++ b/actionmailer/test/old_base/mail_render_test.rb
@@ -117,7 +117,7 @@ class RenderHelperTest < Test::Unit::TestCase
def test_rxml_template
mail = RenderMailer.rxml_template.deliver
- assert_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test/>", mail.body.to_s.strip
+ assert_equal %(<?xml version="1.0" encoding="UTF-8"?>\n<test/>), mail.body.to_s.strip
end
def test_included_subtemplate
diff --git a/actionmailer/test/old_base/mail_service_test.rb b/actionmailer/test/old_base/mail_service_test.rb
index f91e7f893c..7054e8052a 100644
--- a/actionmailer/test/old_base/mail_service_test.rb
+++ b/actionmailer/test/old_base/mail_service_test.rb
@@ -281,7 +281,7 @@ class TestMailer < ActionMailer::Base
from "One: Two <test@example.com>"
cc "Three: Four <test@example.com>"
bcc "Five: Six <test@example.com>"
- body "testing"
+ body "testing"
end
def custom_content_type_attributes
@@ -289,7 +289,7 @@ class TestMailer < ActionMailer::Base
subject "custom content types"
from "some.one@somewhere.test"
content_type "text/plain; format=flowed"
- body "testing"
+ body "testing"
end
def return_path
@@ -297,7 +297,7 @@ class TestMailer < ActionMailer::Base
subject "return path test"
from "some.one@somewhere.test"
headers["return-path"] = "another@somewhere.test"
- body "testing"
+ body "testing"
end
def subject_with_i18n(recipient)
@@ -417,7 +417,7 @@ class ActionMailerTest < Test::Unit::TestCase
end
def test_custom_template
- expected = new_mail
+ expected = new_mail
expected.to = @recipient
expected.subject = "[Signed up] Welcome #{@recipient}"
expected.body = "Hello there, \n\nMr. #{@recipient}"
@@ -436,7 +436,7 @@ class ActionMailerTest < Test::Unit::TestCase
assert ActionView::Template.template_handler_extensions.include?("haml"), "haml extension was not registered"
# N.b., custom_templating_extension.text.plain.haml is expected to be in fixtures/test_mailer directory
- expected = new_mail
+ expected = new_mail
expected.to = @recipient
expected.subject = "[Signed up] Welcome #{@recipient}"
expected.body = "Hello there, \n\nMr. #{@recipient}"
@@ -453,7 +453,7 @@ class ActionMailerTest < Test::Unit::TestCase
end
def test_cancelled_account
- expected = new_mail
+ expected = new_mail
expected.to = @recipient
expected.subject = "[Cancelled] Goodbye #{@recipient}"
expected.body = "Goodbye, Mr. #{@recipient}"
@@ -477,7 +477,7 @@ class ActionMailerTest < Test::Unit::TestCase
end
def test_cc_bcc
- expected = new_mail
+ expected = new_mail
expected.to = @recipient
expected.subject = "testing bcc/cc"
expected.body = "Nothing to see here."
@@ -602,7 +602,7 @@ class ActionMailerTest < Test::Unit::TestCase
def test_unencoded_subject
TestMailer.delivery_method = :test
- expected = new_mail
+ expected = new_mail
expected.to = @recipient
expected.subject = "testing unencoded subject"
expected.body = "Nothing to see here."
@@ -1048,8 +1048,9 @@ EOF
def test_multipart_with_template_path_with_dots
mail = FunkyPathMailer.multipart_with_template_path_with_dots(@recipient)
assert_equal 2, mail.parts.length
- assert "text/plain", mail.parts[1].mime_type
- assert "UTF-8", mail.parts[1].charset
+ assert_equal "text/plain", mail.parts[0].mime_type
+ assert_equal "text/html", mail.parts[1].mime_type
+ assert_equal "UTF-8", mail.parts[1].charset
end
def test_custom_content_type_attributes
@@ -1150,15 +1151,15 @@ class RespondToTest < Test::Unit::TestCase
end
def test_should_respond_to_new
- assert RespondToMailer.respond_to?(:new)
+ assert_respond_to RespondToMailer, :new
end
def test_should_respond_to_create_with_template_suffix
- assert RespondToMailer.respond_to?(:create_any_old_template)
+ assert_respond_to RespondToMailer, :create_any_old_template
end
def test_should_respond_to_deliver_with_template_suffix
- assert RespondToMailer.respond_to?(:deliver_any_old_template)
+ assert_respond_to RespondToMailer, :deliver_any_old_template
end
def test_should_not_respond_to_new_with_template_suffix
diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb
index 440fb868c8..8ff604c2c7 100644
--- a/actionmailer/test/test_helper_test.rb
+++ b/actionmailer/test/test_helper_test.rb
@@ -18,7 +18,7 @@ class TestHelperMailerTest < ActionMailer::TestCase
end
def test_setup_creates_the_expected_mailer
- assert @expected.is_a?(Mail::Message)
+ assert_kind_of Mail::Message, @expected
assert_equal "1.0", @expected.mime_version
assert_equal "text/plain", @expected.mime_type
end
@@ -121,7 +121,7 @@ class AnotherTestHelperMailerTest < ActionMailer::TestCase
end
def test_setup_shouldnt_conflict_with_mailer_setup
- assert @expected.is_a?(Mail::Message)
+ assert_kind_of Mail::Message, @expected
assert_equal 'a value', @test_var
end
end
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 4db9c4b84d..54c7771f4c 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
+* Make session stores rely on request.cookie_jar and change set_session semantics to return the cookie value instead of a boolean. [José Valim]
+
* OAuth 2: HTTP Token Authorization support to complement Basic and Digest Authorization. [Rick Olson]
* Fixed inconsistencies in form builder and view helpers #4432 [Neeraj Singh]
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index 1110d7c117..b6d4fb1284 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -104,7 +104,7 @@ module ActionController
def all_application_helpers
helpers = []
helpers_path.each do |path|
- extract = /^#{Regexp.quote(path)}\/?(.*)_helper.rb$/
+ extract = /^#{Regexp.quote(path.to_s)}\/?(.*)_helper.rb$/
helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
end
helpers.sort!
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 8b730a97ee..3b85a98576 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -140,7 +140,7 @@ module ActionDispatch # :nodoc:
def to_a
assign_default_content_type_and_charset!
handle_conditional_get!
- self["Set-Cookie"] = @cookie.join("\n") unless @cookie.blank?
+ self["Set-Cookie"] = self["Set-Cookie"].join("\n") if self["Set-Cookie"].respond_to?(:join)
self["ETag"] = @_etag if @_etag
super
end
@@ -170,7 +170,7 @@ module ActionDispatch # :nodoc:
# assert_equal 'AuthorOfNewPage', r.cookies['author']
def cookies
cookies = {}
- if header = @cookie
+ if header = self["Set-Cookie"]
header = header.split("\n") if header.respond_to?(:to_str)
header.each do |cookie|
if pair = cookie.split(';').first
@@ -182,37 +182,6 @@ module ActionDispatch # :nodoc:
cookies
end
- def set_cookie(key, value)
- case value
- when Hash
- domain = "; domain=" + value[:domain] if value[:domain]
- path = "; path=" + value[:path] if value[:path]
- # According to RFC 2109, we need dashes here.
- # N.B.: cgi.rb uses spaces...
- expires = "; expires=" + value[:expires].clone.gmtime.
- strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
- secure = "; secure" if value[:secure]
- httponly = "; HttpOnly" if value[:httponly]
- value = value[:value]
- end
- value = [value] unless Array === value
- cookie = Rack::Utils.escape(key) + "=" +
- value.map { |v| Rack::Utils.escape v }.join("&") +
- "#{domain}#{path}#{expires}#{secure}#{httponly}"
-
- @cookie << cookie
- end
-
- def delete_cookie(key, value={})
- @cookie.reject! { |cookie|
- cookie =~ /\A#{Rack::Utils.escape(key)}=/
- }
-
- set_cookie(key,
- {:value => '', :path => nil, :domain => nil,
- :expires => Time.at(0) }.merge(value))
- end
-
private
def assign_default_content_type_and_charset!
return if headers[CONTENT_TYPE].present?
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 42ab1d1ebb..87e8dd5010 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -52,9 +52,15 @@ module ActionDispatch
# * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
# only HTTP. Defaults to +false+.
class Cookies
+ HTTP_HEADER = "Set-Cookie".freeze
+ TOKEN_KEY = "action_dispatch.secret_token".freeze
+
+ # Raised when storing more than 4K of session data.
+ class CookieOverflow < StandardError; end
+
class CookieJar < Hash #:nodoc:
def self.build(request)
- secret = request.env["action_dispatch.secret_token"]
+ secret = request.env[TOKEN_KEY]
new(secret).tap do |hash|
hash.update(request.cookies)
end
@@ -134,9 +140,9 @@ module ActionDispatch
@signed ||= SignedCookieJar.new(self, @secret)
end
- def write(response)
- @set_cookies.each { |k, v| response.set_cookie(k, v) }
- @delete_cookies.each { |k, v| response.delete_cookie(k, v) }
+ def write(headers)
+ @set_cookies.each { |k, v| ::Rack::Utils.set_cookie_header!(headers, k, v) }
+ @delete_cookies.each { |k, v| ::Rack::Utils.delete_cookie_header!(headers, k, v) }
end
end
@@ -166,8 +172,11 @@ module ActionDispatch
end
class SignedCookieJar < CookieJar #:nodoc:
+ MAX_COOKIE_SIZE = 4096 # Cookies can typically store 4096 bytes.
+ SECRET_MIN_LENGTH = 30 # Characters
+
def initialize(parent_jar, secret)
- raise "You must set config.secret_token in your app's config" if secret.blank?
+ ensure_secret_secure(secret)
@parent_jar = parent_jar
@verifier = ActiveSupport::MessageVerifier.new(secret)
end
@@ -176,6 +185,8 @@ module ActionDispatch
if signed_message = @parent_jar[name]
@verifier.verify(signed_message)
end
+ rescue ActiveSupport::MessageVerifier::InvalidSignature
+ nil
end
def []=(key, options)
@@ -186,12 +197,34 @@ module ActionDispatch
options = { :value => @verifier.generate(options) }
end
+ raise CookieOverflow if options[:value].size > MAX_COOKIE_SIZE
@parent_jar[key] = options
end
def method_missing(method, *arguments, &block)
@parent_jar.send(method, *arguments, &block)
end
+
+ protected
+
+ # To prevent users from using something insecure like "Password" we make sure that the
+ # secret they've provided is at least 30 characters in length.
+ def ensure_secret_secure(secret)
+ if secret.blank?
+ raise ArgumentError, "A secret is required to generate an " +
+ "integrity hash for cookie session data. Use " +
+ "config.secret_token = \"some secret phrase of at " +
+ "least #{SECRET_MIN_LENGTH} characters\"" +
+ "in config/application.rb"
+ end
+
+ if secret.length < SECRET_MIN_LENGTH
+ raise ArgumentError, "Secret should be something secure, " +
+ "like \"#{ActiveSupport::SecureRandom.hex(16)}\". The value you " +
+ "provided, \"#{secret}\", is shorter than the minimum length " +
+ "of #{SECRET_MIN_LENGTH} characters"
+ end
+ end
end
def initialize(app)
@@ -202,12 +235,13 @@ module ActionDispatch
status, headers, body = @app.call(env)
if cookie_jar = env['action_dispatch.cookies']
- response = Rack::Response.new(body, status, headers)
- cookie_jar.write(response)
- response.to_a
- else
- [status, headers, body]
+ cookie_jar.write(headers)
+ if headers[HTTP_HEADER].respond_to?(:join)
+ headers[HTTP_HEADER] = headers[HTTP_HEADER].join("\n")
+ end
end
+
+ [status, headers, body]
end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index dddedc832f..15493cd2eb 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -1,5 +1,6 @@
require 'rack/utils'
require 'rack/request'
+require 'action_dispatch/middleware/cookies'
require 'active_support/core_ext/object/blank'
module ActionDispatch
@@ -11,9 +12,6 @@ module ActionDispatch
ENV_SESSION_KEY = 'rack.session'.freeze
ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
- HTTP_COOKIE = 'HTTP_COOKIE'.freeze
- SET_COOKIE = 'Set-Cookie'.freeze
-
class SessionHash < Hash
def initialize(by, env)
super()
@@ -22,13 +20,6 @@ module ActionDispatch
@loaded = false
end
- def session_id
- ActiveSupport::Deprecation.warn(
- "ActionDispatch::Session::AbstractStore::SessionHash#session_id " +
- "has been deprecated. Please use request.session_options[:id] instead.", caller)
- @env[ENV_SESSION_OPTIONS_KEY][:id]
- end
-
def [](key)
load! unless @loaded
super(key.to_s)
@@ -45,35 +36,14 @@ module ActionDispatch
h
end
- def update(hash = nil)
- if hash.nil?
- ActiveSupport::Deprecation.warn('use replace instead', caller)
- replace({})
- else
- load! unless @loaded
- super(hash.stringify_keys)
- end
- end
-
- def delete(key = nil)
- if key.nil?
- ActiveSupport::Deprecation.warn('use clear instead', caller)
- clear
- else
- load! unless @loaded
- super(key.to_s)
- end
- end
-
- def data
- ActiveSupport::Deprecation.warn(
- "ActionDispatch::Session::AbstractStore::SessionHash#data " +
- "has been deprecated. Please use #to_hash instead.", caller)
- to_hash
+ def update(hash)
+ load! unless @loaded
+ super(hash.stringify_keys)
end
- def close
- ActiveSupport::Deprecation.warn('sessions should no longer be closed', caller)
+ def delete(key)
+ load! unless @loaded
+ super(key.to_s)
end
def inspect
@@ -124,30 +94,15 @@ module ActionDispatch
}
def initialize(app, options = {})
- # Process legacy CGI options
- options = options.symbolize_keys
- if options.has_key?(:session_path)
- options[:path] = options.delete(:session_path)
- end
- if options.has_key?(:session_key)
- options[:key] = options.delete(:session_key)
- end
- if options.has_key?(:session_http_only)
- options[:httponly] = options.delete(:session_http_only)
- end
-
@app = app
@default_options = DEFAULT_OPTIONS.merge(options)
- @key = @default_options[:key]
- @cookie_only = @default_options[:cookie_only]
+ @key = @default_options.delete(:key).freeze
+ @cookie_only = @default_options.delete(:cookie_only)
+ ensure_session_key!
end
def call(env)
- session = SessionHash.new(self, env)
-
- env[ENV_SESSION_KEY] = session
- env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
-
+ prepare!(env)
response = @app.call(env)
session_data = env[ENV_SESSION_KEY]
@@ -157,53 +112,62 @@ module ActionDispatch
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
sid = options[:id] || generate_sid
+ session_data = session_data.to_hash
- unless set_session(env, sid, session_data.to_hash)
- return response
- end
+ value = set_session(env, sid, session_data)
+ return response unless value
- cookie = Rack::Utils.escape(@key) + '=' + Rack::Utils.escape(sid)
- cookie << "; domain=#{options[:domain]}" if options[:domain]
- cookie << "; path=#{options[:path]}" if options[:path]
- if options[:expire_after]
- expiry = Time.now + options[:expire_after]
- cookie << "; expires=#{expiry.httpdate}"
- end
- cookie << "; Secure" if options[:secure]
- cookie << "; HttpOnly" if options[:httponly]
-
- headers = response[1]
- unless headers[SET_COOKIE].blank?
- headers[SET_COOKIE] << "\n#{cookie}"
- else
- headers[SET_COOKIE] = cookie
+ cookie = { :value => value }
+ unless options[:expire_after].nil?
+ cookie[:expires] = Time.now + options.delete(:expire_after)
end
+
+ request = ActionDispatch::Request.new(env)
+ set_cookie(request, cookie.merge!(options))
end
response
end
private
+
+ def prepare!(env)
+ env[ENV_SESSION_KEY] = SessionHash.new(self, env)
+ env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
+ end
+
def generate_sid
ActiveSupport::SecureRandom.hex(16)
end
+ def set_cookie(request, options)
+ request.cookie_jar[@key] = options
+ end
+
def load_session(env)
request = Rack::Request.new(env)
- sid = request.cookies[@key]
- unless @cookie_only
- sid ||= request.params[@key]
- end
+ sid = request.cookies[@key]
+ sid ||= request.params[@key] unless @cookie_only
sid, session = get_session(env, sid)
[sid, session]
end
+ def ensure_session_key!
+ if @key.blank?
+ raise ArgumentError, 'A key is required to write a ' +
+ 'cookie containing the session data. Use ' +
+ 'config.session_store SESSION_STORE, { :key => ' +
+ '"_myapp_session" } in config/application.rb'
+ end
+ end
+
def get_session(env, sid)
raise '#get_session needs to be implemented.'
end
def set_session(env, sid, session_data)
- raise '#set_session needs to be implemented.'
+ raise '#set_session needs to be implemented and should return ' <<
+ 'the value to be stored in the cookie (usually the sid)'
end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index 7114f42003..92a86ee229 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -38,23 +38,11 @@ module ActionDispatch
# "rake secret" and set the key in config/environment.rb.
#
# Note that changing digest or secret invalidates all existing sessions!
- class CookieStore
- # Cookies can typically store 4096 bytes.
- MAX = 4096
- SECRET_MIN_LENGTH = 30 # characters
-
- DEFAULT_OPTIONS = {
- :key => '_session_id',
- :domain => nil,
- :path => "/",
- :expire_after => nil,
- :httponly => true
- }.freeze
-
+ class CookieStore < AbstractStore
class OptionsHash < Hash
def initialize(by, env, default_options)
- @session_data = env[CookieStore::ENV_SESSION_KEY]
- default_options.each { |key, value| self[key] = value }
+ @session_data = env[AbstractStore::ENV_SESSION_KEY]
+ merge!(default_options)
end
def [](key)
@@ -62,172 +50,38 @@ module ActionDispatch
end
end
- ENV_SESSION_KEY = "rack.session".freeze
- ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze
- HTTP_SET_COOKIE = "Set-Cookie".freeze
-
- # Raised when storing more than 4K of session data.
- class CookieOverflow < StandardError; end
-
def initialize(app, options = {})
- # Process legacy CGI options
- options = options.symbolize_keys
- if options.has_key?(:session_path)
- options[:path] = options.delete(:session_path)
- end
- if options.has_key?(:session_key)
- options[:key] = options.delete(:session_key)
- end
- if options.has_key?(:session_http_only)
- options[:httponly] = options.delete(:session_http_only)
- end
-
- @app = app
-
- # The session_key option is required.
- ensure_session_key(options[:key])
- @key = options.delete(:key).freeze
-
- # The secret option is required.
- ensure_secret_secure(options[:secret])
- @secret = options.delete(:secret).freeze
-
- @digest = options.delete(:digest) || 'SHA1'
- @verifier = verifier_for(@secret, @digest)
-
- @default_options = DEFAULT_OPTIONS.merge(options).freeze
-
+ super(app, options.merge!(:cookie_only => true))
freeze
end
- def call(env)
- env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
- env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
-
- status, headers, body = @app.call(env)
-
- session_data = env[ENV_SESSION_KEY]
- options = env[ENV_SESSION_OPTIONS_KEY]
-
- if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
- session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
- session_data = marshal(session_data.to_hash)
-
- raise CookieOverflow if session_data.size > MAX
-
- cookie = Hash.new
- cookie[:value] = session_data
- unless options[:expire_after].nil?
- cookie[:expires] = Time.now + options[:expire_after]
- end
-
- cookie = build_cookie(@key, cookie.merge(options))
- unless headers[HTTP_SET_COOKIE].blank?
- headers[HTTP_SET_COOKIE] << "\n#{cookie}"
- else
- headers[HTTP_SET_COOKIE] = cookie
- end
- end
-
- [status, headers, body]
- end
-
private
- # Should be in Rack::Utils soon
- def build_cookie(key, value)
- case value
- when Hash
- domain = "; domain=" + value[:domain] if value[:domain]
- path = "; path=" + value[:path] if value[:path]
- # According to RFC 2109, we need dashes here.
- # N.B.: cgi.rb uses spaces...
- expires = "; expires=" + value[:expires].clone.gmtime.
- strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
- secure = "; secure" if value[:secure]
- httponly = "; HttpOnly" if value[:httponly]
- value = value[:value]
- end
- value = [value] unless Array === value
- cookie = Rack::Utils.escape(key) + "=" +
- value.map { |v| Rack::Utils.escape(v) }.join("&") +
- "#{domain}#{path}#{expires}#{secure}#{httponly}"
+
+ def prepare!(env)
+ env[ENV_SESSION_KEY] = SessionHash.new(self, env)
+ env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
end
def load_session(env)
- request = Rack::Request.new(env)
- session_data = request.cookies[@key]
- data = unmarshal(session_data) || persistent_session_id!({})
+ request = ActionDispatch::Request.new(env)
+ data = request.cookie_jar.signed[@key]
+ data = persistent_session_id!(data)
data.stringify_keys!
[data["session_id"], data]
end
- # Marshal a session hash into safe cookie data. Include an integrity hash.
- def marshal(session)
- @verifier.generate(persistent_session_id!(session))
- end
-
- # Unmarshal cookie data to a hash and verify its integrity.
- def unmarshal(cookie)
- persistent_session_id!(@verifier.verify(cookie)) if cookie
- rescue ActiveSupport::MessageVerifier::InvalidSignature
- nil
- end
-
- def ensure_session_key(key)
- if key.blank?
- raise ArgumentError, 'A key is required to write a ' +
- 'cookie containing the session data. Use ' +
- 'config.session_store :cookie_store, { :key => ' +
- '"_myapp_session" } in config/application.rb'
- end
- end
-
- # To prevent users from using something insecure like "Password" we make sure that the
- # secret they've provided is at least 30 characters in length.
- def ensure_secret_secure(secret)
- # There's no way we can do this check if they've provided a proc for the
- # secret.
- return true if secret.is_a?(Proc)
-
- if secret.blank?
- raise ArgumentError, "A secret is required to generate an " +
- "integrity hash for cookie session data. Use " +
- "config.secret_token = \"some secret phrase of at " +
- "least #{SECRET_MIN_LENGTH} characters\"" +
- "in config/application.rb"
- end
-
- if secret.length < SECRET_MIN_LENGTH
- raise ArgumentError, "Secret should be something secure, " +
- "like \"#{ActiveSupport::SecureRandom.hex(16)}\". The value you " +
- "provided, \"#{secret}\", is shorter than the minimum length " +
- "of #{SECRET_MIN_LENGTH} characters"
- end
- end
-
- def verifier_for(secret, digest)
- key = secret.respond_to?(:call) ? secret.call : secret
- ActiveSupport::MessageVerifier.new(key, digest)
- end
-
- def generate_sid
- ActiveSupport::SecureRandom.hex(16)
- end
-
- def persistent_session_id!(data)
- (data ||= {}).merge!(inject_persistent_session_id(data))
+ def set_cookie(request, options)
+ request.cookie_jar.signed[@key] = options
end
- def inject_persistent_session_id(data)
- requires_session_id?(data) ? { "session_id" => generate_sid } : {}
+ def set_session(env, sid, session_data)
+ persistent_session_id!(session_data, sid)
end
- def requires_session_id?(data)
- if data
- data.respond_to?(:key?) && !data.key?("session_id")
- else
- true
- end
+ def persistent_session_id!(data, sid=nil)
+ data ||= {}
+ data["session_id"] ||= sid || generate_sid
+ data
end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
index be1d5a43a2..8df8f977e8 100644
--- a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
@@ -38,9 +38,9 @@ module ActionDispatch
options = env['rack.session.options']
expiry = options[:expire_after] || 0
@pool.set(sid, session_data, expiry)
- return true
+ sid
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
- return false
+ false
end
end
end
diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index 004c254e55..38da44d7e7 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -10,8 +10,6 @@ module ActionDispatch
# Prepare dispatcher callbacks and run 'prepare' callbacks
initializer "action_dispatch.prepare_dispatcher" do |app|
- # TODO: This used to say unless defined?(Dispatcher). Find out why and fix.
- require 'rails/dispatcher'
ActionDispatch::Callbacks.to_prepare { app.routes_reloader.reload_if_changed }
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 4b02c2deb3..8a8d21c434 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -693,6 +693,11 @@ module ActionDispatch
super
end
+ def root(options={})
+ options[:on] ||= :collection if @scope[:scope_level] == :resources
+ super(options)
+ end
+
protected
def parent_resource #:nodoc:
@scope[:scope_level_resource]
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 5555217ee2..9f56cca869 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -51,13 +51,17 @@ module ActionView
autoload :MissingTemplate, 'action_view/template/error'
autoload :ActionViewError, 'action_view/template/error'
- autoload :TemplateError, 'action_view/template/error'
+ autoload :EncodingError, 'action_view/template/error'
+ autoload :TemplateError, 'action_view/template/error'
+ autoload :WrongEncodingError, 'action_view/template/error'
autoload :TemplateHandler, 'action_view/template'
autoload :TemplateHandlers, 'action_view/template'
end
autoload :TestCase, 'action_view/test_case'
+
+ ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*'
end
require 'active_support/i18n'
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 4ac2ee52d6..735398d972 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -201,7 +201,7 @@ module ActionView #:nodoc:
end
def initialize(lookup_context = nil, assigns_for_first_render = {}, controller = nil, formats = nil) #:nodoc:
- @config = nil
+ @config = nil
@assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) }
@helpers = self.class.helpers || Module.new
@@ -212,6 +212,7 @@ module ActionView #:nodoc:
@_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
+ @output_buffer = nil
@lookup_context = lookup_context.is_a?(ActionView::LookupContext) ?
lookup_context : ActionView::LookupContext.new(lookup_context)
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 01fecc0f23..fccf004adf 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -13,6 +13,9 @@ module ActionView
# unchanged if can't be converted into a valid number.
module NumberHelper
+ DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :unit => "$", :separator => ".", :delimiter => ",",
+ :precision => 2, :significant => false, :strip_insignificant_zeros => false }
+
# Raised when argument +number+ param given to the helpers is invalid and
# the option :raise is set to +true+.
class InvalidNumberError < StandardError
@@ -104,9 +107,9 @@ module ActionView
defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(currency)
- options = options.reverse_merge(defaults)
+ defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency)
+ options = defaults.merge!(options)
unit = options.delete(:unit)
format = options.delete(:format)
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index a1a970e2d2..5d8ac6b115 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -1,12 +1,89 @@
-# encoding: utf-8
-# This is so that templates compiled in this file are UTF-8
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/kernel/singleton_class'
module ActionView
class Template
extend ActiveSupport::Autoload
+ # === Encodings in ActionView::Template
+ #
+ # ActionView::Template is one of a few sources of potential
+ # encoding issues in Rails. This is because the source for
+ # templates are usually read from disk, and Ruby (like most
+ # encoding-aware programming languages) assumes that the
+ # String retrieved through File IO is encoded in the
+ # <tt>default_external</tt> encoding. In Rails, the default
+ # <tt>default_external</tt> encoding is UTF-8.
+ #
+ # As a result, if a user saves their template as ISO-8859-1
+ # (for instance, using a non-Unicode-aware text editor),
+ # and uses characters outside of the ASCII range, their
+ # users will see diamonds with question marks in them in
+ # the browser.
+ #
+ # To mitigate this problem, we use a few strategies:
+ # 1. If the source is not valid UTF-8, we raise an exception
+ # when the template is compiled to alert the user
+ # to the problem.
+ # 2. The user can specify the encoding using Ruby-style
+ # encoding comments in any template engine. If such
+ # a comment is supplied, Rails will apply that encoding
+ # to the resulting compiled source returned by the
+ # template handler.
+ # 3. In all cases, we transcode the resulting String to
+ # the <tt>default_internal</tt> encoding (which defaults
+ # to UTF-8).
+ #
+ # This means that other parts of Rails can always assume
+ # that templates are encoded in UTF-8, even if the original
+ # source of the template was not UTF-8.
+ #
+ # From a user's perspective, the easiest thing to do is
+ # to save your templates as UTF-8. If you do this, you
+ # do not need to do anything else for things to "just work".
+ #
+ # === Instructions for template handlers
+ #
+ # The easiest thing for you to do is to simply ignore
+ # encodings. Rails will hand you the template source
+ # as the default_internal (generally UTF-8), raising
+ # an exception for the user before sending the template
+ # to you if it could not determine the original encoding.
+ #
+ # For the greatest simplicity, you can support only
+ # UTF-8 as the <tt>default_internal</tt>. This means
+ # that from the perspective of your handler, the
+ # entire pipeline is just UTF-8.
+ #
+ # === Advanced: Handlers with alternate metadata sources
+ #
+ # If you want to provide an alternate mechanism for
+ # specifying encodings (like ERB does via <%# encoding: ... %>),
+ # you may indicate that you are willing to accept
+ # BINARY data by implementing <tt>self.accepts_binary?</tt>
+ # on your handler.
+ #
+ # If you do, Rails will not raise an exception if
+ # the template's encoding could not be determined,
+ # assuming that you have another mechanism for
+ # making the determination.
+ #
+ # In this case, make sure you return a String from
+ # your handler encoded in the default_internal. Since
+ # you are handling out-of-band metadata, you are
+ # also responsible for alerting the user to any
+ # problems with converting the user's data to
+ # the default_internal.
+ #
+ # To do so, simply raise the raise WrongEncodingError
+ # as follows:
+ #
+ # raise WrongEncodingError.new(
+ # problematic_string,
+ # expected_encoding
+ # )
+
eager_autoload do
autoload :Error
autoload :Handler
@@ -16,20 +93,22 @@ module ActionView
extend Template::Handlers
- attr_reader :source, :identifier, :handler, :virtual_path, :formats
+ attr_reader :source, :identifier, :handler, :virtual_path, :formats,
+ :original_encoding
- Finalizer = proc do |method_name|
+ Finalizer = proc do |method_name, mod|
proc do
- ActionView::CompiledTemplates.module_eval do
+ mod.module_eval do
remove_possible_method method_name
end
end
end
def initialize(source, identifier, handler, details)
- @source = source
- @identifier = identifier
- @handler = handler
+ @source = source
+ @identifier = identifier
+ @handler = handler
+ @original_encoding = nil
@virtual_path = details[:virtual_path]
@method_names = {}
@@ -42,7 +121,13 @@ module ActionView
# Notice that we use a bang in this instrumentation because you don't want to
# consume this in production. This is only slow if it's being listened to.
ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do
- method_name = compile(locals, view)
+ if view.is_a?(ActionView::CompiledTemplates)
+ mod = ActionView::CompiledTemplates
+ else
+ mod = view.singleton_class
+ end
+
+ method_name = compile(locals, view, mod)
view.send(method_name, locals, &block)
end
rescue Exception => e
@@ -50,7 +135,7 @@ module ActionView
e.sub_template_of(self)
raise e
else
- raise Template::Error.new(self, view.assigns, e)
+ raise Template::Error.new(self, view.respond_to?(:assigns) ? view.assigns : {}, e)
end
end
@@ -75,37 +160,97 @@ module ActionView
end
private
- def compile(locals, view)
+ # Among other things, this method is responsible for properly setting
+ # the encoding of the source. Until this point, we assume that the
+ # source is BINARY data. If no additional information is supplied,
+ # we assume the encoding is the same as Encoding.default_external.
+ #
+ # The user can also specify the encoding via a comment on the first
+ # line of the template (# encoding: NAME-OF-ENCODING). This will work
+ # with any template engine, as we process out the encoding comment
+ # before passing the source on to the template engine, leaving a
+ # blank line in its stead.
+ #
+ # Note that after we figure out the correct encoding, we then
+ # encode the source into Encoding.default_internal. In general,
+ # this means that templates will be UTF-8 inside of Rails,
+ # regardless of the original source encoding.
+ def compile(locals, view, mod)
method_name = build_method_name(locals)
return method_name if view.respond_to?(method_name)
locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join
- code = @handler.call(self)
- if code.sub!(/\A(#.*coding.*)\n/, '')
- encoding_comment = $1
- elsif defined?(Encoding) && Encoding.respond_to?(:default_external)
- encoding_comment = "#coding:#{Encoding.default_external}"
+ if source.encoding_aware?
+ if source.sub!(/\A#{ENCODING_FLAG}/, '')
+ encoding = $1
+ else
+ encoding = Encoding.default_external
+ end
+
+ # Tag the source with the default external encoding
+ # or the encoding specified in the file
+ source.force_encoding(encoding)
+
+ # If the original encoding is BINARY, the actual
+ # encoding is either stored out-of-band (such as
+ # in ERB <%# %> style magic comments) or missing.
+ # This is also true if the original encoding is
+ # something other than BINARY, but it's invalid.
+ if source.encoding != Encoding::BINARY && source.valid_encoding?
+ source.encode!
+ # If the assumed encoding is incorrect, check to
+ # see whether the handler accepts BINARY. If it
+ # does, it has another mechanism for determining
+ # the true encoding of the String.
+ elsif @handler.respond_to?(:accepts_binary?) && @handler.accepts_binary?
+ source.force_encoding(Encoding::BINARY)
+ # If the handler does not accept BINARY, the
+ # assumed encoding (either the default_external,
+ # or the explicit encoding specified by the user)
+ # is incorrect. We raise an exception here.
+ else
+ raise WrongEncodingError.new(source, encoding)
+ end
+
+ # Don't validate the encoding yet -- the handler
+ # may treat the String as raw bytes and extract
+ # the encoding some other way
end
+ code = @handler.call(self)
+
source = <<-end_src
def #{method_name}(local_assigns)
- _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = output_buffer;#{locals_code};#{code}
+ _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code}
ensure
- @_virtual_path, self.output_buffer = _old_virtual_path, _old_output_buffer
+ @_virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
end
end_src
- if encoding_comment
- source = "#{encoding_comment}\n#{source}"
- line = -1
- else
- line = 0
+ if source.encoding_aware?
+ # Handlers should return their source Strings in either the
+ # default_internal or BINARY. If the handler returns a BINARY
+ # String, we assume its encoding is the one we determined
+ # earlier, and encode the resulting source in the default_internal.
+ if source.encoding == Encoding::BINARY
+ source.force_encoding(Encoding.default_internal)
+ end
+
+ # In case we get back a String from a handler that is not in
+ # BINARY or the default_internal, encode it to the default_internal
+ source.encode!
+
+ # Now, validate that the source we got back from the template
+ # handler is valid in the default_internal
+ unless source.valid_encoding?
+ raise WrongEncodingError.new(@source, Encoding.default_internal)
+ end
end
begin
- ActionView::CompiledTemplates.module_eval(source, identifier, line)
- ObjectSpace.define_finalizer(self, Finalizer[method_name])
+ mod.module_eval(source, identifier, 0)
+ ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
method_name
rescue Exception => e # errors from template code
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb
index 6866eabf77..d3a53d2147 100644
--- a/actionpack/lib/action_view/template/error.rb
+++ b/actionpack/lib/action_view/template/error.rb
@@ -4,6 +4,24 @@ module ActionView
class ActionViewError < StandardError #:nodoc:
end
+ class EncodingError < StandardError #:nodoc:
+ end
+
+ class WrongEncodingError < EncodingError #:nodoc:
+ def initialize(string, encoding)
+ @string, @encoding = string, encoding
+ end
+
+ def message
+ "Your template was not saved as valid #{@encoding}. Please " \
+ "either specify #{@encoding} as the encoding for your template " \
+ "in your text editor, or mark the template with its " \
+ "encoding by inserting the following as the first line " \
+ "of the template:\n\n# encoding: <name of correct encoding>.\n\n" \
+ "The source of your template was:\n\n#{@string}"
+ end
+ end
+
class MissingTemplate < ActionViewError #:nodoc:
attr_reader :path
diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb
index 237746437a..cbed0108cf 100644
--- a/actionpack/lib/action_view/template/handlers/erb.rb
+++ b/actionpack/lib/action_view/template/handlers/erb.rb
@@ -1,9 +1,15 @@
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/string/output_safety'
+require "action_view/template"
require 'erubis'
module ActionView
class OutputBuffer < ActiveSupport::SafeBuffer
+ def initialize(*)
+ super
+ encode! if encoding_aware?
+ end
+
def <<(value)
super(value.to_s)
end
@@ -17,65 +23,108 @@ module ActionView
end
end
- module Template::Handlers
- class Erubis < ::Erubis::Eruby
- def add_preamble(src)
- src << "@output_buffer = ActionView::OutputBuffer.new;"
- end
+ class Template
+ module Handlers
+ class Erubis < ::Erubis::Eruby
+ def add_preamble(src)
+ src << "@output_buffer = ActionView::OutputBuffer.new;"
+ end
- def add_text(src, text)
- return if text.empty?
- src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
- end
+ def add_text(src, text)
+ return if text.empty?
+ src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
+ end
- BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
+ BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
- def add_expr_literal(src, code)
- if code =~ BLOCK_EXPR
- src << '@output_buffer.append= ' << code
- else
- src << '@output_buffer.append= (' << code << ');'
+ def add_expr_literal(src, code)
+ if code =~ BLOCK_EXPR
+ src << '@output_buffer.append= ' << code
+ else
+ src << '@output_buffer.append= (' << code << ');'
+ end
end
- end
- def add_stmt(src, code)
- if code =~ BLOCK_EXPR
- src << '@output_buffer.append_if_string= ' << code
- else
- super
+ def add_stmt(src, code)
+ if code =~ BLOCK_EXPR
+ src << '@output_buffer.append_if_string= ' << code
+ else
+ super
+ end
end
- end
- def add_expr_escaped(src, code)
- src << '@output_buffer.append= ' << escaped_expr(code) << ';'
- end
+ def add_expr_escaped(src, code)
+ src << '@output_buffer.append= ' << escaped_expr(code) << ';'
+ end
- def add_postamble(src)
- src << '@output_buffer.to_s'
+ def add_postamble(src)
+ src << '@output_buffer.to_s'
+ end
end
- end
- class ERB < Template::Handler
- include Compilable
+ class ERB < Handler
+ include Compilable
+
+ ##
+ # :singleton-method:
+ # Specify trim mode for the ERB compiler. Defaults to '-'.
+ # See ERb documentation for suitable values.
+ cattr_accessor :erb_trim_mode
+ self.erb_trim_mode = '-'
+
+ self.default_format = Mime::HTML
+
+ cattr_accessor :erb_implementation
+ self.erb_implementation = Erubis
- ##
- # :singleton-method:
- # Specify trim mode for the ERB compiler. Defaults to '-'.
- # See ERb documentation for suitable values.
- cattr_accessor :erb_trim_mode
- self.erb_trim_mode = '-'
+ ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
- self.default_format = Mime::HTML
+ def self.accepts_binary?
+ true
+ end
+
+ def compile(template)
+ if template.source.encoding_aware?
+ # Even though Rails has given us a String tagged with the
+ # default_internal encoding (likely UTF-8), it is possible
+ # that the String is actually encoded using a different
+ # encoding, specified via an ERB magic comment. If the
+ # String is not actually UTF-8, the regular expression
+ # engine will (correctly) raise an exception. For now,
+ # we'll reset the String to BINARY so we can run regular
+ # expressions against it
+ template_source = template.source.dup.force_encoding("BINARY")
+
+ # Erubis does not have direct support for encodings.
+ # As a result, we will extract the ERB-style magic
+ # comment, give the String to Erubis as BINARY data,
+ # and then tag the resulting String with the extracted
+ # encoding later
+ erb = template_source.gsub(ENCODING_TAG, '')
+ encoding = $2
- cattr_accessor :erb_implementation
- self.erb_implementation = Erubis
+ if !encoding && (template.source.encoding == Encoding::BINARY)
+ raise WrongEncodingError.new(template_source, Encoding.default_external)
+ end
+ else
+ erb = template.source.dup
+ end
- def compile(template)
- source = template.source.gsub(/\A(<%(#.*coding[:=]\s*(\S+)\s*)-?%>)\s*\n?/, '')
- erb = "<% __in_erb_template=true %>#{source}"
- result = self.class.erb_implementation.new(erb, :trim=>(self.class.erb_trim_mode == "-")).src
- result = "#{$2}\n#{result}" if $2
- result
+ result = self.class.erb_implementation.new(
+ erb,
+ :trim => (self.class.erb_trim_mode == "-")
+ ).src
+
+ # If an encoding tag was found, tag the String
+ # we're returning with that encoding. Otherwise,
+ # return a BINARY String, which is what ERB
+ # returns. Note that if a magic comment was
+ # not specified, we will return the data to
+ # Rails as BINARY, which will then use its
+ # own encoding logic to create a UTF-8 String.
+ result = "\n#{result}".force_encoding(encoding).encode if encoding
+ result
+ end
end
end
end
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index a223b3a55f..ef44925951 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -70,7 +70,10 @@ module ActionView
Dir[query].reject { |p| File.directory?(p) }.map do |p|
handler, format = extract_handler_and_format(p, formats)
- Template.new(File.read(p), File.expand_path(p), handler,
+
+ contents = File.open(p, "rb") {|io| io.read }
+
+ Template.new(contents, File.expand_path(p), handler,
:virtual_path => path, :format => format)
end
end
diff --git a/actionpack/test/abstract/translation_test.rb b/actionpack/test/abstract/translation_test.rb
index 0bf61a6556..09ebfab85e 100644
--- a/actionpack/test/abstract/translation_test.rb
+++ b/actionpack/test/abstract/translation_test.rb
@@ -9,18 +9,18 @@ class TranslationControllerTest < Test::Unit::TestCase
end
def test_action_controller_base_responds_to_translate
- assert @controller.respond_to?(:translate)
+ assert_respond_to @controller, :translate
end
def test_action_controller_base_responds_to_t
- assert @controller.respond_to?(:t)
+ assert_respond_to @controller, :t
end
def test_action_controller_base_responds_to_localize
- assert @controller.respond_to?(:localize)
+ assert_respond_to @controller, :localize
end
def test_action_controller_base_responds_to_l
- assert @controller.respond_to?(:l)
+ assert_respond_to @controller, :l
end
end \ No newline at end of file
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 89ba0990f1..d2e5d2e965 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -12,6 +12,10 @@ $:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers')
ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp')
+if defined?(Encoding.default_internal)
+ Encoding.default_internal = "UTF-8"
+end
+
require 'test/unit'
require 'abstract_controller'
require 'action_controller'
@@ -158,6 +162,7 @@ class ActionController::IntegrationTest < ActiveSupport::TestCase
middleware.use "ActionDispatch::Cookies"
middleware.use "ActionDispatch::Flash"
middleware.use "ActionDispatch::Head"
+ yield(middleware) if block_given?
end
end
diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb
index 61bee1b66c..6d4b8e1e40 100644
--- a/actionpack/test/activerecord/active_record_store_test.rb
+++ b/actionpack/test/activerecord/active_record_store_test.rb
@@ -152,12 +152,18 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
end
private
+
def with_test_route_set(options = {})
with_routing do |set|
set.draw do |map|
match ':action', :to => 'active_record_store_test/test'
end
- @app = ActiveRecord::SessionStore.new(set, options.reverse_merge(:key => '_session_id'))
+
+ @app = self.class.build_app(set) do |middleware|
+ middleware.use ActiveRecord::SessionStore, options.reverse_merge(:key => '_session_id')
+ middleware.delete "ActionDispatch::ShowExceptions"
+ end
+
yield
end
end
diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb
index 7012c4c9b0..4f8ad23174 100644
--- a/actionpack/test/controller/assert_select_test.rb
+++ b/actionpack/test/controller/assert_select_test.rb
@@ -212,12 +212,12 @@ class AssertSelectTest < ActionController::TestCase
assert_nothing_raised { assert_select "div", "bar" }
assert_nothing_raised { assert_select "div", /\w*/ }
assert_nothing_raised { assert_select "div", :text => /\w*/, :count=>2 }
- assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 }
+ assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 }
assert_nothing_raised { assert_select "div", :html=>"<span>bar</span>" }
assert_nothing_raised { assert_select "div", :html=>"<span>bar</span>" }
assert_nothing_raised { assert_select "div", :html=>/\w*/ }
assert_nothing_raised { assert_select "div", :html=>/\w*/, :count=>2 }
- assert_raise(Assertion) { assert_select "div", :html=>"<span>foo</span>", :count=>2 }
+ assert_raise(Assertion) { assert_select "div", :html=>"<span>foo</span>", :count=>2 }
end
end
diff --git a/actionpack/test/controller/capture_test.rb b/actionpack/test/controller/capture_test.rb
index d1dbd535c4..47253f22b8 100644
--- a/actionpack/test/controller/capture_test.rb
+++ b/actionpack/test/controller/capture_test.rb
@@ -68,6 +68,6 @@ class CaptureTest < ActionController::TestCase
private
def expected_content_for_output
- "<title>Putting stuff in the title!</title>\n\nGreat stuff!"
+ "<title>Putting stuff in the title!</title>\nGreat stuff!"
end
end
diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb
index 4971866e7c..f65eda5c69 100644
--- a/actionpack/test/controller/cookie_test.rb
+++ b/actionpack/test/controller/cookie_test.rb
@@ -58,6 +58,17 @@ class CookieTest < ActionController::TestCase
head :ok
end
+ def raise_data_overflow
+ cookies.signed[:foo] = 'bye!' * 1024
+ head :ok
+ end
+
+ def tampered_cookies
+ cookies[:tampered] = "BAh7BjoIZm9vIghiYXI%3D--123456780"
+ cookies.signed[:tampered]
+ head :ok
+ end
+
def set_permanent_signed_cookie
cookies.permanent.signed[:remember_me] = 100
head :ok
@@ -74,7 +85,7 @@ class CookieTest < ActionController::TestCase
def setup
super
- @request.env["action_dispatch.secret_token"] = "thisISverySECRET123"
+ @request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
@request.host = "www.nextangle.com"
end
@@ -163,6 +174,48 @@ class CookieTest < ActionController::TestCase
assert_equal({"user_name" => "david"}, @response.cookies)
end
+ def test_raise_data_overflow
+ assert_raise(ActionDispatch::Cookies::CookieOverflow) do
+ get :raise_data_overflow
+ end
+ end
+
+ def test_tampered_cookies
+ assert_nothing_raised do
+ get :tampered_cookies
+ assert_response :success
+ end
+ end
+
+ def test_raises_argument_error_if_missing_secret
+ assert_raise(ArgumentError, nil.inspect) {
+ @request.env["action_dispatch.secret_token"] = nil
+ get :set_signed_cookie
+ }
+
+ assert_raise(ArgumentError, ''.inspect) {
+ @request.env["action_dispatch.secret_token"] = ""
+ get :set_signed_cookie
+ }
+ end
+
+ def test_raises_argument_error_if_secret_is_probably_insecure
+ assert_raise(ArgumentError, "password".inspect) {
+ @request.env["action_dispatch.secret_token"] = "password"
+ get :set_signed_cookie
+ }
+
+ assert_raise(ArgumentError, "secret".inspect) {
+ @request.env["action_dispatch.secret_token"] = "secret"
+ get :set_signed_cookie
+ }
+
+ assert_raise(ArgumentError, "12345678901234567890123456789".inspect) {
+ @request.env["action_dispatch.secret_token"] = "12345678901234567890123456789"
+ get :set_signed_cookie
+ }
+ end
+
private
def assert_cookie_header(expected)
header = @response.headers["Set-Cookie"]
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index ea740f7233..d5704eba78 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -515,7 +515,7 @@ class FilterTest < ActionController::TestCase
assert assigns["ran_proc_filter2"]
test_process(AnomolousYetValidConditionController, "show_without_filter")
- assert_equal nil, assigns["ran_filter"]
+ assert_nil assigns["ran_filter"]
assert !assigns["ran_class_filter"]
assert !assigns["ran_proc_filter1"]
assert !assigns["ran_proc_filter2"]
@@ -530,16 +530,16 @@ class FilterTest < ActionController::TestCase
test_process(ConditionalCollectionFilterController)
assert_equal %w( ensure_login ), assigns["ran_filter"]
test_process(ConditionalCollectionFilterController, "show_without_filter")
- assert_equal nil, assigns["ran_filter"]
+ assert_nil assigns["ran_filter"]
test_process(ConditionalCollectionFilterController, "another_action")
- assert_equal nil, assigns["ran_filter"]
+ assert_nil assigns["ran_filter"]
end
def test_running_only_condition_filters
test_process(OnlyConditionSymController)
assert_equal %w( ensure_login ), assigns["ran_filter"]
test_process(OnlyConditionSymController, "show_without_filter")
- assert_equal nil, assigns["ran_filter"]
+ assert_nil assigns["ran_filter"]
test_process(OnlyConditionProcController)
assert assigns["ran_proc_filter"]
@@ -556,7 +556,7 @@ class FilterTest < ActionController::TestCase
test_process(ExceptConditionSymController)
assert_equal %w( ensure_login ), assigns["ran_filter"]
test_process(ExceptConditionSymController, "show_without_filter")
- assert_equal nil, assigns["ran_filter"]
+ assert_nil assigns["ran_filter"]
test_process(ExceptConditionProcController)
assert assigns["ran_proc_filter"]
@@ -573,7 +573,7 @@ class FilterTest < ActionController::TestCase
test_process(BeforeAndAfterConditionController)
assert_equal %w( ensure_login clean_up_tmp), assigns["ran_filter"]
test_process(BeforeAndAfterConditionController, "show_without_filter")
- assert_equal nil, assigns["ran_filter"]
+ assert_nil assigns["ran_filter"]
end
def test_around_filter
@@ -674,7 +674,7 @@ class FilterTest < ActionController::TestCase
def test_changing_the_requirements
test_process(ChangingTheRequirementsController, "go_wild")
- assert_equal nil, assigns['ran_filter']
+ assert_nil assigns['ran_filter']
end
def test_a_rescuing_around_filter
diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb
index c662ce264b..01c8fd90a5 100644
--- a/actionpack/test/controller/flash_test.rb
+++ b/actionpack/test/controller/flash_test.rb
@@ -237,10 +237,19 @@ class FlashIntegrationTest < ActionController::IntegrationTest
end
private
+
+ # Overwrite get to send SessionSecret in env hash
+ def get(path, parameters = nil, env = {})
+ env["action_dispatch.secret_token"] ||= SessionSecret
+ super
+ end
+
def with_test_route_set
with_routing do |set|
set.draw do |map|
- match ':action', :to => ActionDispatch::Session::CookieStore.new(FlashIntegrationTest::TestController, :key => FlashIntegrationTest::SessionKey, :secret => FlashIntegrationTest::SessionSecret)
+ match ':action', :to => ActionDispatch::Session::CookieStore.new(
+ FlashIntegrationTest::TestController, :key => SessionKey, :secret => SessionSecret
+ )
end
yield
end
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 20dc96d38d..5ee8e2b6ae 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -176,8 +176,8 @@ class IntegrationTestTest < Test::Unit::TestCase
session1 = @test.open_session { |sess| }
session2 = @test.open_session # implicit session
- assert session1.respond_to?(:assert_template), "open_session makes assert_template available"
- assert session2.respond_to?(:assert_template), "open_session makes assert_template available"
+ assert_respond_to session1, :assert_template, "open_session makes assert_template available"
+ assert_respond_to session2, :assert_template, "open_session makes assert_template available"
assert !session1.equal?(session2)
end
diff --git a/actionpack/test/controller/new_base/bare_metal_test.rb b/actionpack/test/controller/new_base/bare_metal_test.rb
index df4b39a103..8a06e8d2a0 100644
--- a/actionpack/test/controller/new_base/bare_metal_test.rb
+++ b/actionpack/test/controller/new_base/bare_metal_test.rb
@@ -18,10 +18,10 @@ module BareMetalTest
string << part
end
- assert headers.is_a?(Hash), "Headers must be a Hash"
+ assert_kind_of Hash, headers, "Headers must be a Hash"
assert headers["Content-Type"], "Content-Type must exist"
assert_equal "Hello world", string
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 52049f2a8a..2b1f2a27df 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -1079,7 +1079,7 @@ class RenderTest < ActionController::TestCase
def test_action_talk_to_layout
get :action_talk_to_layout
- assert_equal "<title>Talking to the layout</title>\n\nAction was here!", @response.body
+ assert_equal "<title>Talking to the layout</title>\nAction was here!", @response.body
end
# :addressed:
@@ -1096,7 +1096,7 @@ class RenderTest < ActionController::TestCase
def test_yield_content_for
assert_not_deprecated { get :yield_content_for }
- assert_equal "<title>Putting stuff in the title!</title>\n\nGreat stuff!\n", @response.body
+ assert_equal "<title>Putting stuff in the title!</title>\nGreat stuff!\n", @response.body
end
def test_overwritting_rendering_relative_file_with_extension
diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb
index 36b8055810..c7c8360ae6 100644
--- a/actionpack/test/controller/send_file_test.rb
+++ b/actionpack/test/controller/send_file_test.rb
@@ -55,8 +55,8 @@ class SendFileTest < ActionController::TestCase
response = nil
assert_nothing_raised { response = process('file') }
assert_not_nil response
- assert response.body_parts.respond_to?(:each)
- assert response.body_parts.respond_to?(:to_path)
+ assert_respond_to response.body_parts, :each
+ assert_respond_to response.body_parts, :to_path
require 'stringio'
output = StringIO.new
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index c7f7f3102d..c20fa10f63 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -113,6 +113,10 @@ class ResponseTest < ActiveSupport::TestCase
status, headers, body = @response.to_a
assert_equal "user_name=david; path=/\nlogin=foo%26bar; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT", headers["Set-Cookie"]
assert_equal({"login" => "foo&bar", "user_name" => "david"}, @response.cookies)
+
+ @response.delete_cookie("login")
+ status, headers, body = @response.to_a
+ assert_equal({"user_name" => "david", "login" => nil}, @response.cookies)
end
test "read cache control" do
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 651a7a6be0..180889ddf2 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -186,6 +186,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
resources :products, :constraints => { :id => /\d{4}/ } do
+ root :to => "products#root"
+ get :favorite, :on => :collection
resources :images
end
@@ -963,7 +965,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/products/1'
assert_equal 'pass', @response.headers['X-Cascade']
get '/products'
- assert_equal 'products#index', @response.body
+ assert_equal 'products#root', @response.body
+ get '/products/favorite'
+ assert_equal 'products#favorite', @response.body
get '/products/0001'
assert_equal 'products#show', @response.body
@@ -981,6 +985,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_root_works_in_the_resources_scope
+ get '/products'
+ assert_equal 'products#root', @response.body
+ assert_equal '/products', products_root_path
+ end
+
def test_module_scope
with_test_routes do
get '/token'
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index d2c1758af1..21d11ff31c 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -55,42 +55,13 @@ class CookieStoreTest < ActionController::IntegrationTest
}
end
- def test_raises_argument_error_if_missing_secret
- assert_raise(ArgumentError, nil.inspect) {
- ActionDispatch::Session::CookieStore.new(nil,
- :key => SessionKey, :secret => nil)
- }
-
- assert_raise(ArgumentError, ''.inspect) {
- ActionDispatch::Session::CookieStore.new(nil,
- :key => SessionKey, :secret => '')
- }
- end
-
- def test_raises_argument_error_if_secret_is_probably_insecure
- assert_raise(ArgumentError, "password".inspect) {
- ActionDispatch::Session::CookieStore.new(nil,
- :key => SessionKey, :secret => "password")
- }
-
- assert_raise(ArgumentError, "secret".inspect) {
- ActionDispatch::Session::CookieStore.new(nil,
- :key => SessionKey, :secret => "secret")
- }
-
- assert_raise(ArgumentError, "12345678901234567890123456789".inspect) {
- ActionDispatch::Session::CookieStore.new(nil,
- :key => SessionKey, :secret => "12345678901234567890123456789")
- }
- end
-
def test_setting_session_value
with_test_route_set do
get '/set_session_value'
assert_response :success
assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly",
headers['Set-Cookie']
- end
+ end
end
def test_getting_session_value
@@ -99,7 +70,7 @@ class CookieStoreTest < ActionController::IntegrationTest
get '/get_session_value'
assert_response :success
assert_equal 'foo: "bar"', response.body
- end
+ end
end
def test_getting_session_id
@@ -127,7 +98,7 @@ class CookieStoreTest < ActionController::IntegrationTest
def test_close_raises_when_data_overflows
with_test_route_set do
- assert_raise(ActionDispatch::Session::CookieStore::CookieOverflow) {
+ assert_raise(ActionDispatch::Cookies::CookieOverflow) {
get '/raise_data_overflow'
}
end
@@ -209,30 +180,33 @@ class CookieStoreTest < ActionController::IntegrationTest
get '/no_session_access'
assert_response :success
- # Mystery bug that came up in 2.3 as well. What is this trying to test?!
- # assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly",
- # headers['Set-Cookie']
+ assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly",
+ headers['Set-Cookie']
end
end
private
+
+ # Overwrite get to send SessionSecret in env hash
+ def get(path, parameters = nil, env = {})
+ env["action_dispatch.secret_token"] ||= SessionSecret
+ super
+ end
+
def with_test_route_set(options = {})
with_routing do |set|
set.draw do |map|
match ':action', :to => ::CookieStoreTest::TestController
end
- options = {:key => SessionKey, :secret => SessionSecret}.merge(options)
- @app = ActionDispatch::Session::CookieStore.new(set, options)
+
+ options = { :key => SessionKey }.merge!(options)
+
+ @app = self.class.build_app(set) do |middleware|
+ middleware.use ActionDispatch::Session::CookieStore, options
+ middleware.delete "ActionDispatch::ShowExceptions"
+ end
+
yield
end
end
-
- def unmarshal_session(cookie_string)
- session = Rack::Utils.parse_query(cookie_string, ';,').inject({}) {|h,(k,v)|
- h[k] = Array === v ? v.first : v
- h
- }[SessionKey]
- verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1')
- verifier.verify(session)
- end
end
diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb
index 5a1dcb4dab..8858a398e0 100644
--- a/actionpack/test/dispatch/session/mem_cache_store_test.rb
+++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb
@@ -114,7 +114,12 @@ class MemCacheStoreTest < ActionController::IntegrationTest
set.draw do |map|
match ':action', :to => ::MemCacheStoreTest::TestController
end
- @app = ActionDispatch::Session::MemCacheStore.new(set, :key => '_session_id')
+
+ @app = self.class.build_app(set) do |middleware|
+ middleware.use ActionDispatch::Session::MemCacheStore, :key => '_session_id'
+ middleware.delete "ActionDispatch::ShowExceptions"
+ end
+
yield
end
end
diff --git a/actionpack/test/dispatch/session/test_session_test.rb b/actionpack/test/dispatch/session/test_session_test.rb
index c8dc4ab461..31ce97a25b 100644
--- a/actionpack/test/dispatch/session/test_session_test.rb
+++ b/actionpack/test/dispatch/session/test_session_test.rb
@@ -2,18 +2,6 @@ require 'abstract_unit'
require 'stringio'
class ActionController::TestSessionTest < ActiveSupport::TestCase
- def test_calling_delete_without_parameters_raises_deprecation_warning_and_calls_to_clear_test_session
- assert_deprecated(/use clear instead/){ ActionController::TestSession.new.delete }
- end
-
- def test_calling_update_without_parameters_raises_deprecation_warning_and_calls_to_clear_test_session
- assert_deprecated(/use replace instead/){ ActionController::TestSession.new.update }
- end
-
- def test_calling_close_raises_deprecation_warning
- assert_deprecated(/sessions should no longer be closed/){ ActionController::TestSession.new.close }
- end
-
def test_ctor_allows_setting
session = ActionController::TestSession.new({:one => 'one', :two => 'two'})
assert_equal('one', session[:one])
diff --git a/actionpack/test/fixtures/test/content_for.erb b/actionpack/test/fixtures/test/content_for.erb
index 0e47ca8c3d..1fb829f54c 100644
--- a/actionpack/test/fixtures/test/content_for.erb
+++ b/actionpack/test/fixtures/test/content_for.erb
@@ -1,2 +1 @@
-<% content_for :title do %>Putting stuff in the title!<% end %>
-Great stuff! \ No newline at end of file
+<% content_for :title do -%>Putting stuff in the title!<% end -%>Great stuff! \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/content_for_concatenated.erb b/actionpack/test/fixtures/test/content_for_concatenated.erb
index fb6b4b05d7..e65f629574 100644
--- a/actionpack/test/fixtures/test/content_for_concatenated.erb
+++ b/actionpack/test/fixtures/test/content_for_concatenated.erb
@@ -1,3 +1,3 @@
<% content_for :title, "Putting stuff "
- content_for :title, "in the title!" %>
+ content_for :title, "in the title!" -%>
Great stuff! \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/content_for_with_parameter.erb b/actionpack/test/fixtures/test/content_for_with_parameter.erb
index 57aecbac05..aeb6f73ce0 100644
--- a/actionpack/test/fixtures/test/content_for_with_parameter.erb
+++ b/actionpack/test/fixtures/test/content_for_with_parameter.erb
@@ -1,2 +1,2 @@
-<% content_for :title, "Putting stuff in the title!" %>
+<% content_for :title, "Putting stuff in the title!" -%>
Great stuff! \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/non_erb_block_content_for.builder b/actionpack/test/fixtures/test/non_erb_block_content_for.builder
index a94643561c..d539a425a4 100644
--- a/actionpack/test/fixtures/test/non_erb_block_content_for.builder
+++ b/actionpack/test/fixtures/test/non_erb_block_content_for.builder
@@ -1,4 +1,4 @@
content_for :title do
'Putting stuff in the title!'
end
-xml << "\nGreat stuff!"
+xml << "Great stuff!"
diff --git a/actionpack/test/template/number_helper_i18n_test.rb b/actionpack/test/template/number_helper_i18n_test.rb
index f730a0d7f5..8561019461 100644
--- a/actionpack/test/template/number_helper_i18n_test.rb
+++ b/actionpack/test/template/number_helper_i18n_test.rb
@@ -45,6 +45,12 @@ class NumberHelperTest < ActionView::TestCase
assert_equal("&$ - 10.00", number_to_currency(10, :locale => 'ts'))
end
+ def test_number_to_currency_with_clean_i18n_settings
+ clean_i18n do
+ assert_equal("$10.00", number_to_currency(10))
+ end
+ end
+
def test_number_with_precision
#Delimiter was set to ""
assert_equal("10000", number_with_precision(10000, :locale => 'ts'))
@@ -92,4 +98,15 @@ class NumberHelperTest < ActionView::TestCase
#Significant was set to true with precision 2, with custom translated units
assert_equal "4.3 cm", number_to_human(0.0432, :locale => 'ts', :units => :custom_units_for_number_to_human)
end
+
+ private
+ def clean_i18n
+ load_path = I18n.load_path.dup
+ I18n.load_path.clear
+ I18n.reload!
+ yield
+ ensure
+ I18n.load_path = load_path
+ I18n.reload!
+ end
end
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index d0212024ae..aca96e0a24 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -232,13 +232,13 @@ module RenderTestCases
# TODO: Move to deprecated_tests.rb
def test_render_with_nested_layout_deprecated
assert_deprecated do
- assert_equal %(<title>title</title>\n\n\n<div id="column">column</div>\n<div id="content">content</div>\n),
+ assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n),
@view.render(:file => "test/deprecated_nested_layout.erb", :layout => "layouts/yield")
end
end
def test_render_with_nested_layout
- assert_equal %(<title>title</title>\n\n\n<div id="column">column</div>\n<div id="content">content</div>\n),
+ assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n),
@view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield")
end
@@ -284,7 +284,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase
with_external_encoding Encoding::ASCII_8BIT do
result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield")
assert_equal Encoding::UTF_8, result.encoding
- assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result
+ assert_equal "\nРусский \nтекст\n\nUTF-8\nUTF-8\nUTF-8\n", result
end
end
@@ -302,7 +302,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase
result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield")
flunk 'Should have raised incompatible encoding error'
rescue ActionView::Template::Error => error
- assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message
+ assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message
end
end
end
@@ -313,7 +313,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase
result = @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield")
flunk 'Should have raised incompatible encoding error'
rescue ActionView::Template::Error => error
- assert_match 'invalid byte sequence in Shift_JIS', error.original_exception.message
+ assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message
end
end
end
diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb
new file mode 100644
index 0000000000..995d728d50
--- /dev/null
+++ b/actionpack/test/template/template_test.rb
@@ -0,0 +1,130 @@
+require "abstract_unit"
+
+if "ruby".encoding_aware?
+ # These are the normal settings that will be set up by Railties
+ # TODO: Have these tests support other combinations of these values
+ Encoding.default_internal = "UTF-8"
+ Encoding.default_external = "UTF-8"
+end
+
+class TestERBTemplate < ActiveSupport::TestCase
+ ERBHandler = ActionView::Template::Handlers::ERB
+
+ class Context
+ def initialize
+ @output_buffer = "original"
+ end
+
+ def hello
+ "Hello"
+ end
+
+ def partial
+ ActionView::Template.new(
+ "<%= @_virtual_path %>",
+ "partial",
+ ERBHandler,
+ :virtual_path => "partial"
+ )
+ end
+
+ def logger
+ require "logger"
+ Logger.new(STDERR)
+ end
+
+ def my_buffer
+ @output_buffer
+ end
+ end
+
+ def new_template(body = "<%= hello %>", handler = ERBHandler, details = {})
+ ActionView::Template.new(body, "hello template", ERBHandler, {:virtual_path => "hello"})
+ end
+
+ def render(locals = {})
+ @template.render(@obj, locals)
+ end
+
+ def setup
+ @obj = Context.new
+ end
+
+ def test_basic_template
+ @template = new_template
+ assert_equal "Hello", render
+ end
+
+ def test_locals
+ @template = new_template("<%= my_local %>")
+ assert_equal "I'm a local", render(:my_local => "I'm a local")
+ end
+
+ def test_restores_buffer
+ @template = new_template
+ assert_equal "Hello", render
+ assert_equal "original", @obj.my_buffer
+ end
+
+ def test_virtual_path
+ @template = new_template("<%= @_virtual_path %>" \
+ "<%= partial.render(self, {}) %>" \
+ "<%= @_virtual_path %>")
+ assert_equal "hellopartialhello", render
+ end
+
+ if "ruby".encoding_aware?
+ def test_resulting_string_is_utf8
+ @template = new_template
+ assert_equal Encoding::UTF_8, render.encoding
+ end
+
+ def test_no_magic_comment_word_with_utf_8
+ @template = new_template("hello \u{fc}mlat")
+ assert_equal Encoding::UTF_8, render.encoding
+ assert_equal "hello \u{fc}mlat", render
+ end
+
+ # This test ensures that if the default_external
+ # is set to something other than UTF-8, we don't
+ # get any errors and get back a UTF-8 String.
+ def test_default_external_works
+ Encoding.default_external = "ISO-8859-1"
+ @template = new_template("hello \xFCmlat")
+ assert_equal Encoding::UTF_8, render.encoding
+ assert_equal "hello \u{fc}mlat", render
+ ensure
+ Encoding.default_external = "UTF-8"
+ end
+
+ def test_encoding_can_be_specified_with_magic_comment
+ @template = new_template("# encoding: ISO-8859-1\nhello \xFCmlat")
+ assert_equal Encoding::UTF_8, render.encoding
+ assert_equal "\nhello \u{fc}mlat", render
+ end
+
+ # TODO: This is currently handled inside ERB. The case of explicitly
+ # lying about encodings via the normal Rails API should be handled
+ # inside Rails.
+ def test_lying_with_magic_comment
+ assert_raises(ActionView::Template::Error) do
+ @template = new_template("# encoding: UTF-8\nhello \xFCmlat")
+ render
+ end
+ end
+
+ def test_encoding_can_be_specified_with_magic_comment_in_erb
+ @template = new_template("<%# encoding: ISO-8859-1 %>hello \xFCmlat")
+ result = render
+ assert_equal Encoding::UTF_8, render.encoding
+ assert_equal "hello \u{fc}mlat", render
+ end
+
+ def test_error_when_template_isnt_valid_utf8
+ assert_raises(ActionView::Template::Error, /\xFC/) do
+ @template = new_template("hello \xFCmlat")
+ render
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index 716010e88b..062b4cd17f 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -57,10 +57,15 @@ module ActiveModel
protected
def parse_raw_value_as_a_number(raw_value)
- begin
- Kernel.Float(raw_value)
- rescue ArgumentError, TypeError
+ case raw_value
+ when /\A0[xX]/
nil
+ else
+ begin
+ Kernel.Float(raw_value)
+ rescue ArgumentError, TypeError
+ nil
+ end
end
end
diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb
index 5659dcbc48..c60caf90d7 100644
--- a/activemodel/test/cases/attribute_methods_test.rb
+++ b/activemodel/test/cases/attribute_methods_test.rb
@@ -31,7 +31,7 @@ class AttributeMethodsTest < ActiveModel::TestCase
ModelWithAttributes.define_attribute_methods([:foo])
assert ModelWithAttributes.attribute_methods_generated?
- assert ModelWithAttributes.new.respond_to?(:foo)
+ assert_respond_to ModelWithAttributes.new, :foo
assert_equal "value of foo", ModelWithAttributes.new.foo
end
diff --git a/activemodel/test/cases/callbacks_test.rb b/activemodel/test/cases/callbacks_test.rb
index b996f51d6b..9675b5d450 100644
--- a/activemodel/test/cases/callbacks_test.rb
+++ b/activemodel/test/cases/callbacks_test.rb
@@ -65,6 +65,6 @@ class CallbacksTest < ActiveModel::TestCase
test "only selects which types of callbacks should be created" do
assert !ModelCallbacks.respond_to?(:before_initialize)
assert !ModelCallbacks.respond_to?(:around_initialize)
- assert ModelCallbacks.respond_to?(:after_initialize)
+ assert_respond_to ModelCallbacks, :after_initialize
end
end
diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb
index c910cb43d4..e1a35be384 100644
--- a/activemodel/test/cases/dirty_test.rb
+++ b/activemodel/test/cases/dirty_test.rb
@@ -22,8 +22,8 @@ class DirtyTest < ActiveModel::TestCase
test "changes accessible through both strings and symbols" do
model = DirtyModel.new
model.name = "David"
- assert !model.changes[:name].nil?
- assert !model.changes['name'].nil?
+ assert_not_nil model.changes[:name]
+ assert_not_nil model.changes['name']
end
end
diff --git a/activemodel/test/cases/serializeration/xml_serialization_test.rb b/activemodel/test/cases/serializeration/xml_serialization_test.rb
index 4e8e4efa25..ff786658b7 100644
--- a/activemodel/test/cases/serializeration/xml_serialization_test.rb
+++ b/activemodel/test/cases/serializeration/xml_serialization_test.rb
@@ -17,6 +17,9 @@ module Admin
end
end
+class Customer < Struct.new(:name)
+end
+
class XmlSerializationTest < ActiveModel::TestCase
def setup
@contact = Contact.new
@@ -24,7 +27,7 @@ class XmlSerializationTest < ActiveModel::TestCase
@contact.age = 25
@contact.created_at = Time.utc(2006, 8, 1)
@contact.awesome = false
- customer = OpenStruct.new
+ customer = Customer.new
customer.name = "John"
@contact.preferences = customer
end
@@ -69,7 +72,7 @@ class XmlSerializationTest < ActiveModel::TestCase
test "should allow skipped types" do
@xml = @contact.to_xml :skip_types => true
- assert %r{<age>25</age>}.match(@xml)
+ assert_match %r{<age>25</age>}, @xml
end
test "should include yielded additions" do
@@ -104,7 +107,7 @@ class XmlSerializationTest < ActiveModel::TestCase
end
test "should serialize yaml" do
- assert_match %r{<preferences type=\"yaml\">--- !ruby/object:OpenStruct \ntable:\s*:name: John\n</preferences>}, @contact.to_xml
+ assert_match %r{<preferences type=\"yaml\">--- !ruby/struct:Customer \nname: John\n</preferences>}, @contact.to_xml
end
test "should call proc on object" do
diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb
index be620c53fa..8e77a0222e 100644
--- a/activemodel/test/cases/validations/numericality_validation_test.rb
+++ b/activemodel/test/cases/validations/numericality_validation_test.rb
@@ -18,7 +18,7 @@ class NumericalityValidationTest < ActiveModel::TestCase
FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001] + FLOAT_STRINGS
INTEGERS = [0, 10, -10] + INTEGER_STRINGS
BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal.new(bd) }
- JUNK = ["not a number", "42 not a number", "0xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"]
+ JUNK = ["not a number", "42 not a number", "0xdeadbeef", "0xinvalidhex", "0Xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"]
INFINITY = [1.0/0.0]
def test_default_validates_numericality_of
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index fd1082a268..c553e95bad 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -214,6 +214,12 @@ module ActiveRecord
@marked_for_destruction
end
+ # Returns whether or not this record has been changed in any way (including whether
+ # any of its nested autosave associations are likewise changed)
+ def changed_for_autosave?
+ new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
+ end
+
private
# Returns the record for an association collection that should be validated
@@ -223,12 +229,27 @@ module ActiveRecord
if new_record
association
elsif autosave
- association.target.find_all { |record| record.new_record? || record.changed? || record.marked_for_destruction? }
+ association.target.find_all { |record| record.changed_for_autosave? }
else
association.target.find_all { |record| record.new_record? }
end
end
+ # go through nested autosave associations that are loaded in memory (without loading
+ # any new ones), and return true if is changed for autosave
+ def nested_records_changed_for_autosave?
+ self.class.reflect_on_all_autosave_associations.each do |reflection|
+ if association = association_instance_get(reflection.name)
+ if [:belongs_to, :has_one].include?(reflection.macro)
+ return true if association.target && association.target.changed_for_autosave?
+ else
+ association.target.each {|record| return true if record.changed_for_autosave? }
+ end
+ end
+ end
+ false
+ end
+
# Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
# turned on for the association specified by +reflection+.
def validate_single_association(reflection)
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index c02af328c1..1b76f357e3 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1193,10 +1193,6 @@ module ActiveRecord #:nodoc:
self.default_scoping << construct_finder_arel(options, default_scoping.pop)
end
- def clear_default_scope
- self.default_scoping.clear
- end
-
def scoped_methods #:nodoc:
key = :"#{self}_scoped_methods"
Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup
@@ -1362,7 +1358,8 @@ module ActiveRecord #:nodoc:
def replace_bind_variables(statement, values) #:nodoc:
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
bound = values.dup
- statement.gsub('?') { quote_bound_value(bound.shift) }
+ c = connection
+ statement.gsub('?') { quote_bound_value(bound.shift, c) }
end
def replace_named_bind_variables(statement, bind_vars) #:nodoc:
@@ -1394,15 +1391,15 @@ module ActiveRecord #:nodoc:
expanded
end
- def quote_bound_value(value) #:nodoc:
+ def quote_bound_value(value, c = connection) #:nodoc:
if value.respond_to?(:map) && !value.acts_like?(:string)
if value.respond_to?(:empty?) && value.empty?
- connection.quote(nil)
+ c.quote(nil)
else
- value.map { |v| connection.quote(v) }.join(',')
+ value.map { |v| c.quote(v) }.join(',')
end
else
- connection.quote(value)
+ c.quote(value)
end
end
@@ -1462,12 +1459,18 @@ module ActiveRecord #:nodoc:
callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
cloned_attributes.delete(self.class.primary_key)
+
@attributes = cloned_attributes
+
+ @changed_attributes = {}
+ attributes_from_column_definition.each do |attr, orig_value|
+ @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr])
+ end
+
clear_aggregation_cache
@attributes_cache = {}
@new_record = true
ensure_proper_type
- @changed_attributes = other.changed_attributes.dup
if scope = self.class.send(:current_scoped_methods)
create_with = scope.scope_for_create
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
new file mode 100644
index 0000000000..4118ea7b31
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
@@ -0,0 +1,57 @@
+module ActiveRecord
+ module ConnectionAdapters # :nodoc:
+ module DatabaseLimits
+
+ # the maximum length of a table alias
+ def table_alias_length
+ 255
+ end
+
+ # the maximum length of a column name
+ def column_name_length
+ 64
+ end
+
+ # the maximum length of a table name
+ def table_name_length
+ 64
+ end
+
+ # the maximum length of an index name
+ def index_name_length
+ 64
+ end
+
+ # the maximum number of columns per table
+ def columns_per_table
+ 1024
+ end
+
+ # the maximum number of indexes per table
+ def indexes_per_table
+ 16
+ end
+
+ # the maximum number of columns in a multicolumn index
+ def columns_per_multicolumn_index
+ 16
+ end
+
+ # the maximum number of elements in an IN (x,y,z) clause
+ def in_clause_length
+ 65535
+ end
+
+ # the maximum length of a SQL query
+ def sql_query_length
+ 1048575
+ end
+
+ # maximum number of joins in a single query
+ def joins_per_query
+ 256
+ end
+
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 1255ef09be..d3499cea72 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -10,11 +10,6 @@ module ActiveRecord
{}
end
- # This is the maximum length a table alias can be
- def table_alias_length
- 255
- end
-
# Truncates a table alias according to the limits of the current adapter.
def table_alias_for(table_name)
table_name[0..table_alias_length-1].gsub(/\./, '_')
@@ -293,6 +288,14 @@ module ActiveRecord
index_type = options
end
+ if index_name.length > index_name_length
+ @logger.warn("Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters. Skipping.")
+ return
+ end
+ if index_exists?(table_name, index_name, false)
+ @logger.warn("Index name '#{index_name}' on table '#{table_name}' already exists. Skipping.")
+ return
+ end
quoted_column_names = quoted_columns_for_index(column_names, options).join(", ")
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
@@ -309,7 +312,28 @@ module ActiveRecord
# Remove the index named by_branch_party in the accounts table.
# remove_index :accounts, :name => :by_branch_party
def remove_index(table_name, options = {})
- execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{quote_table_name(table_name)}"
+ index_name = index_name(table_name, options)
+ unless index_exists?(table_name, index_name, true)
+ @logger.warn("Index name '#{index_name}' on table '#{table_name}' does not exist. Skipping.")
+ return
+ end
+ remove_index!(table_name, index_name)
+ end
+
+ def remove_index!(table_name, index_name) #:nodoc:
+ execute "DROP INDEX #{quote_column_name(index_name)} ON #{table_name}"
+ end
+
+ # Rename an index.
+ #
+ # Rename the index_people_on_last_name index to index_users_on_last_name
+ # rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
+ def rename_index(table_name, old_name, new_name)
+ # this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
+ old_index_def = indexes(table_name).detect { |i| i.name == old_name }
+ return unless old_index_def
+ remove_index(table_name, :name => old_name)
+ add_index(table_name, old_index_def.columns, :name => new_name, :unique => old_index_def.unique)
end
def index_name(table_name, options) #:nodoc:
@@ -326,6 +350,15 @@ module ActiveRecord
end
end
+ # Verify the existence of an index.
+ #
+ # The default argument is returned if the underlying implementation does not define the indexes method,
+ # as there's no way to determine the correct answer in that case.
+ def index_exists?(table_name, index_name, default)
+ return default unless respond_to?(:indexes)
+ indexes(table_name).detect { |i| i.name == index_name }
+ end
+
# Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
# entire structure of the database.
def structure_dump
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 28a59c1e62..fecd4d590e 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -11,6 +11,7 @@ require 'active_record/connection_adapters/abstract/quoting'
require 'active_record/connection_adapters/abstract/connection_pool'
require 'active_record/connection_adapters/abstract/connection_specification'
require 'active_record/connection_adapters/abstract/query_cache'
+require 'active_record/connection_adapters/abstract/database_limits'
module ActiveRecord
module ConnectionAdapters # :nodoc:
@@ -29,6 +30,7 @@ module ActiveRecord
# notably, the instance methods provided by SchemaStatement are very useful.
class AbstractAdapter
include Quoting, DatabaseStatements, SchemaStatements
+ include DatabaseLimits
include QueryCache
include ActiveSupport::Callbacks
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index e12924e63f..ec25bbf18e 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -513,7 +513,7 @@ module ActiveRecord
def change_column(table_name, column_name, type, options = {}) #:nodoc:
column = column_for(table_name, column_name)
- if has_default?(type) && !options_include_default?(options)
+ unless options_include_default?(options)
options[:default] = column.default
end
@@ -675,10 +675,6 @@ module ActiveRecord
end
column
end
-
- def has_default?(sql_type)
- sql_type =~ :binary || sql_type == :text #mysql forbids defaults on blob and text columns
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 6389094b8a..34aaff2b49 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -819,9 +819,12 @@ module ActiveRecord
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
end
- # Drops an index from a table.
- def remove_index(table_name, options = {})
- execute "DROP INDEX #{quote_table_name(index_name(table_name, options))}"
+ def remove_index!(table_name, index_name) #:nodoc:
+ execute "DROP INDEX #{quote_table_name(index_name)}"
+ end
+
+ def index_name_length
+ 63
end
# Maps logical Rails types to PostgreSQL-specific data types.
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index 29225b83c5..e8a45bb3c6 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -217,8 +217,8 @@ module ActiveRecord
column ? column['name'] : nil
end
- def remove_index(table_name, options={}) #:nodoc:
- execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
+ def remove_index!(table_name, index_name) #:nodoc:
+ execute "DROP INDEX #{quote_column_name(index_name)}"
end
def rename_table(name, new_name)
diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb
index 9dda3361d8..931872eded 100644
--- a/activerecord/lib/active_record/session_store.rb
+++ b/activerecord/lib/active_record/session_store.rb
@@ -307,7 +307,7 @@ module ActiveRecord
end
end
- return true
+ sid
end
def get_session_model(env, sid)
diff --git a/activerecord/test/cases/active_schema_test_mysql.rb b/activerecord/test/cases/active_schema_test_mysql.rb
index f4d123be15..3526f49afd 100644
--- a/activerecord/test/cases/active_schema_test_mysql.rb
+++ b/activerecord/test/cases/active_schema_test_mysql.rb
@@ -16,6 +16,10 @@ class ActiveSchemaTest < ActiveRecord::TestCase
end
def test_add_index
+ # add_index calls index_exists? which can't work since execute is stubbed
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:define_method, :index_exists?) do |*|
+ false
+ end
expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`)"
assert_equal expected, add_index(:people, :last_name, :length => nil)
@@ -30,6 +34,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase
expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10))"
assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15, :first_name => 10})
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:remove_method, :index_exists?)
end
def test_drop_table
diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb
index 8b6ec04018..e5fc1a2046 100644
--- a/activerecord/test/cases/aggregations_test.rb
+++ b/activerecord/test/cases/aggregations_test.rb
@@ -58,36 +58,36 @@ class AggregationsTest < ActiveRecord::TestCase
end
def test_gps_equality
- assert GpsLocation.new('39x110') == GpsLocation.new('39x110')
+ assert_equal GpsLocation.new('39x110'), GpsLocation.new('39x110')
end
def test_gps_inequality
- assert GpsLocation.new('39x110') != GpsLocation.new('39x111')
+ assert_not_equal GpsLocation.new('39x110'), GpsLocation.new('39x111')
end
def test_allow_nil_gps_is_nil
- assert_equal nil, customers(:zaphod).gps_location
+ assert_nil customers(:zaphod).gps_location
end
def test_allow_nil_gps_set_to_nil
customers(:david).gps_location = nil
customers(:david).save
customers(:david).reload
- assert_equal nil, customers(:david).gps_location
+ assert_nil customers(:david).gps_location
end
def test_allow_nil_set_address_attributes_to_nil
customers(:zaphod).address = nil
- assert_equal nil, customers(:zaphod).attributes[:address_street]
- assert_equal nil, customers(:zaphod).attributes[:address_city]
- assert_equal nil, customers(:zaphod).attributes[:address_country]
+ assert_nil customers(:zaphod).attributes[:address_street]
+ assert_nil customers(:zaphod).attributes[:address_city]
+ assert_nil customers(:zaphod).attributes[:address_country]
end
def test_allow_nil_address_set_to_nil
customers(:zaphod).address = nil
customers(:zaphod).save
customers(:zaphod).reload
- assert_equal nil, customers(:zaphod).address
+ assert_nil customers(:zaphod).address
end
def test_nil_raises_error_when_allow_nil_is_false
@@ -104,9 +104,9 @@ class AggregationsTest < ActiveRecord::TestCase
def test_nil_assignment_results_in_nil
customers(:david).gps_location = GpsLocation.new('39x111')
- assert_not_equal nil, customers(:david).gps_location
+ assert_not_nil customers(:david).gps_location
customers(:david).gps_location = nil
- assert_equal nil, customers(:david).gps_location
+ assert_nil customers(:david).gps_location
end
def test_custom_constructor
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index be77ee4bf3..9258c987ef 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -403,7 +403,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal saved_member.id, sponsor.sponsorable_id
sponsor.sponsorable = new_member
- assert_equal nil, sponsor.sponsorable_id
+ assert_nil sponsor.sponsorable_id
end
def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records
@@ -415,7 +415,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal saved_writer.name, essay.writer_id
essay.writer = new_writer
- assert_equal nil, essay.writer_id
+ assert_nil essay.writer_id
end
def test_belongs_to_proxy_should_not_respond_to_private_methods
diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
index 7c470616a5..b124a2bfc3 100644
--- a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
+++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
@@ -29,7 +29,7 @@ class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase
ActiveRecord::Base.store_full_sti_class = true
post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging )
- assert_equal 'Tagging', post.tagging.class.name
+ assert_instance_of Tagging, post.tagging
ensure
ActiveRecord::Base.store_full_sti_class = old
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 79e5ecf4ce..445e6889c0 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -110,7 +110,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
author = assert_queries(3) { Author.find(author_id, :include => {:posts_with_comments => :comments}) } # find the author, then find the posts, then find the comments
author.posts_with_comments.each do |post_with_comments|
assert_equal post_with_comments.comments.length, post_with_comments.comments.count
- assert_equal nil, post_with_comments.comments.uniq!
+ assert_nil post_with_comments.comments.uniq!
end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 6e47967696..8e5bc56008 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -175,14 +175,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
c = Client.new
assert_nil c.firm
- if c.firm
- assert false, "belongs_to failed if check"
- end
-
- unless c.firm
- else
- assert false, "belongs_to failed unless check"
- end
+ flunk "belongs_to failed if check" if c.firm
end
def test_find_ids
@@ -620,7 +613,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal [], Client.destroyed_client_ids[firm.id]
# Should be destroyed since the association is exclusively dependent.
- assert Client.find_by_id(client_id).nil?
+ assert_nil Client.find_by_id(client_id)
end
def test_dependent_association_respects_optional_conditions_on_delete
@@ -669,7 +662,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
old_record = firm.clients_using_primary_key_with_delete_all.first
firm = Firm.find(:first)
firm.destroy
- assert Client.find_by_id(old_record.id).nil?
+ assert_nil Client.find_by_id(old_record.id)
end
def test_creation_respects_hash_condition
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index ff799191c2..e4dd810732 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -63,8 +63,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert_queries(1) { posts(:thinking) }
assert_queries(0) do
- posts(:thinking).people.build(:first_name=>"Bob")
- posts(:thinking).people.new(:first_name=>"Ted")
+ posts(:thinking).people.build(:first_name => "Bob")
+ posts(:thinking).people.new(:first_name => "Ted")
end
# Should only need to load the association once
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 8f5540950e..469a21b9bf 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -149,7 +149,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
num_accounts = Account.count
firm = Firm.find(1)
- assert !firm.account.nil?
+ assert_not_nil firm.account
account_id = firm.account.id
assert_equal [], Account.destroyed_account_ids[firm.id]
@@ -162,7 +162,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
num_accounts = Account.count
firm = ExclusivelyDependentFirm.find(9)
- assert !firm.account.nil?
+ assert_not_nil firm.account
account_id = firm.account.id
assert_equal [], Account.destroyed_account_ids[firm.id]
@@ -181,7 +181,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
firm = RestrictedFirm.new(:name => 'restrict')
firm.save!
account = firm.create_account(:credit_limit => 10)
- assert !firm.account.nil?
+ assert_not_nil firm.account
assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy }
end
@@ -246,7 +246,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
def test_dependence_with_missing_association
Account.destroy_all
firm = Firm.find(1)
- assert firm.account.nil?
+ assert_nil firm.account
firm.destroy
end
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index 1d7604f52b..34d24a2948 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -23,39 +23,39 @@ class InverseAssociationTests < ActiveRecord::TestCase
def test_should_be_able_to_ask_a_reflection_if_it_has_an_inverse
has_one_with_inverse_ref = Man.reflect_on_association(:face)
- assert has_one_with_inverse_ref.respond_to?(:has_inverse?)
+ assert_respond_to has_one_with_inverse_ref, :has_inverse?
assert has_one_with_inverse_ref.has_inverse?
has_many_with_inverse_ref = Man.reflect_on_association(:interests)
- assert has_many_with_inverse_ref.respond_to?(:has_inverse?)
+ assert_respond_to has_many_with_inverse_ref, :has_inverse?
assert has_many_with_inverse_ref.has_inverse?
belongs_to_with_inverse_ref = Face.reflect_on_association(:man)
- assert belongs_to_with_inverse_ref.respond_to?(:has_inverse?)
+ assert_respond_to belongs_to_with_inverse_ref, :has_inverse?
assert belongs_to_with_inverse_ref.has_inverse?
has_one_without_inverse_ref = Club.reflect_on_association(:sponsor)
- assert has_one_without_inverse_ref.respond_to?(:has_inverse?)
+ assert_respond_to has_one_without_inverse_ref, :has_inverse?
assert !has_one_without_inverse_ref.has_inverse?
has_many_without_inverse_ref = Club.reflect_on_association(:memberships)
- assert has_many_without_inverse_ref.respond_to?(:has_inverse?)
+ assert_respond_to has_many_without_inverse_ref, :has_inverse?
assert !has_many_without_inverse_ref.has_inverse?
belongs_to_without_inverse_ref = Sponsor.reflect_on_association(:sponsor_club)
- assert belongs_to_without_inverse_ref.respond_to?(:has_inverse?)
+ assert_respond_to belongs_to_without_inverse_ref, :has_inverse?
assert !belongs_to_without_inverse_ref.has_inverse?
end
def test_should_be_able_to_ask_a_reflection_what_it_is_the_inverse_of
has_one_ref = Man.reflect_on_association(:face)
- assert has_one_ref.respond_to?(:inverse_of)
+ assert_respond_to has_one_ref, :inverse_of
has_many_ref = Man.reflect_on_association(:interests)
- assert has_many_ref.respond_to?(:inverse_of)
+ assert_respond_to has_many_ref, :inverse_of
belongs_to_ref = Face.reflect_on_association(:man)
- assert belongs_to_ref.respond_to?(:inverse_of)
+ assert_respond_to belongs_to_ref, :inverse_of
end
def test_inverse_of_method_should_supply_the_actual_reflection_instance_it_is_the_inverse_of
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index dca72be4fd..447fe4d275 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -280,12 +280,12 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
def test_has_many_find_conditions
assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
- assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
+ assert_nil authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
end
def test_has_many_class_methods_called_by_method_missing
assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
- assert_equal nil, authors(:david).categories.find_by_name('Technology')
+ assert_nil authors(:david).categories.find_by_name('Technology')
end
def test_has_many_array_methods_called_by_method_missing
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 055590da0a..d59fa0a632 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -310,7 +310,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
end
assert !@target.instance_method_already_implemented?(:title)
topic = @target.new
- assert_equal nil, topic.title
+ assert_nil topic.title
Object.send(:undef_method, :title) # remove test method from object
end
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index 5cc5dff633..063f0f0fb2 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -1236,11 +1236,11 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas
end
test "should generate validation methods for has_many associations" do
- assert @pirate.respond_to?(:validate_associated_records_for_birds)
+ assert_respond_to @pirate, :validate_associated_records_for_birds
end
test "should generate validation methods for has_one associations with :validate => true" do
- assert @pirate.respond_to?(:validate_associated_records_for_ship)
+ assert_respond_to @pirate, :validate_associated_records_for_ship
end
test "should not generate validation methods for has_one associations without :validate => true" do
@@ -1248,7 +1248,7 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas
end
test "should generate validation methods for belongs_to associations with :validate => true" do
- assert @pirate.respond_to?(:validate_associated_records_for_parrot)
+ assert_respond_to @pirate, :validate_associated_records_for_parrot
end
test "should not generate validation methods for belongs_to associations without :validate => true" do
@@ -1256,7 +1256,7 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas
end
test "should generate validation methods for HABTM associations with :validate => true" do
- assert @pirate.respond_to?(:validate_associated_records_for_parrots)
+ assert_respond_to @pirate, :validate_associated_records_for_parrots
end
test "should not generate validation methods for HABTM associations without :validate => true" do
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index b7ae619787..0c7723c0e6 100755
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -111,14 +111,14 @@ class BasicsTest < ActiveRecord::TestCase
def test_respond_to?
topic = Topic.find(1)
- assert topic.respond_to?("title")
- assert topic.respond_to?("title?")
- assert topic.respond_to?("title=")
- assert topic.respond_to?(:title)
- assert topic.respond_to?(:title?)
- assert topic.respond_to?(:title=)
- assert topic.respond_to?("author_name")
- assert topic.respond_to?("attribute_names")
+ assert_respond_to topic, "title"
+ assert_respond_to topic, "title?"
+ assert_respond_to topic, "title="
+ assert_respond_to topic, :title
+ assert_respond_to topic, :title?
+ assert_respond_to topic, :title=
+ assert_respond_to topic, "author_name"
+ assert_respond_to topic, "attribute_names"
assert !topic.respond_to?("nothingness")
assert !topic.respond_to?(:nothingness)
end
@@ -1038,9 +1038,9 @@ class BasicsTest < ActiveRecord::TestCase
def test_mass_assignment_protection_against_class_attribute_writers
[:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names,
:default_timezone, :schema_format, :lock_optimistically, :record_timestamps].each do |method|
- assert Task.respond_to?(method)
- assert Task.respond_to?("#{method}=")
- assert Task.new.respond_to?(method)
+ assert_respond_to Task, method
+ assert_respond_to Task, "#{method}="
+ assert_respond_to Task.new, method
assert !Task.new.respond_to?("#{method}=")
end
end
@@ -1369,37 +1369,37 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_new_record_returns_boolean
- assert_equal Topic.new.new_record?, true
- assert_equal Topic.find(1).new_record?, false
+ assert_equal true, Topic.new.new_record?
+ assert_equal false, Topic.find(1).new_record?
end
def test_destroyed_returns_boolean
developer = Developer.first
- assert_equal developer.destroyed?, false
+ assert_equal false, developer.destroyed?
developer.destroy
- assert_equal developer.destroyed?, true
+ assert_equal true, developer.destroyed?
developer = Developer.last
- assert_equal developer.destroyed?, false
+ assert_equal false, developer.destroyed?
developer.delete
- assert_equal developer.destroyed?, true
+ assert_equal true, developer.destroyed?
end
def test_persisted_returns_boolean
developer = Developer.new(:name => "Jose")
- assert_equal developer.persisted?, false
+ assert_equal false, developer.persisted?
developer.save!
- assert_equal developer.persisted?, true
+ assert_equal true, developer.persisted?
developer = Developer.first
- assert_equal developer.persisted?, true
+ assert_equal true, developer.persisted?
developer.destroy
- assert_equal developer.persisted?, false
+ assert_equal false, developer.persisted?
developer = Developer.last
- assert_equal developer.persisted?, true
+ assert_equal true, developer.persisted?
developer.delete
- assert_equal developer.persisted?, false
+ assert_equal false, developer.persisted?
end
def test_clone
@@ -1427,7 +1427,7 @@ class BasicsTest < ActiveRecord::TestCase
# test if saved clone object differs from original
cloned_topic.save
assert !cloned_topic.new_record?
- assert cloned_topic.id != topic.id
+ assert_not_equal cloned_topic.id, topic.id
end
def test_clone_with_aggregate_of_same_name_as_attribute
@@ -1447,7 +1447,7 @@ class BasicsTest < ActiveRecord::TestCase
assert clone.save
assert !clone.new_record?
- assert clone.id != dev.id
+ assert_not_equal clone.id, dev.id
end
def test_clone_preserves_subtype
@@ -1456,6 +1456,56 @@ class BasicsTest < ActiveRecord::TestCase
assert_kind_of Client, clone
end
+ def test_clone_of_new_object_with_defaults
+ developer = Developer.new
+ assert !developer.name_changed?
+ assert !developer.salary_changed?
+
+ cloned_developer = developer.clone
+ assert !cloned_developer.name_changed?
+ assert !cloned_developer.salary_changed?
+ end
+
+ def test_clone_of_new_object_marks_attributes_as_dirty
+ developer = Developer.new :name => 'Bjorn', :salary => 100000
+ assert developer.name_changed?
+ assert developer.salary_changed?
+
+ cloned_developer = developer.clone
+ assert cloned_developer.name_changed?
+ assert cloned_developer.salary_changed?
+ end
+
+ def test_clone_of_new_object_marks_as_dirty_only_changed_attributes
+ developer = Developer.new :name => 'Bjorn'
+ assert developer.name_changed? # obviously
+ assert !developer.salary_changed? # attribute has non-nil default value, so treated as not changed
+
+ cloned_developer = developer.clone
+ assert cloned_developer.name_changed?
+ assert !cloned_developer.salary_changed? # ... and cloned instance should behave same
+ end
+
+ def test_clone_of_saved_object_marks_attributes_as_dirty
+ developer = Developer.create! :name => 'Bjorn', :salary => 100000
+ assert !developer.name_changed?
+ assert !developer.salary_changed?
+
+ cloned_developer = developer.clone
+ assert cloned_developer.name_changed? # both attributes differ from defaults
+ assert cloned_developer.salary_changed?
+ end
+
+ def test_clone_of_saved_object_marks_as_dirty_only_changed_attributes
+ developer = Developer.create! :name => 'Bjorn'
+ assert !developer.name_changed? # both attributes of saved object should be threated as not changed
+ assert !developer.salary_changed?
+
+ cloned_developer = developer.clone
+ assert cloned_developer.name_changed? # ... but on cloned object should be
+ assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be threated as not changed on cloned instance
+ end
+
def test_bignum
company = Company.find(1)
company.rating = 2147483647
diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb
index 8b6c019d50..b5767344cd 100644
--- a/activerecord/test/cases/column_definition_test.rb
+++ b/activerecord/test/cases/column_definition_test.rb
@@ -71,17 +71,17 @@ class ColumnDefinitionTest < ActiveRecord::TestCase
if current_adapter?(:PostgreSQLAdapter)
def test_bigint_column_should_map_to_integer
bigint_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('number', nil, "bigint")
- assert_equal bigint_column.type, :integer
+ assert_equal :integer, bigint_column.type
end
def test_smallint_column_should_map_to_integer
smallint_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('number', nil, "smallint")
- assert_equal smallint_column.type, :integer
+ assert_equal :integer, smallint_column.type
end
def test_uuid_column_should_map_to_string
uuid_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('unique_id', nil, "uuid")
- assert_equal uuid_column.type, :string
+ assert_equal :string, uuid_column.type
end
end
end
diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb
index bba216ae19..39aafa1ec7 100644
--- a/activerecord/test/cases/defaults_test.rb
+++ b/activerecord/test/cases/defaults_test.rb
@@ -67,8 +67,8 @@ if current_adapter?(:MysqlAdapter)
assert_equal '', klass.columns_hash['non_null_blob'].default
assert_equal '', klass.columns_hash['non_null_text'].default
- assert_equal nil, klass.columns_hash['null_blob'].default
- assert_equal nil, klass.columns_hash['null_text'].default
+ assert_nil klass.columns_hash['null_blob'].default
+ assert_nil klass.columns_hash['null_text'].default
assert_nothing_raised do
instance = klass.create!
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index 3ea2948f62..75f7453aa9 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -103,7 +103,7 @@ class DirtyTest < ActiveRecord::TestCase
assert pirate.created_on_changed?
# kind_of does not work because
# ActiveSupport::TimeWithZone.name == 'Time'
- assert_equal Time, pirate.created_on_was.class
+ assert_instance_of Time, pirate.created_on_was
assert_equal old_created_on, pirate.created_on_was
end
end
@@ -132,7 +132,7 @@ class DirtyTest < ActiveRecord::TestCase
assert pirate.created_on_changed?
# kind_of does not work because
# ActiveSupport::TimeWithZone.name == 'Time'
- assert_equal Time, pirate.created_on_was.class
+ assert_instance_of Time, pirate.created_on_was
assert_equal old_created_on, pirate.created_on_was
end
diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb
index 4e6fecf11a..235805a67c 100644
--- a/activerecord/test/cases/finder_respond_to_test.rb
+++ b/activerecord/test/cases/finder_respond_to_test.rb
@@ -7,53 +7,53 @@ class FinderRespondToTest < ActiveRecord::TestCase
def test_should_preserve_normal_respond_to_behaviour_and_respond_to_newly_added_method
class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) { }
- assert Topic.respond_to?(:method_added_for_finder_respond_to_test)
+ assert_respond_to Topic, :method_added_for_finder_respond_to_test
ensure
class << Topic; self; end.send(:remove_method, :method_added_for_finder_respond_to_test)
end
def test_should_preserve_normal_respond_to_behaviour_and_respond_to_standard_object_method
- assert Topic.respond_to?(:to_s)
+ assert_respond_to Topic, :to_s
end
def test_should_respond_to_find_by_one_attribute_before_caching
ensure_topic_method_is_not_cached(:find_by_title)
- assert Topic.respond_to?(:find_by_title)
+ assert_respond_to Topic, :find_by_title
end
def test_should_respond_to_find_all_by_one_attribute
ensure_topic_method_is_not_cached(:find_all_by_title)
- assert Topic.respond_to?(:find_all_by_title)
+ assert_respond_to Topic, :find_all_by_title
end
def test_should_respond_to_find_all_by_two_attributes
ensure_topic_method_is_not_cached(:find_all_by_title_and_author_name)
- assert Topic.respond_to?(:find_all_by_title_and_author_name)
+ assert_respond_to Topic, :find_all_by_title_and_author_name
end
def test_should_respond_to_find_by_two_attributes
ensure_topic_method_is_not_cached(:find_by_title_and_author_name)
- assert Topic.respond_to?(:find_by_title_and_author_name)
+ assert_respond_to Topic, :find_by_title_and_author_name
end
def test_should_respond_to_find_or_initialize_from_one_attribute
ensure_topic_method_is_not_cached(:find_or_initialize_by_title)
- assert Topic.respond_to?(:find_or_initialize_by_title)
+ assert_respond_to Topic, :find_or_initialize_by_title
end
def test_should_respond_to_find_or_initialize_from_two_attributes
ensure_topic_method_is_not_cached(:find_or_initialize_by_title_and_author_name)
- assert Topic.respond_to?(:find_or_initialize_by_title_and_author_name)
+ assert_respond_to Topic, :find_or_initialize_by_title_and_author_name
end
def test_should_respond_to_find_or_create_from_one_attribute
ensure_topic_method_is_not_cached(:find_or_create_by_title)
- assert Topic.respond_to?(:find_or_create_by_title)
+ assert_respond_to Topic, :find_or_create_by_title
end
def test_should_respond_to_find_or_create_from_two_attributes
ensure_topic_method_is_not_cached(:find_or_create_by_title_and_author_name)
- assert Topic.respond_to?(:find_or_create_by_title_and_author_name)
+ assert_respond_to Topic, :find_or_create_by_title_and_author_name
end
def test_should_not_respond_to_find_by_one_missing_attribute
@@ -73,4 +73,4 @@ class FinderRespondToTest < ActiveRecord::TestCase
class << Topic; self; end.send(:remove_method, method_id) if Topic.public_methods.any? { |m| m.to_s == method_id.to_s }
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index c73ad50a71..860d330a7f 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -255,7 +255,7 @@ class FinderTest < ActiveRecord::TestCase
assert !topic.attribute_present?("title")
#assert !topic.respond_to?("title")
assert topic.attribute_present?("author_name")
- assert topic.respond_to?("author_name")
+ assert_respond_to topic, "author_name"
end
def test_find_on_blank_conditions
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index 0672fb938b..c1c8f01e46 100644
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -72,10 +72,10 @@ class InheritanceTest < ActiveRecord::TestCase
end
def test_inheritance_find
- assert Company.find(1).kind_of?(Firm), "37signals should be a firm"
- assert Firm.find(1).kind_of?(Firm), "37signals should be a firm"
- assert Company.find(2).kind_of?(Client), "Summit should be a client"
- assert Client.find(2).kind_of?(Client), "Summit should be a client"
+ assert_kind_of Firm, Company.find(1), "37signals should be a firm"
+ assert_kind_of Firm, Firm.find(1), "37signals should be a firm"
+ assert_kind_of Client, Company.find(2), "Summit should be a client"
+ assert_kind_of Client, Client.find(2), "Summit should be a client"
end
def test_alt_inheritance_find
@@ -86,8 +86,8 @@ class InheritanceTest < ActiveRecord::TestCase
def test_inheritance_find_all
companies = Company.find(:all, :order => 'id')
- assert companies[0].kind_of?(Firm), "37signals should be a firm"
- assert companies[1].kind_of?(Client), "Summit should be a client"
+ assert_kind_of Firm, companies[0], "37signals should be a firm"
+ assert_kind_of Client, companies[1], "Summit should be a client"
end
def test_alt_inheritance_find_all
@@ -102,7 +102,7 @@ class InheritanceTest < ActiveRecord::TestCase
firm.save
next_angle = Company.find(firm.id)
- assert next_angle.kind_of?(Firm), "Next Angle should be a firm"
+ assert_kind_of Firm, next_angle, "Next Angle should be a firm"
end
def test_alt_inheritance_save
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index 3a6354ec6d..e93f22bede 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -587,18 +587,6 @@ class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase
end
end
-class ClearDefaultScopeTest < ActiveRecord::TestCase
- fixtures :developers
-
- def test_should_clear_default_scope
- klass = Class.new(DeveloperCalledDavid)
- klass.__send__ :clear_default_scope
- expected = Developer.all.collect { |dev| dev.name }
- actual = klass.all.collect { |dev| dev.name }
- assert_equal expected, actual
- end
-end
-
class DefaultScopingTest < ActiveRecord::TestCase
fixtures :developers, :posts
@@ -634,7 +622,7 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal ['salary DESC'], klass.scoped.order_values
# Parent should still have the original scope
- assert_equal nil, DeveloperOrderedBySalary.scoped.limit_value
+ assert_nil DeveloperOrderedBySalary.scoped.limit_value
assert_equal ['salary DESC'], DeveloperOrderedBySalary.scoped.order_values
end
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 768a44f6df..b5fa258f7b 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -119,6 +119,40 @@ if ActiveRecord::Base.connection.supports_migrations?
end
end
+ def test_add_index_length_limit
+ good_index_name = 'x' * Person.connection.index_name_length
+ too_long_index_name = good_index_name + 'x'
+ assert_nothing_raised { Person.connection.add_index("people", "first_name", :name => too_long_index_name) }
+ assert !Person.connection.index_exists?("people", too_long_index_name, false)
+ assert_nothing_raised { Person.connection.add_index("people", "first_name", :name => good_index_name) }
+ assert Person.connection.index_exists?("people", good_index_name, false)
+ end
+
+ def test_remove_nonexistent_index
+ # we do this by name, so OpenBase is a wash as noted above
+ unless current_adapter?(:OpenBaseAdapter)
+ assert_nothing_raised { Person.connection.remove_index("people", "no_such_index") }
+ end
+ end
+
+ def test_rename_index
+ unless current_adapter?(:OpenBaseAdapter)
+ # keep the names short to make Oracle and similar behave
+ Person.connection.add_index('people', [:first_name], :name => 'old_idx')
+ assert_nothing_raised { Person.connection.rename_index('people', 'old_idx', 'new_idx') }
+ # if the adapter doesn't support the indexes call, pick defaults that let the test pass
+ assert !Person.connection.index_exists?('people', 'old_idx', false)
+ assert Person.connection.index_exists?('people', 'new_idx', true)
+ end
+ end
+
+ def test_double_add_index
+ unless current_adapter?(:OpenBaseAdapter)
+ Person.connection.add_index('people', [:first_name], :name => 'some_idx')
+ assert_nothing_raised { Person.connection.add_index('people', [:first_name], :name => 'some_idx') }
+ end
+ end
+
def testing_table_with_only_foo_attribute
Person.connection.create_table :testings, :id => false do |t|
t.column :foo, :string
@@ -491,7 +525,7 @@ if ActiveRecord::Base.connection.supports_migrations?
end
end
- assert_equal TrueClass, bob.male?.class
+ assert_instance_of TrueClass, bob.male?
assert_kind_of BigDecimal, bob.wealth
end
@@ -860,18 +894,6 @@ if ActiveRecord::Base.connection.supports_migrations?
assert_equal "Tester", Person.new.first_name
end
- unless current_adapter?(:PostgreSQLAdapter)
- def test_change_column_type_default_should_change
- old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
- assert !old_columns.find { |c| c.name == 'data' }
-
- assert_nothing_raised do
- Person.connection.add_column "people", "data", :string, :default => ''
- Person.connection.change_column "people", "data", :binary
- end
- end
- end
-
def test_change_column_quotes_column_names
Person.connection.create_table :testings do |t|
t.column :select, :string
diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb
index c924c3dfad..4b635792c7 100644
--- a/activerecord/test/cases/modules_test.rb
+++ b/activerecord/test/cases/modules_test.rb
@@ -35,7 +35,7 @@ class ModulesTest < ActiveRecord::TestCase
def test_module_spanning_has_and_belongs_to_many_associations
project = MyApplication::Business::Project.find(:first)
project.developers << MyApplication::Business::Developer.create("name" => "John")
- assert "John", project.developers.last.name
+ assert_equal "John", project.developers.last.name
end
def test_associations_spanning_cross_modules
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index fadd62b5a1..57b66fb312 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -1,6 +1,7 @@
require "cases/helper"
require "models/pirate"
require "models/ship"
+require "models/ship_part"
require "models/bird"
require "models/parrot"
require "models/treasure"
@@ -732,3 +733,82 @@ class TestNestedAttributesWithNonStandardPrimaryKeys < ActiveRecord::TestCase
assert_equal ['Foo', 'Bar'], @owner.pets.map(&:name)
end
end
+
+class TestHasOneAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ def setup
+ @pirate = Pirate.create!(:catchphrase => "My baby takes tha mornin' train!")
+ @ship = @pirate.create_ship(:name => "The good ship Dollypop")
+ @part = @ship.parts.create!(:name => "Mast")
+ @trinket = @part.trinkets.create!(:name => "Necklace")
+ end
+
+ test "when great-grandchild changed in memory, saving parent should save great-grandchild" do
+ @trinket.name = "changed"
+ @pirate.save
+ assert_equal "changed", @trinket.reload.name
+ end
+
+ test "when great-grandchild changed via attributes, saving parent should save great-grandchild" do
+ @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]}}
+ @pirate.save
+ assert_equal "changed", @trinket.reload.name
+ end
+
+ test "when great-grandchild marked_for_destruction via attributes, saving parent should destroy great-grandchild" do
+ @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]}}
+ assert_difference('@part.trinkets.count', -1) { @pirate.save }
+ end
+
+ test "when great-grandchild added via attributes, saving parent should create great-grandchild" do
+ @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]}}
+ assert_difference('@part.trinkets.count', 1) { @pirate.save }
+ end
+
+ test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do
+ @trinket.name = "changed"
+ Ship.create!(:pirate => @pirate, :name => "The Black Rock")
+ ShipPart.create!(:ship => @ship, :name => "Stern")
+ assert_no_queries { @pirate.valid? }
+ end
+end
+
+class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ def setup
+ @ship = Ship.create!(:name => "The good ship Dollypop")
+ @part = @ship.parts.create!(:name => "Mast")
+ @trinket = @part.trinkets.create!(:name => "Necklace")
+ end
+
+ test "when grandchild changed in memory, saving parent should save grandchild" do
+ @trinket.name = "changed"
+ @ship.save
+ assert_equal "changed", @trinket.reload.name
+ end
+
+ test "when grandchild changed via attributes, saving parent should save grandchild" do
+ @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]}
+ @ship.save
+ assert_equal "changed", @trinket.reload.name
+ end
+
+ test "when grandchild marked_for_destruction via attributes, saving parent should destroy grandchild" do
+ @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]}
+ assert_difference('@part.trinkets.count', -1) { @ship.save }
+ end
+
+ test "when grandchild added via attributes, saving parent should create grandchild" do
+ @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]}
+ assert_difference('@part.trinkets.count', 1) { @ship.save }
+ end
+
+ test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do
+ @trinket.name = "changed"
+ Ship.create!(:name => "The Black Rock")
+ ShipPart.create!(:ship => @ship, :name => "Stern")
+ assert_no_queries { @ship.valid? }
+ end
+end
diff --git a/activerecord/test/cases/pk_test.rb b/activerecord/test/cases/pk_test.rb
index 33ad5992de..73f4b3848c 100644
--- a/activerecord/test/cases/pk_test.rb
+++ b/activerecord/test/cases/pk_test.rb
@@ -18,7 +18,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase
def test_to_key_with_customized_primary_key
keyboard = Keyboard.new
- assert keyboard.to_key.nil?
+ assert_nil keyboard.to_key
keyboard.save
assert_equal keyboard.to_key, [keyboard.id]
end
@@ -37,7 +37,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase
topic = Topic.new
topic.title = "New Topic"
- assert_equal(nil, topic.id)
+ assert_nil topic.id
assert_nothing_raised { topic.save! }
id = topic.id
diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb
index 94d6663778..e61960059e 100644
--- a/activerecord/test/cases/pooled_connections_test.rb
+++ b/activerecord/test/cases/pooled_connections_test.rb
@@ -34,8 +34,8 @@ class PooledConnectionsTest < ActiveRecord::TestCase
if RUBY_VERSION < '1.9'
def test_pooled_connection_checkout
checkout_connections
- assert_equal @connections.length, 2
- assert_equal @timed_out, 2
+ assert_equal 2, @connections.length
+ assert_equal 2, @timed_out
end
end
@@ -137,4 +137,4 @@ class PooledConnectionsTest < ActiveRecord::TestCase
def add_record(name)
ActiveRecord::Base.connection_pool.with_connection { Project.create! :name => name }
end
-end unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name \ No newline at end of file
+end unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 91349689bc..68abca70b3 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -58,7 +58,7 @@ class QueryCacheTest < ActiveRecord::TestCase
Task.cache do
# Oracle adapter returns count() as Fixnum or Float
if current_adapter?(:OracleAdapter)
- assert Task.connection.select_value("SELECT count(*) AS count_all FROM tasks").is_a?(Numeric)
+ assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
elsif current_adapter?(:SQLite3Adapter) && SQLite3::Version::VERSION > '1.2.5'
# Future versions of the sqlite3 adapter will return numeric
assert_instance_of Fixnum,
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 7b9e680c02..b6815af67e 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -145,7 +145,7 @@ class RelationTest < ActiveRecord::TestCase
relation = Topic.scoped
["map", "uniq", "sort", "insert", "delete", "update"].each do |method|
- assert relation.respond_to?(method), "Topic.scoped should respond to #{method.inspect}"
+ assert_respond_to relation, method, "Topic.scoped should respond to #{method.inspect}"
end
end
@@ -160,7 +160,7 @@ class RelationTest < ActiveRecord::TestCase
relation = Topic.scoped
["find_by_title", "find_by_title_and_author_name", "find_or_create_by_title", "find_or_initialize_by_title_and_author_name"].each do |method|
- assert relation.respond_to?(method), "Topic.scoped should respond to #{method.inspect}"
+ assert_respond_to relation, method, "Topic.scoped should respond to #{method.inspect}"
end
end
@@ -238,7 +238,7 @@ class RelationTest < ActiveRecord::TestCase
def test_default_scope_with_conditions_string
assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.scoped.map(&:id).sort
- assert_equal nil, DeveloperCalledDavid.create!.name
+ assert_nil DeveloperCalledDavid.create!.name
end
def test_default_scope_with_conditions_hash
diff --git a/activerecord/test/cases/reserved_word_test_mysql.rb b/activerecord/test/cases/reserved_word_test_mysql.rb
index ce1622bb20..90d8b0d923 100644
--- a/activerecord/test/cases/reserved_word_test_mysql.rb
+++ b/activerecord/test/cases/reserved_word_test_mysql.rb
@@ -115,7 +115,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
create_test_fixtures :select, :distinct, :group, :values, :distincts_selects
v = nil
assert_nothing_raised { v = Group.find(1).values }
- assert_equal v.id, 2
+ assert_equal 2, v.id
end
# belongs_to association with reserved-word table name
diff --git a/activerecord/test/cases/schema_test_postgresql.rb b/activerecord/test/cases/schema_test_postgresql.rb
index 3ed73786a7..3ed9b1974d 100644
--- a/activerecord/test/cases/schema_test_postgresql.rb
+++ b/activerecord/test/cases/schema_test_postgresql.rb
@@ -152,11 +152,11 @@ class SchemaTest < ActiveRecord::TestCase
def test_with_uppercase_index_name
ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)"
- assert_nothing_raised { ActiveRecord::Base.connection.remove_index :things, :name => "#{SCHEMA_NAME}.things_Index"}
+ assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "#{SCHEMA_NAME}.things_Index"}
ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)"
ActiveRecord::Base.connection.schema_search_path = SCHEMA_NAME
- assert_nothing_raised { ActiveRecord::Base.connection.remove_index :things, :name => "things_Index"}
+ assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "things_Index"}
ActiveRecord::Base.connection.schema_search_path = "public"
end
diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb
index 24b237a72b..549c4af6b1 100644
--- a/activerecord/test/cases/timestamp_test.rb
+++ b/activerecord/test/cases/timestamp_test.rb
@@ -15,26 +15,26 @@ class TimestampTest < ActiveRecord::TestCase
@developer.name = "Jack Bauer"
@developer.save!
- assert @previously_updated_at != @developer.updated_at
+ assert_not_equal @previously_updated_at, @developer.updated_at
end
def test_saving_a_unchanged_record_doesnt_update_its_timestamp
@developer.save!
- assert @previously_updated_at == @developer.updated_at
+ assert_equal @previously_updated_at, @developer.updated_at
end
def test_touching_a_record_updates_its_timestamp
@developer.touch
- assert @previously_updated_at != @developer.updated_at
+ assert_not_equal @previously_updated_at, @developer.updated_at
end
def test_touching_a_different_attribute
previously_created_at = @developer.created_at
@developer.touch(:created_at)
- assert previously_created_at != @developer.created_at
+ assert_not_equal previously_created_at, @developer.created_at
end
def test_saving_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at
@@ -45,7 +45,7 @@ class TimestampTest < ActiveRecord::TestCase
pet.name = "Fluffy the Third"
pet.save
- assert previously_owner_updated_at != pet.owner.updated_at
+ assert_not_equal previously_owner_updated_at, pet.owner.updated_at
end
def test_destroying_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at
@@ -55,7 +55,7 @@ class TimestampTest < ActiveRecord::TestCase
pet.destroy
- assert previously_owner_updated_at != pet.owner.updated_at
+ assert_not_equal previously_owner_updated_at, pet.owner.updated_at
end
def test_saving_a_record_with_a_belongs_to_that_specifies_touching_a_specific_attribute_the_parent_should_update_that_attribute
@@ -68,8 +68,8 @@ class TimestampTest < ActiveRecord::TestCase
pet.name = "Fluffy the Third"
pet.save
- assert previously_owner_happy_at != pet.owner.happy_at
+ assert_not_equal previously_owner_happy_at, pet.owner.happy_at
ensure
Pet.belongs_to :owner, :touch => true
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index a07da093f1..ebc16653cb 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -54,33 +54,31 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
@first.after_rollback_block{|r| r.history << :after_rollback}
@first.save!
- assert @first.history, [:after_commit]
+ assert_equal [:after_commit], @first.history
end
def test_only_call_after_commit_on_update_after_transaction_commits_for_existing_record
- commit_callback = []
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
@first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
- @first.after_commit_block(:create){|r| r.history << :rollback_on_create}
- @first.after_commit_block(:update){|r| r.history << :rollback_on_update}
- @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy}
+ @first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
+ @first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
+ @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
@first.save!
- assert @first.history, [:commit_on_update]
+ assert_equal [:commit_on_update], @first.history
end
def test_only_call_after_commit_on_destroy_after_transaction_commits_for_destroyed_record
- commit_callback = []
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
@first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
- @first.after_commit_block(:create){|r| r.history << :rollback_on_create}
- @first.after_commit_block(:update){|r| r.history << :rollback_on_update}
- @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy}
+ @first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
+ @first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
+ @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
@first.destroy
- assert @first.history, [:commit_on_destroy]
+ assert_equal [:commit_on_destroy], @first.history
end
def test_only_call_after_commit_on_create_after_transaction_commits_for_new_record
@@ -88,12 +86,12 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
@new_record.after_commit_block(:create){|r| r.history << :commit_on_create}
@new_record.after_commit_block(:update){|r| r.history << :commit_on_update}
@new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
- @new_record.after_commit_block(:create){|r| r.history << :rollback_on_create}
- @new_record.after_commit_block(:update){|r| r.history << :rollback_on_update}
- @new_record.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy}
+ @new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create}
+ @new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update}
+ @new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
@new_record.save!
- assert @new_record.history, [:commit_on_create]
+ assert_equal [:commit_on_create], @new_record.history
end
def test_call_after_rollback_after_transaction_rollsback
@@ -105,41 +103,39 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
raise ActiveRecord::Rollback
end
- assert @first.history, [:after_rollback]
+ assert_equal [:after_rollback], @first.history
end
def test_only_call_after_rollback_on_update_after_transaction_rollsback_for_existing_record
- commit_callback = []
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
@first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
- @first.after_commit_block(:create){|r| r.history << :rollback_on_create}
- @first.after_commit_block(:update){|r| r.history << :rollback_on_update}
- @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy}
+ @first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
+ @first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
+ @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
Topic.transaction do
@first.save!
raise ActiveRecord::Rollback
end
- assert @first.history, [:rollback_on_update]
+ assert_equal [:rollback_on_update], @first.history
end
def test_only_call_after_rollback_on_destroy_after_transaction_rollsback_for_destroyed_record
- commit_callback = []
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
@first.after_commit_block(:destroy){|r| r.history << :commit_on_update}
- @first.after_commit_block(:create){|r| r.history << :rollback_on_create}
- @first.after_commit_block(:update){|r| r.history << :rollback_on_update}
- @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy}
+ @first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
+ @first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
+ @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
Topic.transaction do
@first.destroy
raise ActiveRecord::Rollback
end
- assert @first.history, [:rollback_on_destroy]
+ assert_equal [:rollback_on_destroy], @first.history
end
def test_only_call_after_rollback_on_create_after_transaction_rollsback_for_new_record
@@ -147,16 +143,16 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
@new_record.after_commit_block(:create){|r| r.history << :commit_on_create}
@new_record.after_commit_block(:update){|r| r.history << :commit_on_update}
@new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
- @new_record.after_commit_block(:create){|r| r.history << :rollback_on_create}
- @new_record.after_commit_block(:update){|r| r.history << :rollback_on_update}
- @new_record.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy}
+ @new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create}
+ @new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update}
+ @new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
Topic.transaction do
@new_record.save!
raise ActiveRecord::Rollback
end
- assert @new_record.history, [:rollback_on_create]
+ assert_equal [:rollback_on_create], @new_record.history
end
def test_call_after_rollback_when_commit_fails
@@ -170,7 +166,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
@first.after_rollback_block{|r| r.history << :after_rollback}
assert !@first.save rescue nil
- assert @first.history == [:after_rollback]
+ assert_equal [:after_rollback], @first.history
ensure
@first.connection.class.send(:remove_method, :commit_db_transaction)
@first.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction)
@@ -196,18 +192,18 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
end
end
- assert 1, @first.commits
- assert 0, @first.rollbacks
- assert 1, @second.commits
- assert 1, @second.rollbacks
+ assert_equal 1, @first.commits
+ assert_equal 0, @first.rollbacks
+ assert_equal 0, @second.commits
+ assert_equal 1, @second.rollbacks
end
def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint_when_release_savepoint_fails
def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
def @first.commits(i=0); @commits ||= 0; @commits += i if i; end
- @second.after_rollback_block{|r| r.rollbacks(1)}
- @second.after_commit_block{|r| r.commits(1)}
+ @first.after_rollback_block{|r| r.rollbacks(1)}
+ @first.after_commit_block{|r| r.commits(1)}
Topic.transaction do
@first.save
@@ -221,8 +217,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
end
end
- assert 1, @first.commits
- assert 2, @first.rollbacks
+ assert_equal 1, @first.commits
+ assert_equal 2, @first.rollbacks
end
def test_after_transaction_callbacks_should_not_raise_errors
@@ -232,13 +228,13 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
@first.after_rollback_block{|r| r.last_after_transaction_error = :rollback; raise "fail!";}
@first.save!
- assert_equal @first.last_after_transaction_error, :commit
+ assert_equal :commit, @first.last_after_transaction_error
Topic.transaction do
@first.save!
raise ActiveRecord::Rollback
end
- assert_equal @first.last_after_transaction_error, :rollback
+ assert_equal :rollback, @first.last_after_transaction_error
end
end
diff --git a/activerecord/test/models/ship.rb b/activerecord/test/models/ship.rb
index 75c792d176..3da031946f 100644
--- a/activerecord/test/models/ship.rb
+++ b/activerecord/test/models/ship.rb
@@ -3,8 +3,9 @@ class Ship < ActiveRecord::Base
belongs_to :pirate
belongs_to :update_only_pirate, :class_name => 'Pirate'
- has_many :parts, :class_name => 'ShipPart', :autosave => true
+ has_many :parts, :class_name => 'ShipPart'
+ accepts_nested_attributes_for :parts, :allow_destroy => true
accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
accepts_nested_attributes_for :update_only_pirate, :update_only => true
diff --git a/activerecord/test/models/ship_part.rb b/activerecord/test/models/ship_part.rb
index 0a606db239..b6a8a506b4 100644
--- a/activerecord/test/models/ship_part.rb
+++ b/activerecord/test/models/ship_part.rb
@@ -1,5 +1,7 @@
class ShipPart < ActiveRecord::Base
belongs_to :ship
+ has_many :trinkets, :class_name => "Treasure", :as => :looter
+ accepts_nested_attributes_for :trinkets, :allow_destroy => true
validates_presence_of :name
end \ No newline at end of file
diff --git a/activeresource/test/cases/base/schema_test.rb b/activeresource/test/cases/base/schema_test.rb
index d9dc679941..136c827926 100644
--- a/activeresource/test/cases/base/schema_test.rb
+++ b/activeresource/test/cases/base/schema_test.rb
@@ -185,7 +185,7 @@ class SchemaTest < ActiveModel::TestCase
####
test "should be able to use schema" do
- assert Person.respond_to?(:schema), "should at least respond to the schema method"
+ assert_respond_to Person, :schema, "should at least respond to the schema method"
assert_nothing_raised("Should allow the schema to take a block") do
Person.schema { }
@@ -199,7 +199,7 @@ class SchemaTest < ActiveModel::TestCase
s = self
attribute :foo, :string
end
- assert s.respond_to?(:attrs), "should return attributes in theory"
+ assert_respond_to s, :attrs, "should return attributes in theory"
assert_equal({'foo' => 'string' }, s.attrs, "should return attributes in practice")
end
end
@@ -308,8 +308,8 @@ class SchemaTest < ActiveModel::TestCase
Person.schema { string new_attr_name_two }
end
- assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
- assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
+ assert_respond_to Person.new, new_attr_name, "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
+ assert_respond_to Person.new, new_attr_name_two, "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
end
test "should not care about ordering of schema definitions" do
@@ -326,8 +326,8 @@ class SchemaTest < ActiveModel::TestCase
Person.schema = {new_attr_name.to_s => 'string'}
end
- assert Person.new.respond_to?(new_attr_name), "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
- assert Person.new.respond_to?(new_attr_name_two), "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
+ assert_respond_to Person.new, new_attr_name, "should respond to the attribute in a passed-in schema, but failed on: #{new_attr_name}"
+ assert_respond_to Person.new, new_attr_name_two, "should respond to the attribute from the schema, but failed on: #{new_attr_name_two}"
end
# method_missing effects
diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb
index 4e21e84596..d5ee7659af 100644
--- a/activeresource/test/cases/base_test.rb
+++ b/activeresource/test/cases/base_test.rb
@@ -671,9 +671,9 @@ class BaseTest < Test::Unit::TestCase
########################################################################
def test_respond_to
matz = Person.find(1)
- assert matz.respond_to?(:name)
- assert matz.respond_to?(:name=)
- assert matz.respond_to?(:name?)
+ assert_respond_to matz, :name
+ assert_respond_to matz, :name=
+ assert_respond_to matz, :name?
assert !matz.respond_to?(:super_scalable_stuff)
end
@@ -708,7 +708,7 @@ class BaseTest < Test::Unit::TestCase
def test_id_from_response_without_location
p = Person.new
resp = {}
- assert_equal nil, p.__send__(:id_from_response, resp)
+ assert_nil p.__send__(:id_from_response, resp)
end
def test_create_with_custom_prefix
@@ -775,7 +775,7 @@ class BaseTest < Test::Unit::TestCase
mock.post "/people.xml", {}, nil, 201
end
person = Person.create(:name => 'Rick')
- assert_equal nil, person.id
+ assert_nil person.id
end
def test_clone
@@ -1048,7 +1048,7 @@ class BaseTest < Test::Unit::TestCase
json = joe.to_json
Person.format = :xml
- assert encode, json
+ assert_equal encode, json
assert_match %r{^\{"person":\{"person":\{}, json
assert_match %r{"id":6}, json
assert_match %r{"name":"Joe"}, json
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 7afd9926b5..c617a0ec3b 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,6 +1,8 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
-* Defines prev_(month|year) in Date and Time, and deprecates last_(month|year). [fxn]
+* Renames Array#rand -> Array#random_element. [Santiago Pastorino, Rizwan Reza]
+
+* 1.9 compat: Renames last_(month|year) to prev_(month|year) in Date and Time. [fxn]
* Aliases Date#sunday to Date#end_of_week. [fxn]
diff --git a/activesupport/lib/active_support/core_ext/array/random_access.rb b/activesupport/lib/active_support/core_ext/array/random_access.rb
index 5338836b29..67c322daea 100644
--- a/activesupport/lib/active_support/core_ext/array/random_access.rb
+++ b/activesupport/lib/active_support/core_ext/array/random_access.rb
@@ -1,16 +1,6 @@
class Array
- # This method is deprecated because it masks Kernel#rand within the Array class itself,
- # which may be used by a 3rd party library extending Array in turn. See
- #
- # https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4555
- #
- def rand # :nodoc:
- ActiveSupport::Deprecation.warn "Array#rand is deprecated, use random_element instead", caller
- random_element
- end
-
# Returns a random element from the array.
def random_element
self[Kernel.rand(length)]
end
-end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 755d96ce91..579079d4f1 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -2,7 +2,6 @@ require 'date'
require 'active_support/duration'
require 'active_support/core_ext/time/zones'
require 'active_support/core_ext/object/acts_like'
-require 'active_support/deprecation'
class Date
if RUBY_VERSION < '1.9'
@@ -147,11 +146,6 @@ class Date
advance(:years => years)
end
- def last_year # :nodoc:
- ActiveSupport::Deprecation.warn("Date#last_year has been deprecated, please use Date#prev_year instead", caller)
- prev_year
- end
-
# Shorthand for years_ago(1)
def prev_year
years_ago(1)
@@ -161,11 +155,6 @@ class Date
def next_year
years_since(1)
end unless method_defined?(:next_year)
-
- def last_month # :nodoc:
- ActiveSupport::Deprecation.warn("Date#last_month has been deprecated, please use Date#prev_month instead", caller)
- prev_month
- end
# Short-hand for months_ago(1)
def prev_month
diff --git a/activesupport/lib/active_support/core_ext/string/encoding.rb b/activesupport/lib/active_support/core_ext/string/encoding.rb
new file mode 100644
index 0000000000..d4781bfe0c
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/string/encoding.rb
@@ -0,0 +1,11 @@
+class String
+ if defined?(Encoding) && "".respond_to?(:encode)
+ def encoding_aware?
+ true
+ end
+ else
+ def encoding_aware?
+ false
+ end
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index e27b08ec2e..3c218d88e5 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -2,7 +2,6 @@ require 'active_support/duration'
require 'active_support/core_ext/date/acts_like'
require 'active_support/core_ext/date/calculations'
require 'active_support/core_ext/date_time/conversions'
-require 'active_support/deprecation'
class Time
COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
@@ -133,11 +132,6 @@ class Time
advance(:years => years)
end
- def last_year # :nodoc:
- ActiveSupport::Deprecation.warn("Time#last_year has been deprecated, please use Time#prev_year instead", caller)
- prev_year
- end
-
# Short-hand for years_ago(1)
def prev_year
years_ago(1)
@@ -148,11 +142,6 @@ class Time
years_since(1)
end
- def last_month # :nodoc:
- ActiveSupport::Deprecation.warn("Time#last_month has been deprecated, please use Time#prev_month instead", caller)
- prev_month
- end
-
# Short-hand for months_ago(1)
def prev_month
months_ago(1)
diff --git a/activesupport/lib/active_support/ruby/shim.rb b/activesupport/lib/active_support/ruby/shim.rb
index 4a9ac920e8..608b3fe4b9 100644
--- a/activesupport/lib/active_support/ruby/shim.rb
+++ b/activesupport/lib/active_support/ruby/shim.rb
@@ -15,6 +15,7 @@ require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/process/daemon'
require 'active_support/core_ext/string/conversions'
require 'active_support/core_ext/string/interpolation'
+require 'active_support/core_ext/string/encoding'
require 'active_support/core_ext/rexml'
require 'active_support/core_ext/time/conversions'
require 'active_support/core_ext/file/path'
diff --git a/activesupport/test/buffered_logger_test.rb b/activesupport/test/buffered_logger_test.rb
index 5b072d4102..850febb959 100644
--- a/activesupport/test/buffered_logger_test.rb
+++ b/activesupport/test/buffered_logger_test.rb
@@ -69,11 +69,11 @@ class BufferedLoggerTest < Test::Unit::TestCase
4.times do
@logger.info 'wait for it..'
- assert @output.string.empty?, @output.string
+ assert @output.string.empty?, "@output.string should be empty but it is #{@output.string}"
end
@logger.flush
- assert !@output.string.empty?, @logger.send(:buffer).size.to_s
+ assert !@output.string.empty?, "@logger.send(:buffer).size.to_s should not be empty but it is empty"
end
define_method "test_disabling_auto_flush_with_#{disable.inspect}_should_flush_at_max_buffer_size_as_failsafe" do
@@ -82,11 +82,11 @@ class BufferedLoggerTest < Test::Unit::TestCase
(Logger::MAX_BUFFER_SIZE - 1).times do
@logger.info 'wait for it..'
- assert @output.string.empty?, @output.string
+ assert @output.string.empty?, "@output.string should be empty but is #{@output.string}"
end
@logger.info 'there it is.'
- assert !@output.string.empty?, @logger.send(:buffer).size.to_s
+ assert !@output.string.empty?, "@logger.send(:buffer).size.to_s should not be empty but it is empty"
end
end
@@ -102,11 +102,11 @@ class BufferedLoggerTest < Test::Unit::TestCase
4.times do
@logger.info 'wait for it..'
- assert @output.string.empty?, @output.string
+ assert @output.string.empty?, "@output.string should be empty but it is #{@output.string}"
end
@logger.info 'there it is.'
- assert !@output.string.empty?, @output.string
+ assert !@output.string.empty?, "@output.string should not be empty but it is empty"
end
def test_should_create_the_log_directory_if_it_doesnt_exist
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index 49d9de63b0..70a2950f9b 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -521,7 +521,7 @@ module CallbacksTest
def test_save
obj = HyphenatedCallbacks.new
obj.save
- assert_equal obj.stuff, "ACTION"
+ assert_equal "ACTION", obj.stuff
end
end
end
diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb
index ebd6806416..1f7cdb8ec1 100644
--- a/activesupport/test/core_ext/array_ext_test.rb
+++ b/activesupport/test/core_ext/array_ext_test.rb
@@ -368,10 +368,6 @@ class ArrayExtRandomTests < ActiveSupport::TestCase
Kernel.expects(:rand).with(3).returns(1)
assert_equal 2, [1, 2, 3].random_element
end
-
- def test_deprecated_rand_on_array
- assert_deprecated { [].rand }
- end
end
class ArrayWrapperTests < Test::Unit::TestCase
diff --git a/activesupport/test/core_ext/class/attribute_accessor_test.rb b/activesupport/test/core_ext/class/attribute_accessor_test.rb
index 0f579d12e5..2c896d0cdb 100644
--- a/activesupport/test/core_ext/class/attribute_accessor_test.rb
+++ b/activesupport/test/core_ext/class/attribute_accessor_test.rb
@@ -25,14 +25,14 @@ class ClassAttributeAccessorTest < Test::Unit::TestCase
end
def test_should_not_create_instance_writer
- assert @class.respond_to?(:foo)
- assert @class.respond_to?(:foo=)
- assert @object.respond_to?(:bar)
+ assert_respond_to @class, :foo
+ assert_respond_to @class, :foo=
+ assert_respond_to @object, :bar
assert !@object.respond_to?(:bar=)
end
def test_should_not_create_instance_reader
- assert @class.respond_to?(:shaq)
+ assert_respond_to @class, :shaq
assert !@object.respond_to?(:shaq)
end
end
diff --git a/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb b/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb
index eeda468d9c..63ea46b564 100644
--- a/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb
+++ b/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb
@@ -219,7 +219,7 @@ class ClassInheritableAttributesTest < Test::Unit::TestCase
@klass.reset_inheritable_attributes
@sub = eval("class NotInheriting < @klass; end; NotInheriting")
- assert_equal nil, @klass.a
- assert_equal nil, @sub.a
+ assert_nil @klass.a
+ assert_nil @sub.a
end
end
diff --git a/activesupport/test/core_ext/class/delegating_attributes_test.rb b/activesupport/test/core_ext/class/delegating_attributes_test.rb
index 6d6cb61571..cbfb290c48 100644
--- a/activesupport/test/core_ext/class/delegating_attributes_test.rb
+++ b/activesupport/test/core_ext/class/delegating_attributes_test.rb
@@ -32,16 +32,16 @@ class DelegatingAttributesTest < Test::Unit::TestCase
single_class.superclass_delegating_accessor :both
# Class should have accessor and mutator
# the instance should have an accessor only
- assert single_class.respond_to?(:both)
- assert single_class.respond_to?(:both=)
+ assert_respond_to single_class, :both
+ assert_respond_to single_class, :both=
assert single_class.public_instance_methods.map(&:to_s).include?("both")
assert !single_class.public_instance_methods.map(&:to_s).include?("both=")
end
def test_simple_accessor_declaration_with_instance_reader_false
single_class.superclass_delegating_accessor :no_instance_reader, :instance_reader => false
- assert single_class.respond_to?(:no_instance_reader)
- assert single_class.respond_to?(:no_instance_reader=)
+ assert_respond_to single_class, :no_instance_reader
+ assert_respond_to single_class, :no_instance_reader=
assert !single_class.public_instance_methods.map(&:to_s).include?("no_instance_reader")
end
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index 1bf118e3b7..a3a2f13436 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -145,10 +145,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal Date.new(2005,2,28), Date.new(2004,2,29).years_since(1) # 1 year since leap day
end
- def test_last_year_is_deprecated
- assert_deprecated { Date.today.last_year }
- end
-
def test_prev_year
assert_equal Date.new(2004,6,5), Date.new(2005,6,5).prev_year
end
@@ -229,10 +225,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal Date.new(2005, 9, 30), Date.new(2005, 8, 31).next_month
end
- def test_last_month_is_deprecated
- assert_deprecated { Date.today.last_month }
- end
-
def test_prev_month_on_31st
assert_equal Date.new(2004, 2, 29), Date.new(2004, 3, 31).prev_month
end
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index 4780760a19..eba8170cda 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -275,12 +275,12 @@ class DateTimeExtCalculationsTest < Test::Unit::TestCase
end
def test_current_without_time_zone
- assert DateTime.current.is_a?(DateTime)
+ assert_kind_of DateTime, DateTime.current
end
def test_current_with_time_zone
with_env_tz 'US/Eastern' do
- assert DateTime.current.is_a?(DateTime)
+ assert_kind_of DateTime, DateTime.current
end
end
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 6530de1ef4..05f529dc7d 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -5,8 +5,8 @@ class DurationTest < ActiveSupport::TestCase
def test_is_a
d = 1.day
assert d.is_a?(ActiveSupport::Duration)
- assert d.is_a?(Numeric)
- assert d.is_a?(Fixnum)
+ assert_kind_of Numeric, d
+ assert_kind_of Fixnum, d
assert !d.is_a?(Hash)
k = Class.new
diff --git a/activesupport/test/core_ext/module/attribute_accessor_test.rb b/activesupport/test/core_ext/module/attribute_accessor_test.rb
index 263e78feaa..67fcd437d0 100644
--- a/activesupport/test/core_ext/module/attribute_accessor_test.rb
+++ b/activesupport/test/core_ext/module/attribute_accessor_test.rb
@@ -27,14 +27,14 @@ class ModuleAttributeAccessorTest < Test::Unit::TestCase
end
def test_should_not_create_instance_writer
- assert @module.respond_to?(:foo)
- assert @module.respond_to?(:foo=)
- assert @object.respond_to?(:bar)
+ assert_respond_to @module, :foo
+ assert_respond_to @module, :foo=
+ assert_respond_to @object, :bar
assert !@object.respond_to?(:bar=)
end
def test_should_not_create_instance_reader
- assert @module.respond_to?(:shaq)
+ assert_respond_to @module, :shaq
assert !@object.respond_to?(:shaq)
end
end
diff --git a/activesupport/test/core_ext/module/synchronization_test.rb b/activesupport/test/core_ext/module/synchronization_test.rb
index 43d65ab249..eb850893f0 100644
--- a/activesupport/test/core_ext/module/synchronization_test.rb
+++ b/activesupport/test/core_ext/module/synchronization_test.rb
@@ -16,8 +16,8 @@ class SynchronizationTest < Test::Unit::TestCase
attr_accessor :value
synchronize :value, :with => :mutex
end
- assert @instance.respond_to?(:value_with_synchronization)
- assert @instance.respond_to?(:value_without_synchronization)
+ assert_respond_to @instance, :value_with_synchronization
+ assert_respond_to @instance, :value_without_synchronization
end
def test_synchronize_does_not_change_behavior
@@ -81,7 +81,7 @@ class SynchronizationTest < Test::Unit::TestCase
class << @target
synchronize :to_s, :with => :mutex
end
- assert @target.respond_to?(:to_s_without_synchronization)
+ assert_respond_to @target, :to_s_without_synchronization
assert_nothing_raised { @target.to_s; @target.to_s }
assert_equal 2, @target.mutex.sync_count
end
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index 1712b0649b..39ee0ac748 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -225,7 +225,7 @@ class MethodAliasingTest < Test::Unit::TestCase
FooClassWithBarMethod.class_eval { include BarMethodAliaser }
feature_aliases.each do |method|
- assert @instance.respond_to?(method)
+ assert_respond_to @instance, method
end
assert_equal 'bar_with_baz', @instance.bar
@@ -242,7 +242,7 @@ class MethodAliasingTest < Test::Unit::TestCase
include BarMethodAliaser
alias_method_chain :quux!, :baz
end
- assert @instance.respond_to?(:quux_with_baz!)
+ assert_respond_to @instance, :quux_with_baz!
assert_equal 'quux_with_baz', @instance.quux!
assert_equal 'quux', @instance.quux_without_baz!
@@ -260,9 +260,9 @@ class MethodAliasingTest < Test::Unit::TestCase
assert !@instance.respond_to?(:quux_with_baz=)
FooClassWithBarMethod.class_eval { include BarMethodAliaser }
- assert @instance.respond_to?(:quux_with_baz!)
- assert @instance.respond_to?(:quux_with_baz?)
- assert @instance.respond_to?(:quux_with_baz=)
+ assert_respond_to @instance, :quux_with_baz!
+ assert_respond_to @instance, :quux_with_baz?
+ assert_respond_to @instance, :quux_with_baz=
FooClassWithBarMethod.alias_method_chain :quux!, :baz
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 97b08da0e4..ea21e445e2 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -117,7 +117,7 @@ class StringInflectionsTest < Test::Unit::TestCase
assert_equal Time.local(2005, 2, 27, 23, 50, 19, 275038), "2005-02-27T23:50:19.275038".to_time(:local)
assert_equal DateTime.civil(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time
assert_equal Time.local_time(2039, 2, 27, 23, 50), "2039-02-27 23:50".to_time(:local)
- assert_equal nil, "".to_time
+ assert_nil "".to_time
end
def test_string_to_datetime
@@ -125,12 +125,12 @@ class StringInflectionsTest < Test::Unit::TestCase
assert_equal 0, "2039-02-27 23:50".to_datetime.offset # use UTC offset
assert_equal ::Date::ITALY, "2039-02-27 23:50".to_datetime.start # use Ruby's default start value
assert_equal DateTime.civil(2039, 2, 27, 23, 50, 19 + Rational(275038, 1000000), "-04:00"), "2039-02-27T23:50:19.275038-04:00".to_datetime
- assert_equal nil, "".to_datetime
+ assert_nil "".to_datetime
end
def test_string_to_date
assert_equal Date.new(2005, 2, 27), "2005-02-27".to_date
- assert_equal nil, "".to_date
+ assert_nil "".to_date
end
def test_access
@@ -224,7 +224,7 @@ class CoreExtStringMultibyteTest < ActiveSupport::TestCase
BYTE_STRING = "\270\236\010\210\245"
def test_core_ext_adds_mb_chars
- assert UNICODE_STRING.respond_to?(:mb_chars)
+ assert_respond_to UNICODE_STRING, :mb_chars
end
def test_string_should_recognize_utf8_strings
@@ -236,20 +236,20 @@ class CoreExtStringMultibyteTest < ActiveSupport::TestCase
if RUBY_VERSION < '1.9'
def test_mb_chars_returns_self_when_kcode_not_set
with_kcode('none') do
- assert UNICODE_STRING.mb_chars.kind_of?(String)
+ assert_kind_of String, UNICODE_STRING.mb_chars
end
end
def test_mb_chars_returns_an_instance_of_the_chars_proxy_when_kcode_utf8
with_kcode('UTF8') do
- assert UNICODE_STRING.mb_chars.kind_of?(ActiveSupport::Multibyte.proxy_class)
+ assert_kind_of ActiveSupport::Multibyte.proxy_class, UNICODE_STRING.mb_chars
end
end
end
if RUBY_VERSION >= '1.9'
def test_mb_chars_returns_string
- assert UNICODE_STRING.mb_chars.kind_of?(String)
+ assert_kind_of String, UNICODE_STRING.mb_chars
end
end
end
@@ -439,6 +439,14 @@ class OutputSafetyTest < ActiveSupport::TestCase
test 'emits normal string yaml' do
assert_equal 'foo'.to_yaml, 'foo'.html_safe.to_yaml(:foo => 1)
end
+
+ test 'knows whether it is encoding aware' do
+ if RUBY_VERSION >= "1.9"
+ assert 'ruby'.encoding_aware?
+ else
+ assert !'ruby'.encoding_aware?
+ end
+ end
end
class StringExcludeTest < ActiveSupport::TestCase
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index 30ee1d1652..1cf84df386 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -166,10 +166,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
# assert_equal Time.local(2182,6,5,10), Time.local(2005,6,5,10,0,0).years_since(177)
end
- def test_last_year_is_deprecated
- assert_deprecated { Time.now.last_year }
- end
-
def test_prev_year
assert_equal Time.local(2004,6,5,10), Time.local(2005,6,5,10,0,0).prev_year
end
@@ -619,10 +615,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005, 9, 30), Time.local(2005, 8, 31).next_month
end
- def test_last_month_is_deprecated
- assert_deprecated { Time.now.last_month }
- end
-
def test_prev_month_on_31st
assert_equal Time.local(2004, 2, 29), Time.local(2004, 3, 31).prev_month
end
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index a808a25821..77b1893f77 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -279,13 +279,13 @@ class TimeWithZoneTest < Test::Unit::TestCase
def test_to_f
result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_f
assert_equal 946684800.0, result
- assert result.is_a?(Float)
+ assert_kind_of Float, result
end
def test_to_i
result = ActiveSupport::TimeWithZone.new( Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Hawaii'] ).to_i
assert_equal 946684800, result
- assert result.is_a?(Integer)
+ assert_kind_of Integer, result
end
def test_to_i_with_wrapped_datetime
@@ -324,9 +324,9 @@ class TimeWithZoneTest < Test::Unit::TestCase
end
def test_is_a
- assert @twz.is_a?(Time)
- assert @twz.kind_of?(Time)
- assert @twz.is_a?(ActiveSupport::TimeWithZone)
+ assert_kind_of Time, @twz
+ assert_kind_of Time, @twz
+ assert ActiveSupport::TimeWithZone, @twz
end
def test_class_name
@@ -830,7 +830,7 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase
assert_raise(TZInfo::InvalidTimezoneIdentifier) { Time.zone.utc_offset }
Time.zone = -15.hours
- assert_equal nil, Time.zone
+ assert_nil Time.zone
end
def test_current_returns_time_now_when_zone_default_not_set
diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb
index caf50aa1c9..f15b1351f7 100644
--- a/activesupport/test/multibyte_chars_test.rb
+++ b/activesupport/test/multibyte_chars_test.rb
@@ -31,12 +31,12 @@ class MultibyteCharsTest < Test::Unit::TestCase
end
def test_forwarded_method_calls_should_return_new_chars_instance
- assert @chars.__method_for_multibyte_testing.kind_of?(@proxy_class)
+ assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing
assert_not_equal @chars.object_id, @chars.__method_for_multibyte_testing.object_id
end
def test_forwarded_bang_method_calls_should_return_the_original_chars_instance
- assert @chars.__method_for_multibyte_testing!.kind_of?(@proxy_class)
+ assert_kind_of @proxy_class, @chars.__method_for_multibyte_testing!
assert_equal @chars.object_id, @chars.__method_for_multibyte_testing!.object_id
end
@@ -114,7 +114,7 @@ class MultibyteCharsUTF8BehaviourTest < Test::Unit::TestCase
if RUBY_VERSION < '1.9'
def test_split_should_return_an_array_of_chars_instances
@chars.split(//).each do |character|
- assert character.kind_of?(ActiveSupport::Multibyte.proxy_class)
+ assert_kind_of ActiveSupport::Multibyte.proxy_class, character
end
end
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index 516da7a14c..620623b389 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -22,7 +22,7 @@ class TimeZoneTest < Test::Unit::TestCase
ActiveSupport::TimeZone::MAPPING.keys.each do |name|
define_method("test_map_#{name.downcase.gsub(/[^a-z]/, '_')}_to_tzinfo") do
zone = ActiveSupport::TimeZone[name]
- assert zone.tzinfo.respond_to?(:period_for_local)
+ assert_respond_to zone.tzinfo, :period_for_local
end
end
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index 50146dd372..dd4e94a9e1 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -1462,11 +1462,32 @@ Rails also comes with built-in help that you can generate using the rake command
* Running +rake doc:guides+ will put a full copy of the Rails Guides in the +doc/guides+ folder of your application. Open +doc/guides/index.html+ in your web browser to explore the Guides.
* Running +rake doc:rails+ will put a full copy of the API documentation for Rails in the +doc/api+ folder of your application. Open +doc/api/index.html+ in your web browser to explore the API documentation.
+h3. Configuration Gotchas
+
+The easiest way to work with Rails is to store all external data as UTF-8. If you don't, Ruby libraries and Rails will often be able to convert your native data into UTF-8, but this doesn't always work reliably, so you're better off ensuring that all external data is UTF-8.
+
+If you have made a mistake in this area, the most common symptom is a black diamond with a question mark inside appearing in the browser. Another common symptom is characters like "ü" appearing instead of "ü". Rails takes a number of internal steps to mitigate common causes of these problems that can be automatically detected and corrected. However, if you have external data that is not stored as UTF-8, it can occasionally result in these kinds of issues that cannot be automatically detected by Rails and corrected.
+
+Two very common sources of data that are not UTF-8:
+* Your text editor: Most text editors (such as Textmate), default to saving files as
+ UTF-8. If your text editor does not, this can result in special characters that you
+ enter in your templates (such as é) to appear as a diamond with a question mark inside
+ in the browser. This also applies to your I18N translation files.
+ Most editors that do not already default to UTF-8 (such as some versions of
+ Dreamweaver) offer a way to change the default to UTF-8. Do so.
+* Your database. Rails defaults to converting data from your database into UTF-8 at
+ the boundary. However, if your database is not using UTF-8 internally, it may not
+ be able to store all characters that your users enter. For instance, if your database
+ is using Latin-1 internally, and your user enters a Russian, Hebrew, or Japanese
+ character, the data will be lost forever once it enters the database. If possible,
+ use UTF-8 as the internal storage of your database.
h3. Changelog
"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/2
+* May 16, 2010: Added a section on configuration gotchas to address common encoding
+ problems that people might have
* April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com
* April 25, 2010: Couple of more minor fixups "Mikel Lindsaar":credits.html#raasdnil
* April 1, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index 0611b2a9f5..be486ef2ac 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -23,6 +23,7 @@ if RUBY_VERSION < '1.9'
$KCODE='u'
else
Encoding.default_external = Encoding::UTF_8
+ Encoding.default_internal = Encoding::UTF_8
end
module Rails
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 9353fbefef..1b8af370f7 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -1,4 +1,5 @@
require 'active_support/deprecation'
+require 'active_support/core_ext/string/encoding'
require 'rails/engine/configuration'
module Rails
@@ -10,7 +11,8 @@ module Rails
:encoding, :consider_all_requests_local, :dependency_loading,
:filter_parameters, :log_level, :logger, :metals,
:plugins, :preload_frameworks, :reload_engines, :reload_plugins,
- :secret_token, :serve_static_assets, :time_zone, :whiny_nils
+ :secret_token, :serve_static_assets, :session_options,
+ :time_zone, :whiny_nils
def initialize(*)
super
@@ -27,8 +29,15 @@ module Rails
def encoding=(value)
@encoding = value
- if defined?(Encoding) && Encoding.respond_to?(:default_external=)
+ if "ruby".encoding_aware?
Encoding.default_external = value
+ Encoding.default_internal = value
+ else
+ $KCODE = value
+ if $KCODE == "NONE"
+ raise "The value you specified for config.encoding is " \
+ "invalid. The possible values are UTF8, SJIS, or EUC"
+ end
end
end
@@ -130,11 +139,6 @@ module Rails
end
end
- def session_options
- return @session_options unless @session_store == :cookie_store
- @session_options.merge(:secret => @secret_token)
- end
-
protected
def default_middleware_stack
diff --git a/railties/lib/rails/dispatcher.rb b/railties/lib/rails/dispatcher.rb
deleted file mode 100644
index 75ee4de140..0000000000
--- a/railties/lib/rails/dispatcher.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-#--
-# Copyright (c) 2004-2010 David Heinemeier Hansson
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#++
-require 'action_controller/deprecated/dispatcher'
-Dispatcher = ActionController::Dispatcher
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index dfc4e2359b..9928ee2c52 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -180,7 +180,8 @@ module ApplicationTests
require "#{app_path}/config/application"
unless RUBY_VERSION < '1.9'
- assert_equal Encoding.find("utf-8"), Encoding.default_external
+ assert_equal Encoding::UTF_8, Encoding.default_external
+ assert_equal Encoding::UTF_8, Encoding.default_internal
end
end
@@ -195,7 +196,7 @@ module ApplicationTests
test "config.secret_token is sent in env" do
make_basic_app do |app|
- app.config.secret_token = 'ThisIsASECRET123'
+ app.config.secret_token = 'b3c631c314c0bbca50c1b2843150fe33'
app.config.session_store :disabled
end
@@ -207,7 +208,7 @@ module ApplicationTests
end
get "/"
- assert_equal 'ThisIsASECRET123', last_response.body
+ assert_equal 'b3c631c314c0bbca50c1b2843150fe33', last_response.body
end
test "protect from forgery is the default in a new app" do
diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb
index 8e57022e5b..fadcc4c025 100644
--- a/railties/test/application/initializers/frameworks_test.rb
+++ b/railties/test/application/initializers/frameworks_test.rb
@@ -47,7 +47,7 @@ module ApplicationTests
test "if there's no config.active_support.bare, all of ActiveSupport is required" do
use_frameworks []
require "#{app_path}/config/environment"
- assert_nothing_raised { [1,2,3].rand }
+ assert_nothing_raised { [1,2,3].random_element }
end
test "config.active_support.bare does not require all of ActiveSupport" do
@@ -57,7 +57,7 @@ module ApplicationTests
Dir.chdir("#{app_path}/app") do
require "#{app_path}/config/environment"
- assert_raises(NoMethodError) { [1,2,3].rand }
+ assert_raises(NoMethodError) { [1,2,3].random_element }
end
end
diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb
index d08f04bddb..617525bf78 100644
--- a/railties/test/application/middleware_test.rb
+++ b/railties/test/application/middleware_test.rb
@@ -175,7 +175,10 @@ module ApplicationTests
def remote_ip(env = {})
remote_ip = nil
- env = Rack::MockRequest.env_for("/").merge(env).merge('action_dispatch.show_exceptions' => false)
+ env = Rack::MockRequest.env_for("/").merge(env).merge!(
+ 'action_dispatch.show_exceptions' => false,
+ 'action_dispatch.secret_token' => 'b3c631c314c0bbca50c1b2843150fe33'
+ )
endpoint = Proc.new do |e|
remote_ip = ActionDispatch::Request.new(e).remote_ip
diff --git a/railties/test/application/rackup_test.rb b/railties/test/application/rackup_test.rb
index f909c1b282..3790de721c 100644
--- a/railties/test/application/rackup_test.rb
+++ b/railties/test/application/rackup_test.rb
@@ -28,14 +28,14 @@ module ApplicationTests
test "Rails.application is available after config.ru has been racked up" do
rackup
- assert Rails.application.is_a?(Rails::Application)
+ assert_kind_of Rails::Application, Rails.application
end
# Passenger still uses AC::Dispatcher, so we need to
# keep it working for now
test "deprecated ActionController::Dispatcher still works" do
rackup
- assert ActionController::Dispatcher.new.is_a?(Rails::Application)
+ assert_kind_of? Rails::Application, ActionController::Dispatcher.new
end
test "the config object is available on the application object" do