aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--actionmailer/actionmailer.gemspec2
-rw-r--r--actionmailer/lib/action_mailer/base.rb11
-rw-r--r--actionmailer/lib/action_mailer/test_helper.rb2
-rw-r--r--actionpack/CHANGELOG.md5
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/metal.rb10
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb2
-rw-r--r--actionpack/lib/action_controller/metal/implicit_render.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb9
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb29
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb24
-rw-r--r--actionpack/lib/action_view/flows.rb5
-rw-r--r--actionpack/lib/action_view/helpers/active_model_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb15
-rw-r--r--actionpack/lib/action_view/helpers/csrf_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb40
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb11
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb131
-rw-r--r--actionpack/lib/action_view/helpers/tags.rb48
-rw-r--r--actionpack/lib/action_view/helpers/tags/base.rb5
-rw-r--r--actionpack/lib/action_view/helpers/tags/date_select.rb8
-rw-r--r--actionpack/lib/action_view/helpers/tags/select.rb1
-rw-r--r--actionpack/lib/action_view/helpers/tags/text_field.rb8
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb22
-rw-r--r--actionpack/lib/action_view/locale/en.yml1
-rw-r--r--actionpack/lib/action_view/template.rb5
-rw-r--r--actionpack/lib/action_view/template/error.rb4
-rw-r--r--actionpack/test/abstract_unit.rb15
-rw-r--r--actionpack/test/controller/base_test.rb6
-rw-r--r--actionpack/test/controller/force_ssl_test.rb3
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb7
-rw-r--r--actionpack/test/controller/rescue_test.rb4
-rw-r--r--actionpack/test/controller/routing_test.rb82
-rw-r--r--actionpack/test/dispatch/cookies_test.rb11
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb2
-rw-r--r--actionpack/test/dispatch/routing_test.rb23
-rw-r--r--actionpack/test/dispatch/show_exceptions_test.rb2
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb6
-rw-r--r--actionpack/test/template/date_helper_i18n_test.rb8
-rw-r--r--actionpack/test/template/date_helper_test.rb36
-rw-r--r--actionpack/test/template/form_helper_test.rb8
-rw-r--r--actionpack/test/template/form_options_helper_test.rb16
-rw-r--r--actionpack/test/template/html-scanner/sanitizer_test.rb2
-rw-r--r--actionpack/test/template/number_helper_test.rb26
-rw-r--r--actionpack/test/template/template_error_test.rb4
-rw-r--r--actionpack/test/template/url_helper_test.rb27
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb4
-rw-r--r--activemodel/lib/active_model/errors.rb2
-rw-r--r--activemodel/lib/active_model/observing.rb2
-rw-r--r--activemodel/test/cases/validations/callbacks_test.rb7
-rw-r--r--activerecord/CHANGELOG.md29
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb3
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb100
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb16
-rw-r--r--activerecord/lib/active_record/core.rb45
-rw-r--r--activerecord/lib/active_record/counter_cache.rb6
-rw-r--r--activerecord/lib/active_record/locking/pessimistic.rb22
-rw-r--r--activerecord/lib/active_record/railtie.rb3
-rw-r--r--activerecord/lib/active_record/relation.rb4
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb10
-rw-r--r--activerecord/lib/active_record/test_case.rb35
-rw-r--r--activerecord/test/cases/adapters/sqlite3/quoting_test.rb4
-rw-r--r--activerecord/test/cases/attribute_methods/read_test.rb8
-rw-r--r--activerecord/test/cases/base_test.rb39
-rw-r--r--activerecord/test/cases/helper.rb2
-rw-r--r--activerecord/test/cases/locking_test.rb20
-rw-r--r--activerecord/test/cases/migration/index_test.rb8
-rw-r--r--activerecord/test/cases/test_case.rb63
-rw-r--r--activeresource/lib/active_resource/base.rb141
-rw-r--r--activeresource/lib/active_resource/connection.rb46
-rw-r--r--activeresource/lib/active_resource/custom_methods.rb4
-rw-r--r--activeresource/lib/active_resource/http_mock.rb21
-rw-r--r--activeresource/lib/active_resource/validations.rb2
-rw-r--r--activeresource/test/cases/authorization_test.rb161
-rw-r--r--activeresource/test/cases/connection_test.rb1
-rw-r--r--activeresource/test/fixtures/street_address.rb2
-rw-r--r--activesupport/CHANGELOG.md2
-rw-r--r--activesupport/lib/active_support/callbacks.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb27
-rw-r--r--activesupport/lib/active_support/core_ext/module/delegation.rb38
-rw-r--r--activesupport/lib/active_support/core_ext/string/inflections.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/uri.rb2
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb12
-rw-r--r--activesupport/lib/active_support/log_subscriber.rb6
-rw-r--r--activesupport/lib/active_support/logger.rb35
-rw-r--r--activesupport/lib/active_support/ordered_options.rb5
-rw-r--r--activesupport/lib/active_support/tagged_logging.rb78
-rw-r--r--activesupport/lib/active_support/test_case.rb2
-rw-r--r--activesupport/lib/active_support/testing/isolation.rb22
-rw-r--r--activesupport/lib/active_support/testing/pending.rb20
-rw-r--r--activesupport/lib/active_support/testing/performance.rb47
-rw-r--r--activesupport/test/broadcast_logger_test.rb82
-rw-r--r--activesupport/test/callbacks_test.rb56
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb13
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb8
-rw-r--r--activesupport/test/core_ext/uri_ext_test.rb8
-rw-r--r--activesupport/test/log_subscriber_test.rb4
-rw-r--r--rails.gemspec2
-rw-r--r--railties/guides/code/getting_started/Gemfile23
-rw-r--r--railties/guides/code/getting_started/app/assets/javascripts/application.js12
-rw-r--r--railties/guides/code/getting_started/app/assets/stylesheets/application.css16
-rw-r--r--railties/guides/code/getting_started/app/views/layouts/application.html.erb2
-rw-r--r--railties/guides/code/getting_started/config/application.rb14
-rw-r--r--railties/guides/code/getting_started/config/environments/development.rb18
-rw-r--r--railties/guides/code/getting_started/config/environments/production.rb40
-rw-r--r--railties/guides/code/getting_started/config/environments/test.rb20
-rw-r--r--railties/guides/code/getting_started/config/initializers/inflections.rb5
-rw-r--r--railties/guides/code/getting_started/config/routes.rb8
-rw-r--r--railties/guides/code/getting_started/public/500.html1
-rw-r--r--railties/guides/source/3_2_release_notes.textile56
-rw-r--r--railties/guides/source/active_record_querying.textile21
-rw-r--r--railties/guides/source/active_record_validations_callbacks.textile33
-rw-r--r--railties/guides/source/active_resource_basics.textile2
-rw-r--r--railties/guides/source/getting_started.textile4
-rw-r--r--railties/guides/source/i18n.textile6
-rw-r--r--railties/lib/rails/application/finisher.rb3
-rw-r--r--railties/lib/rails/commands/server.rb9
-rw-r--r--railties/lib/rails/deprecation.rb37
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/generators/generated_attribute.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb10
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt18
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt40
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt16
-rw-r--r--railties/lib/rails/rack/log_tailer.rb10
-rw-r--r--railties/test/generators/migration_generator_test.rb6
132 files changed, 1541 insertions, 901 deletions
diff --git a/Gemfile b/Gemfile
index 5edfcce3ec..3046a97573 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,8 +2,6 @@ source 'https://rubygems.org'
gemspec
-gem 'rack', :git => 'git://github.com/rack/rack.git'
-
if ENV['AREL']
gem 'arel', :path => ENV['AREL']
else
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec
index 1527e0ad86..c605f1ff04 100644
--- a/actionmailer/actionmailer.gemspec
+++ b/actionmailer/actionmailer.gemspec
@@ -17,5 +17,5 @@ Gem::Specification.new do |s|
s.requirements << 'none'
s.add_dependency('actionpack', version)
- s.add_dependency('mail', '~> 2.4.0')
+ s.add_dependency('mail', '~> 2.4.1')
end
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 7d8852f961..1800ff5839 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -1,7 +1,6 @@
require 'mail'
require 'action_mailer/collector'
require 'active_support/core_ext/object/blank'
-require 'active_support/core_ext/proc'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/hash/except'
require 'action_mailer/log_subscriber'
@@ -409,7 +408,7 @@ module ActionMailer #:nodoc:
# and passing a Mail::Message will do nothing except tell the logger you sent the email.
def deliver_mail(mail) #:nodoc:
ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload|
- self.set_payload_for_mail(payload, mail)
+ set_payload_for_mail(payload, mail)
yield # Let Mail do the delivery actions
end
end
@@ -602,9 +601,6 @@ module ActionMailer #:nodoc:
# end
#
def mail(headers={}, &block)
- # Guard flag to prevent both the old and the new API from firing
- # Should be removed when old API is removed
- @mail_was_called = true
m = @_message
# At the beginning, do not consider class default for parts order neither content_type
@@ -612,8 +608,9 @@ module ActionMailer #:nodoc:
parts_order = headers[:parts_order]
# Call all the procs (if any)
- default_values = self.class.default.merge(self.class.default) do |k,v|
- v.respond_to?(:call) ? v.bind(self).call : v
+ class_default = self.class.default
+ default_values = class_default.merge(class_default) do |k,v|
+ v.respond_to?(:to_proc) ? instance_eval(&v) : v
end
# Handle defaults
diff --git a/actionmailer/lib/action_mailer/test_helper.rb b/actionmailer/lib/action_mailer/test_helper.rb
index 5beab87ad2..7204822395 100644
--- a/actionmailer/lib/action_mailer/test_helper.rb
+++ b/actionmailer/lib/action_mailer/test_helper.rb
@@ -1,7 +1,5 @@
module ActionMailer
module TestHelper
- extend ActiveSupport::Concern
-
# Asserts that the number of emails sent matches the given number.
#
# def test_emails
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 382a3cbd1d..5e78aba0cc 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,4 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+
+* Add `:format` option to number_to_percentage *Rodrigo Flores*
+
* Add `config.action_view.logger` to configure logger for ActionView. *Rafael França*
* Deprecated ActionController::Integration in favour of ActionDispatch::Integration
@@ -33,8 +36,6 @@
* Deprecate method_missing handling for not found actions, use action_missing instead. *Carlos Antonio da Silva*
-* Deprecate ActionController#performed?, check for response_body presence instead. *Carlos Antonio da Silva*
-
* Deprecate ActionController#rescue_action, ActionController#initialize_template_class, and ActionController#assign_shortcuts.
These methods were not being used internally anymore and are going to be removed in Rails 4. *Carlos Antonio da Silva*
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 4ce0624207..f13b1d5a60 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
s.add_dependency('activemodel', version)
s.add_dependency('rack-cache', '~> 1.1')
s.add_dependency('builder', '~> 3.0.0')
- s.add_dependency('rack', '~> 1.4.0')
+ s.add_dependency('rack', '~> 1.4.1')
s.add_dependency('rack-test', '~> 0.6.1')
s.add_dependency('journey', '~> 1.0.0')
s.add_dependency('sprockets', '~> 2.2.0')
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 3aab77a069..92433ab462 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -181,9 +181,13 @@ module ActionController
@_status = Rack::Utils.status_code(status)
end
- def response_body=(val)
- body = (val.nil? || val.respond_to?(:each)) ? val : [val]
- super body
+ def response_body=(body)
+ body = [body] unless body.nil? || body.respond_to?(:each)
+ super
+ end
+
+ def performed?
+ !!response_body
end
def dispatch(name, request) #:nodoc:
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 4972c6bede..3d46163b74 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -67,7 +67,7 @@ module ActionController
# class PostsController < ApplicationController
# REALM = "SuperSecret"
# USERS = {"dhh" => "secret", #plain text password
- # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password
+ # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password
#
# before_filter :authenticate, :except => [:index]
#
diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb
index e8e465d3ba..ae04b53825 100644
--- a/actionpack/lib/action_controller/metal/implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/implicit_render.rb
@@ -2,7 +2,7 @@ module ActionController
module ImplicitRender
def send_action(method, *args)
ret = super
- default_render unless response_body
+ default_render unless performed?
ret
end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 39ff58a447..25f1db8228 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -191,6 +191,15 @@ module ActionDispatch
value
end
+ # Whether the given cookie is to be deleted by this CookieJar.
+ # Like <tt>[]=</tt>, you can pass in an options hash to test if a
+ # deletion applies to a specific <tt>:path</tt>, <tt>:domain</tt> etc.
+ def deleted?(key, options = {})
+ options.symbolize_keys!
+ handle_options(options)
+ @delete_cookies[key.to_s] == options
+ end
+
# Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie
def clear(options = {})
@cookies.each_key{ |k| delete(k, options) }
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index db1e3198b3..e2d7a29079 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -2,6 +2,7 @@ require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/inclusion'
require 'active_support/inflector'
+require 'active_support/deprecation'
require 'action_dispatch/routing/redirection'
module ActionDispatch
@@ -54,6 +55,7 @@ module ActionDispatch
def initialize(set, scope, path, options)
@set, @scope = set, scope
+ @segment_keys = nil
@options = (@scope[:options] || {}).merge(options)
@path = normalize_path(path)
normalize_options!
@@ -213,7 +215,9 @@ module ActionDispatch
end
def segment_keys
- @segment_keys ||= Journey::Path::Pattern.new(
+ return @segment_keys if @segment_keys
+
+ @segment_keys = Journey::Path::Pattern.new(
Journey::Router::Strexp.compile(@path, requirements, SEPARATORS)
).names
end
@@ -464,7 +468,7 @@ module ActionDispatch
#
# get 'bacon', :to => 'food#bacon'
def get(*args, &block)
- map_method(:get, *args, &block)
+ map_method(:get, args, &block)
end
# Define a route that only recognizes HTTP POST.
@@ -474,7 +478,7 @@ module ActionDispatch
#
# post 'bacon', :to => 'food#bacon'
def post(*args, &block)
- map_method(:post, *args, &block)
+ map_method(:post, args, &block)
end
# Define a route that only recognizes HTTP PUT.
@@ -484,7 +488,7 @@ module ActionDispatch
#
# put 'bacon', :to => 'food#bacon'
def put(*args, &block)
- map_method(:put, *args, &block)
+ map_method(:put, args, &block)
end
# Define a route that only recognizes HTTP PUT.
@@ -494,15 +498,24 @@ module ActionDispatch
#
# delete 'broccoli', :to => 'food#broccoli'
def delete(*args, &block)
- map_method(:delete, *args, &block)
+ map_method(:delete, args, &block)
end
private
- def map_method(method, *args, &block)
+ def map_method(method, args, &block)
+ if args.length > 2
+ ActiveSupport::Deprecation.warn <<-eowarn
+The method signature of #{method}() is changing to:
+
+ #{method}(path, options = {}, &block)
+
+Calling with multiple paths is deprecated.
+ eowarn
+ end
+
options = args.extract_options!
options[:via] = method
- args.push(options)
- match(*args, &block)
+ match(*args, options, &block)
self
end
end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 2c21887220..ac4dd7d927 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -360,7 +360,26 @@ module ActionDispatch
SEPARATORS,
anchor)
- Journey::Path::Pattern.new(strexp)
+ pattern = Journey::Path::Pattern.new(strexp)
+
+ builder = Journey::GTG::Builder.new pattern.spec
+
+ # Get all the symbol nodes followed by literals that are not the
+ # dummy node.
+ symbols = pattern.spec.grep(Journey::Nodes::Symbol).find_all { |n|
+ builder.followpos(n).first.literal?
+ }
+
+ # Get all the symbol nodes preceded by literals.
+ symbols.concat pattern.spec.find_all(&:literal?).map { |n|
+ builder.followpos(n).first
+ }.find_all(&:symbol?)
+
+ symbols.each { |x|
+ x.regexp = /(?:#{Regexp.union(x.regexp, '-')})+/
+ }
+
+ pattern
end
private :build_path
@@ -579,7 +598,8 @@ module ActionDispatch
params[key] = URI.parser.unescape(value)
end
end
-
+ old_params = env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] = (old_params || {}).merge(params)
dispatcher = route.app
while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
dispatcher = dispatcher.app
diff --git a/actionpack/lib/action_view/flows.rb b/actionpack/lib/action_view/flows.rb
index a8f740713f..c0e458cd41 100644
--- a/actionpack/lib/action_view/flows.rb
+++ b/actionpack/lib/action_view/flows.rb
@@ -22,11 +22,8 @@ module ActionView
def append(key, value)
@content[key] << value
end
+ alias_method :append!, :append
- # Called by provide
- def append!(key, value)
- @content[key] << value
- end
end
class StreamingFlow < OutputFlow #:nodoc:
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index 973135e2ea..1187956081 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -16,7 +16,9 @@ module ActionView
end
end
- module_eval "def content_tag(*) error_wrapping(super) end", __FILE__, __LINE__
+ def content_tag(*)
+ error_wrapping(super)
+ end
def tag(type, options, *)
tag_generate_errors?(options) ? error_wrapping(super) : super
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 5dbba3c4a7..134eaab8bc 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -422,7 +422,7 @@ module ActionView
if sources.is_a?(Array)
content_tag("video", options) do
- sources.map { |source| tag("source", :src => source) }.join.html_safe
+ sources.map { |source| tag("source", :src => path_to_video(source)) }.join.html_safe
end
else
options[:src] = path_to_video(sources)
@@ -441,10 +441,17 @@ module ActionView
# <audio src="/audios/sound.wav" />
# audio_tag("sound.wav", :autoplay => true, :controls => true) # =>
# <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />
- def audio_tag(source, options = {})
+ def audio_tag(sources, options = {})
options.symbolize_keys!
- options[:src] = path_to_audio(source)
- tag("audio", options)
+
+ if sources.is_a?(Array)
+ content_tag("audio", options) do
+ sources.collect { |source| tag("source", :src => path_to_audio(source)) }.join.html_safe
+ end
+ else
+ options[:src] = path_to_audio(sources)
+ tag("audio", options)
+ end
end
private
diff --git a/actionpack/lib/action_view/helpers/csrf_helper.rb b/actionpack/lib/action_view/helpers/csrf_helper.rb
index 1f2bc28cac..eeb0ed94b9 100644
--- a/actionpack/lib/action_view/helpers/csrf_helper.rb
+++ b/actionpack/lib/action_view/helpers/csrf_helper.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/string/strip'
-
module ActionView
# = Action View CSRF Helper
module Helpers
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index f5077b034a..ea71889519 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -142,6 +142,8 @@ module ActionView
# ==== Options
# * <tt>:use_month_numbers</tt> - Set to true if you want to use month numbers rather than month names (e.g.
# "2" instead of "February").
+ # * <tt>:use_two_digit_numbers</tt> - Set to true if you want to display two digit month and day numbers (e.g.
+ # "02" instead of "February" and "08" instead of "8").
# * <tt>:use_short_month</tt> - Set to true if you want to use abbreviated month names instead of full
# month names (e.g. "Feb" instead of "February").
# * <tt>:add_month_numbers</tt> - Set to true if you want to use both month numbers and month names (e.g.
@@ -189,6 +191,10 @@ module ActionView
# date_select("article", "written_on", :start_year => 1995, :use_month_numbers => true,
# :discard_day => true, :include_blank => true)
#
+ # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute,
+ # # with two digit numbers used for months and days.
+ # date_select("article", "written_on", :use_two_digit_numbers => true)
+ #
# # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute
# # with the fields ordered as day, month, year rather than month, day, year.
# date_select("article", "written_on", :order => [:day, :month, :year])
@@ -502,6 +508,7 @@ module ActionView
# Returns a select tag with options for each of the days 1 through 31 with the current day selected.
# The <tt>date</tt> can also be substituted for a day number.
+ # If you want to display days with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
# Override the field name using the <tt>:field_name</tt> option, 'day' by default.
#
# ==== Examples
@@ -513,6 +520,9 @@ module ActionView
# # Generates a select field for days that defaults to the number given.
# select_day(5)
#
+ # # Generates a select field for days that defaults to the number given, but displays it with two digits.
+ # select_day(5, :use_two_digit_numbers => true)
+ #
# # Generates a select field for days that defaults to the day for the date in my_date
# # that is named 'due' rather than 'day'.
# select_day(my_time, :field_name => 'due')
@@ -532,6 +542,7 @@ module ActionView
# want both numbers and names, set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer
# to show month names as abbreviations, set the <tt>:use_short_month</tt> key in +options+ to true. If you want
# to use your own month names, set the <tt>:use_month_names</tt> key in +options+ to an array of 12 month names.
+ # If you want to display months with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
# Override the field name using the <tt>:field_name</tt> option, 'month' by default.
#
# ==== Examples
@@ -559,6 +570,10 @@ module ActionView
# # will use keys like "Januar", "Marts."
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
#
+ # # Generates a select field for months that defaults to the current month that
+ # # will use keys with two digit numbers like "01", "03".
+ # select_month(Date.today, :use_two_digit_numbers => true)
+ #
# # Generates a select field for months with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_month(14, :prompt => 'Choose month')
@@ -734,7 +749,7 @@ module ActionView
def select_day
if @options[:use_hidden] || @options[:discard_day]
- build_hidden(:day, day)
+ build_hidden(:day, day || 1)
else
build_options_and_select(:day, day, :start => 1, :end => 31, :leading_zeros => false, :use_two_digit_numbers => @options[:use_two_digit_numbers])
end
@@ -742,7 +757,7 @@ module ActionView
def select_month
if @options[:use_hidden] || @options[:discard_month]
- build_hidden(:month, month)
+ build_hidden(:month, month || 1)
else
month_options = []
1.upto(12) do |month_number|
@@ -756,7 +771,7 @@ module ActionView
def select_year
if !@datetime || @datetime == 0
- val = ''
+ val = '1'
middle_year = Date.today.year
else
val = middle_year = year
@@ -817,6 +832,9 @@ module ActionView
# If <tt>:use_month_numbers</tt> option is passed
# month_name(1) => 1
#
+ # If <tt>:use_two_month_numbers</tt> option is passed
+ # month_name(1) => '01'
+ #
# If <tt>:add_month_numbers</tt> option is passed
# month_name(1) => "1 - January"
def month_name(number)
@@ -836,7 +854,15 @@ module ActionView
end
def translated_date_order
- I18n.translate(:'date.order', :locale => @options[:locale]) || []
+ date_order = I18n.translate(:'date.order', :locale => @options[:locale]) || []
+
+ forbidden_elements = date_order - [:year, :month, :day]
+ if forbidden_elements.any?
+ raise StandardError,
+ "#{@options[:locale]}.date.order only accepts :year, :month and :day"
+ end
+
+ date_order
end
# Build full select tag from date type and options.
@@ -850,6 +876,12 @@ module ActionView
# <option value="2">2</option>
# <option value="3">3</option>..."
#
+ # If <tt>:use_two_digit_numbers => true</tt> option is passed
+ # build_options(15, :start => 1, :end => 31, :use_two_digit_numbers => true)
+ # => "<option value="1">01</option>
+ # <option value="2">02</option>
+ # <option value="3">03</option>..."
+ #
# If <tt>:step</tt> options is passed
# build_options(15, :start => 1, :end => 31, :step => 2)
# => "<option value="1">1</option>
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index e323350608..c8811e3b10 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -334,7 +334,7 @@ module ActionView
end.join("\n").html_safe
end
- # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
+ # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning
# the result of a call to the +value_method+ as the option value and the +text_method+ as the option text.
# Example:
# options_from_collection_for_select(@people, 'id', 'name')
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 57b90a9c42..e97f602728 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -627,7 +627,7 @@ module ActionView
token_tag(authenticity_token)
else
html_options["method"] = "post"
- tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag(authenticity_token)
+ method_tag(method) + token_tag(authenticity_token)
end
tags = utf8_enforcer_tag << method_tag
@@ -646,15 +646,6 @@ module ActionView
output.safe_concat("</form>")
end
- def token_tag(token)
- if token == false || !protect_against_forgery?
- ''
- else
- token ||= form_authenticity_token
- tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token)
- end
- end
-
# see http://www.w3.org/TR/html4/types.html#type-name
def sanitize_to_id(name)
name.to_s.gsub(']','').gsub(/[^-a-zA-Z0-9:.]/, "_")
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 43122ef2ba..b0860f87c4 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -57,15 +57,11 @@ module ActionView
# # => +1.123.555.1234 x 1343
def number_to_phone(number, options = {})
return unless number
+ options = options.symbolize_keys
- begin
- Float(number)
- rescue ArgumentError, TypeError
- raise InvalidNumberError, number
- end if options[:raise]
+ parse_float(number, true) if options[:raise]
number = number.to_s.strip
- options = options.symbolize_keys
area_code = options[:area_code]
delimiter = options[:delimiter] || "-"
extension = options[:extension]
@@ -75,7 +71,7 @@ module ActionView
number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
else
number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
- number.slice!(0, 1) if number.starts_with?(delimiter) && !delimiter.blank?
+ number.slice!(0, 1) if number.start_with?(delimiter) && !delimiter.blank?
end
str = []
@@ -122,14 +118,12 @@ module ActionView
# # => 1234567890,50 &pound;
def number_to_currency(number, options = {})
return unless number
+ options = options.symbolize_keys
- options.symbolize_keys!
-
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {})
+ currency = translations_for('currency', options[:locale])
currency[:negative_format] ||= "-" + currency[:format] if currency[:format]
- defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency)
+ defaults = DEFAULT_CURRENCY_VALUES.merge(defaults_translations(options[:locale])).merge!(currency)
defaults[:negative_format] = "-" + options[:format] if options[:format]
options = defaults.merge!(options)
@@ -152,7 +146,6 @@ module ActionView
e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
end
end
-
end
# Formats a +number+ as a percentage string (e.g., 65%). You can customize the format in the +options+ hash.
@@ -169,6 +162,8 @@ module ActionView
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator
# (defaults to +false+).
+ # * <tt>:format</tt> - Specifies the format of the percentage string
+ # The number field is <tt>%n</tt> (defaults to "%n%").
# * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
#
# ==== Examples
@@ -180,26 +175,27 @@ module ActionView
# number_to_percentage(302.24398923423, :precision => 5) # => 302.24399%
# number_to_percentage(1000, :locale => :fr) # => 1 000,000%
# number_to_percentage("98a") # => 98a%
+ # number_to_percentage(100, :format => "%n %") # => 100 %
#
# number_to_percentage("98a", :raise => true) # => InvalidNumberError
def number_to_percentage(number, options = {})
return unless number
+ options = options.symbolize_keys
- options.symbolize_keys!
+ defaults = format_translations('percentage', options[:locale])
+ options = defaults.merge!(options)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(percentage)
-
- options = options.reverse_merge(defaults)
+ format = options[:format] || "%n%"
begin
- "#{number_with_precision(number, options.merge(:raise => true))}%".html_safe
+ value = number_with_precision(number, options.merge(:raise => true))
+ format.gsub(/%n/, value).html_safe
rescue InvalidNumberError => e
if options[:raise]
raise
else
- e.number.to_s.html_safe? ? "#{e.number}%".html_safe : "#{e.number}%"
+ formatted_number = format.gsub(/%n/, e.number)
+ e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
end
end
end
@@ -229,25 +225,15 @@ module ActionView
#
# number_with_delimiter("112a", :raise => true) # => raise InvalidNumberError
def number_with_delimiter(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ parse_float(number, options[:raise]) or return number
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- options = options.reverse_merge(defaults)
+ options = defaults_translations(options[:locale]).merge(options)
parts = number.to_s.to_str.split('.')
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
parts.join(options[:separator]).html_safe
-
end
# Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision
@@ -264,6 +250,7 @@ module ActionView
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator
# (defaults to +false+).
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
#
# ==== Examples
# number_with_precision(111.2345) # => 111.235
@@ -282,23 +269,13 @@ module ActionView
# number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
# # => 1.111,23
def number_with_precision(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- number = begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ number = (parse_float(number, options[:raise]) or return number)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(precision_defaults)
+ defaults = format_translations('precision', options[:locale])
+ options = defaults.merge!(options)
- options = options.reverse_merge(defaults) # Allow the user to unset default values: Eg.: :significant => false
precision = options.delete :precision
significant = options.delete :significant
strip_insignificant_zeros = options.delete :strip_insignificant_zeros
@@ -323,7 +300,6 @@ module ActionView
else
formatted_number
end
-
end
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
@@ -343,6 +319,7 @@ module ActionView
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +true+)
# * <tt>:prefix</tt> - If +:si+ formats the number using the SI prefix (defaults to :binary)
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
# ==== Examples
# number_to_human_size(123) # => 123 Bytes
# number_to_human_size(1234) # => 1.21 KB
@@ -359,23 +336,13 @@ module ActionView
# number_to_human_size(1234567890123, :precision => 5) # => "1.1229 TB"
# number_to_human_size(524288000, :precision => 5) # => "500 MB"
def number_to_human_size(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- number = begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ number = (parse_float(number, options[:raise]) or return number)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(human)
+ defaults = format_translations('human', options[:locale])
+ options = defaults.merge!(options)
- options = options.reverse_merge(defaults)
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
@@ -424,6 +391,7 @@ module ActionView
# * *integers*: <tt>:unit</tt>, <tt>:ten</tt>, <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>, <tt>:billion</tt>, <tt>:trillion</tt>, <tt>:quadrillion</tt>
# * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>, <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>, <tt>:pico</tt>, <tt>:femto</tt>
# * <tt>:format</tt> - Sets the format of the output string (defaults to "%n %u"). The field types are:
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when the argument is invalid.
#
# %u The quantifier (ex.: 'thousand')
# %n The number
@@ -478,23 +446,13 @@ module ActionView
# number_to_human(0.34, :units => :distance) # => "34 centimeters"
#
def number_to_human(number, options = {})
- options.symbolize_keys!
+ options = options.symbolize_keys
- number = begin
- Float(number)
- rescue ArgumentError, TypeError
- if options[:raise]
- raise InvalidNumberError, number
- else
- return number
- end
- end
+ number = (parse_float(number, options[:raise]) or return number)
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
- human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
- defaults = defaults.merge(human)
+ defaults = format_translations('human', options[:locale])
+ options = defaults.merge!(options)
- options = options.reverse_merge(defaults)
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
@@ -530,6 +488,25 @@ module ActionView
decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip.html_safe
end
+ private
+
+ def format_translations(namespace, locale)
+ defaults_translations(locale).merge(translations_for(namespace, locale))
+ end
+
+ def defaults_translations(locale)
+ I18n.translate(:'number.format', :locale => locale, :default => {})
+ end
+
+ def translations_for(namespace, locale)
+ I18n.translate(:"number.#{namespace}.format", :locale => locale, :default => {})
+ end
+
+ def parse_float(number, raise_error)
+ Float(number)
+ rescue ArgumentError, TypeError
+ raise InvalidNumberError, number if raise_error
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionpack/lib/action_view/helpers/tags.rb
index 89b3efda5f..e874d4ca42 100644
--- a/actionpack/lib/action_view/helpers/tags.rb
+++ b/actionpack/lib/action_view/helpers/tags.rb
@@ -1,28 +1,30 @@
module ActionView
module Helpers
- module Tags
- autoload :Base, 'action_view/helpers/tags/base'
- autoload :Label, 'action_view/helpers/tags/label'
- autoload :TextField, 'action_view/helpers/tags/text_field'
- autoload :PasswordField, 'action_view/helpers/tags/password_field'
- autoload :HiddenField, 'action_view/helpers/tags/hidden_field'
- autoload :FileField, 'action_view/helpers/tags/file_field'
- autoload :SearchField, 'action_view/helpers/tags/search_field'
- autoload :TelField, 'action_view/helpers/tags/tel_field'
- autoload :UrlField, 'action_view/helpers/tags/url_field'
- autoload :EmailField, 'action_view/helpers/tags/email_field'
- autoload :NumberField, 'action_view/helpers/tags/number_field'
- autoload :RangeField, 'action_view/helpers/tags/range_field'
- autoload :TextArea, 'action_view/helpers/tags/text_area'
- autoload :CheckBox, 'action_view/helpers/tags/check_box'
- autoload :RadioButton, 'action_view/helpers/tags/radio_button'
- autoload :Select, 'action_view/helpers/tags/select'
- autoload :CollectionSelect, 'action_view/helpers/tags/collection_select'
- autoload :GroupedCollectionSelect, 'action_view/helpers/tags/grouped_collection_select'
- autoload :TimeZoneSelect, 'action_view/helpers/tags/time_zone_select'
- autoload :DateSelect, 'action_view/helpers/tags/date_select'
- autoload :TimeSelect, 'action_view/helpers/tags/time_select'
- autoload :DatetimeSelect, 'action_view/helpers/tags/datetime_select'
+ module Tags #:nodoc:
+ extend ActiveSupport::Autoload
+
+ autoload :Base
+ autoload :Label
+ autoload :TextField
+ autoload :PasswordField
+ autoload :HiddenField
+ autoload :FileField
+ autoload :SearchField
+ autoload :TelField
+ autoload :UrlField
+ autoload :EmailField
+ autoload :NumberField
+ autoload :RangeField
+ autoload :TextArea
+ autoload :CheckBox
+ autoload :RadioButton
+ autoload :Select
+ autoload :CollectionSelect
+ autoload :GroupedCollectionSelect
+ autoload :TimeZoneSelect
+ autoload :DateSelect
+ autoload :TimeSelect
+ autoload :DatetimeSelect
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb
index 24956beb9c..449f94d347 100644
--- a/actionpack/lib/action_view/helpers/tags/base.rb
+++ b/actionpack/lib/action_view/helpers/tags/base.rb
@@ -19,8 +19,9 @@ module ActionView
@auto_index = retrieve_autoindex(Regexp.last_match.pre_match) if Regexp.last_match
end
- def render(&block)
- raise "Abstract Method called"
+ # This is what child classes implement.
+ def render
+ raise NotImplementedError, "Subclasses must implement a render method"
end
private
diff --git a/actionpack/lib/action_view/helpers/tags/date_select.rb b/actionpack/lib/action_view/helpers/tags/date_select.rb
index 5912598ca1..5d706087b0 100644
--- a/actionpack/lib/action_view/helpers/tags/date_select.rb
+++ b/actionpack/lib/action_view/helpers/tags/date_select.rb
@@ -12,10 +12,16 @@ module ActionView
error_wrapping(datetime_selector(@options, @html_options).send("select_#{select_type}").html_safe)
end
+ class << self
+ def select_type
+ @select_type ||= self.name.split("::").last.sub("Select", "").downcase
+ end
+ end
+
private
def select_type
- self.class.name.split("::").last.sub("Select", "").downcase
+ self.class.select_type
end
def datetime_selector(options, html_options)
diff --git a/actionpack/lib/action_view/helpers/tags/select.rb b/actionpack/lib/action_view/helpers/tags/select.rb
index 71fd4d04b7..02b790db4e 100644
--- a/actionpack/lib/action_view/helpers/tags/select.rb
+++ b/actionpack/lib/action_view/helpers/tags/select.rb
@@ -4,6 +4,7 @@ module ActionView
class Select < Base #:nodoc:
def initialize(object_name, method_name, template_object, choices, options, html_options)
@choices = choices
+ @choices = @choices.to_a if @choices.is_a?(Range)
@html_options = html_options
super(object_name, method_name, template_object, options)
diff --git a/actionpack/lib/action_view/helpers/tags/text_field.rb b/actionpack/lib/action_view/helpers/tags/text_field.rb
index 0f81726eb4..ce5182d20f 100644
--- a/actionpack/lib/action_view/helpers/tags/text_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/text_field.rb
@@ -13,10 +13,16 @@ module ActionView
tag("input", options)
end
+ class << self
+ def field_type
+ @field_type ||= self.name.split("::").last.sub("Field", "").downcase
+ end
+ end
+
private
def field_type
- @field_type ||= self.class.name.split("::").last.sub("Field", "").downcase
+ self.class.field_type
end
end
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index ebd1f280a8..d27d49821b 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -327,7 +327,7 @@ module ActionView
method_tag = ''
if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s)
- method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
+ method_tag = method_tag(method)
end
form_method = method.to_s == 'get' ? 'get' : 'post'
@@ -336,10 +336,7 @@ module ActionView
remote = html_options.delete('remote')
- request_token_tag = ''
- if form_method == 'post' && protect_against_forgery?
- request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
- end
+ request_token_tag = form_method == 'post' ? token_tag : ''
url = options.is_a?(String) ? options : self.url_for(options)
name ||= url
@@ -476,7 +473,7 @@ module ActionView
# string given as the value.
# * <tt>:subject</tt> - Preset the subject line of the email.
# * <tt>:body</tt> - Preset the body of the email.
- # * <tt>:cc</tt> - Carbon Copy addition recipients on the email.
+ # * <tt>:cc</tt> - Carbon Copy additional recipients on the email.
# * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
#
# ==== Examples
@@ -670,6 +667,19 @@ module ActionView
bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
html_options
end
+
+ def token_tag(token=nil)
+ if token == false || !protect_against_forgery?
+ ''
+ else
+ token ||= form_authenticity_token
+ tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token)
+ end
+ end
+
+ def method_tag(method)
+ tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
+ end
end
end
end
diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml
index f2a83b92a9..7cca7d969a 100644
--- a/actionpack/lib/action_view/locale/en.yml
+++ b/actionpack/lib/action_view/locale/en.yml
@@ -37,6 +37,7 @@
# precision:
# significant: false
# strip_insignificant_zeros: false
+ format: "%n%"
# Used in number_to_precision()
precision:
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 593eaa2abf..edb3d427d5 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -288,7 +288,7 @@ module ActionView
logger.debug "Backtrace: #{e.backtrace.join("\n")}"
end
- raise ActionView::Template::Error.new(self, {}, e)
+ raise ActionView::Template::Error.new(self, e)
end
end
@@ -297,13 +297,12 @@ module ActionView
e.sub_template_of(self)
raise e
else
- assigns = view.respond_to?(:assigns) ? view.assigns : {}
template = self
unless template.source
template = refresh(view)
template.encode!
end
- raise Template::Error.new(template, assigns, e)
+ raise Template::Error.new(template, e)
end
end
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb
index 83df2604bb..d8258f7b11 100644
--- a/actionpack/lib/action_view/template/error.rb
+++ b/actionpack/lib/action_view/template/error.rb
@@ -55,9 +55,9 @@ module ActionView
attr_reader :original_exception, :backtrace
- def initialize(template, assigns, original_exception)
+ def initialize(template, original_exception)
super(original_exception.message)
- @template, @assigns, @original_exception = template, assigns.dup, original_exception
+ @template, @original_exception = template, original_exception
@sub_templates = nil
@backtrace = original_exception.backtrace
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 0a25d7ba47..b1a5356ddd 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -344,6 +344,21 @@ module ActionDispatch
end
end
+module ActionDispatch
+ module RoutingVerbs
+ def get(uri_or_host, path = nil, port = nil)
+ host = uri_or_host.host unless path
+ path ||= uri_or_host.path
+
+ params = {'PATH_INFO' => path,
+ 'REQUEST_METHOD' => 'GET',
+ 'HTTP_HOST' => host}
+
+ routes.call(params)[2].join
+ end
+ end
+end
+
module RoutingTestHelpers
def url_for(set, options, recall = nil)
set.send(:url_for, options.merge(:only_path => true, :_path_segments => recall))
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index b95a524612..70e03d24ea 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -93,6 +93,12 @@ class ControllerInstanceTests < ActiveSupport::TestCase
Submodule::ContainedNonEmptyController.new]
end
+ def test_performed?
+ assert !@empty.performed?
+ @empty.response_body = ["sweet"]
+ assert @empty.performed?
+ end
+
def test_action_methods
@empty_controllers.each do |c|
assert_equal Set.new, c.class.action_methods, "#{c.controller_path} should be empty!"
diff --git a/actionpack/test/controller/force_ssl_test.rb b/actionpack/test/controller/force_ssl_test.rb
index 125012631e..3ea3c06ac4 100644
--- a/actionpack/test/controller/force_ssl_test.rb
+++ b/actionpack/test/controller/force_ssl_test.rb
@@ -39,10 +39,8 @@ class ForceSSLFlash < ForceSSLController
@flashy = flash["that"]
render :inline => "hello"
end
-
end
-
class ForceSSLControllerLevelTest < ActionController::TestCase
tests ForceSSLControllerLevel
@@ -135,5 +133,4 @@ class ForceSSLFlashTest < ActionController::TestCase
assert_equal "hello", assigns["flash_copy"]["that"]
assert_equal "hello", assigns["flashy"]
end
-
end
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 4a291582d8..e6d3fa74f2 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -1,6 +1,5 @@
require 'abstract_unit'
require 'digest/sha1'
-require 'active_support/core_ext/string/strip'
require "active_support/log_subscriber/test_helper"
# common controller actions
@@ -72,9 +71,7 @@ class CustomAuthenticityParamController < RequestForgeryProtectionController
end
end
-
# common test methods
-
module RequestForgeryProtectionTests
def setup
@token = "cf50faa3fe97702ca1ae"
@@ -246,10 +243,6 @@ class FreeCookieControllerTest < ActionController::TestCase
end
end
-
-
-
-
class CustomAuthenticityParamControllerTest < ActionController::TestCase
def setup
ActionController::Base.request_forgery_protection_token = :custom_token_name
diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb
index 86d6737cbb..9c51db135b 100644
--- a/actionpack/test/controller/rescue_test.rb
+++ b/actionpack/test/controller/rescue_test.rb
@@ -137,11 +137,11 @@ class RescueController < ActionController::Base
end
def io_error_in_view
- raise ActionView::TemplateError.new(nil, {}, IOError.new('this is io error'))
+ raise ActionView::TemplateError.new(nil, IOError.new('this is io error'))
end
def zero_division_error_in_view
- raise ActionView::TemplateError.new(nil, {}, ZeroDivisionError.new('this is zero division error'))
+ raise ActionView::TemplateError.new(nil, ZeroDivisionError.new('this is zero division error'))
end
protected
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index bec9eb16f3..44a40e0665 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -73,23 +73,76 @@ end
class LegacyRouteSetTests < ActiveSupport::TestCase
include RoutingTestHelpers
+ include ActionDispatch::RoutingVerbs
attr_reader :rs
+ alias :routes :rs
def setup
@rs = ::ActionDispatch::Routing::RouteSet.new
@response = nil
end
- def get(uri_or_host, path = nil, port = nil)
- host = uri_or_host.host unless path
- path ||= uri_or_host.path
+ def test_symbols_with_dashes
+ rs.draw do
+ match '/:artist/:song-omg', :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
+
+ hash = JSON.load get(URI('http://example.org/journey/faithfully-omg'))
+ assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash)
+ end
+
+ def test_id_with_dash
+ rs.draw do
+ match '/journey/:id', :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
+
+ hash = JSON.load get(URI('http://example.org/journey/faithfully-omg'))
+ assert_equal({"id"=>"faithfully-omg"}, hash)
+ end
- params = {'PATH_INFO' => path,
- 'REQUEST_METHOD' => 'GET',
- 'HTTP_HOST' => host}
+ def test_dash_with_custom_regexp
+ rs.draw do
+ match '/:artist/:song-omg', :constraints => { :song => /\d+/ }, :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
- @rs.call(params)[2].join
+ hash = JSON.load get(URI('http://example.org/journey/123-omg'))
+ assert_equal({"artist"=>"journey", "song"=>"123"}, hash)
+ assert_equal 'Not Found', get(URI('http://example.org/journey/faithfully-omg'))
+ end
+
+ def test_pre_dash
+ rs.draw do
+ match '/:artist/omg-:song', :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
+
+ hash = JSON.load get(URI('http://example.org/journey/omg-faithfully'))
+ assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash)
+ end
+
+ def test_pre_dash_with_custom_regexp
+ rs.draw do
+ match '/:artist/omg-:song', :constraints => { :song => /\d+/ }, :to => lambda { |env|
+ resp = JSON.dump env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ [200, {}, [resp]]
+ }
+ end
+
+ hash = JSON.load get(URI('http://example.org/journey/omg-123'))
+ assert_equal({"artist"=>"journey", "song"=>"123"}, hash)
+ assert_equal 'Not Found', get(URI('http://example.org/journey/omg-faithfully'))
end
def test_regexp_precidence
@@ -1327,7 +1380,20 @@ class RouteSetTest < ActiveSupport::TestCase
end
end
end
-
+
+ def test_route_with_subdomain_and_constraints_must_receive_params
+ name_param = nil
+ set.draw do
+ match 'page/:name' => 'pages#show', :constraints => lambda {|request|
+ name_param = request.params[:name]
+ return true
+ }
+ end
+ assert_equal({:controller => 'pages', :action => 'show', :name => 'mypage'},
+ set.recognize_path('http://subdomain.example.org/page/mypage'))
+ assert_equal(name_param, 'mypage')
+ end
+
def test_route_requirement_recognize_with_ignore_case
set.draw do
match 'page/:name' => 'pages#show',
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 6ebd02e85c..3e48d97e67 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -245,6 +245,17 @@ class CookiesTest < ActionController::TestCase
assert_cookie_header "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT"
end
+ def test_deleted_cookie_predicate
+ cookies.delete("user_name")
+ assert cookies.deleted?("user_name")
+ assert_equal false, cookies.deleted?("another")
+ end
+
+ def test_deleted_cookie_predicate_with_mismatching_options
+ cookies.delete("user_name", :path => "/path")
+ assert_equal false, cookies.deleted?("user_name", :path => "/different")
+ end
+
def test_cookies_persist_throughout_request
response = get :authenticate
assert response.headers["Set-Cookie"] =~ /user_name=david/
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index c3a565990e..11c292d61a 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -34,7 +34,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
when "/unprocessable_entity"
raise ActionController::InvalidAuthenticityToken
when "/not_found_original_exception"
- raise ActionView::Template::Error.new('template', {}, AbstractController::ActionNotFound.new)
+ raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new)
else
raise "puke!"
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index c6e6ed4d6b..3689b17877 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -1,3 +1,4 @@
+# encoding: UTF-8
require 'erb'
require 'abstract_unit'
require 'controller/fake_controllers'
@@ -156,7 +157,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
resources :posts do
- get :archive, :toggle_view, :on => :collection
+ get :archive, :on => :collection
+ get :toggle_view, :on => :collection
post :preview, :on => :member
resource :subscription
@@ -2543,3 +2545,22 @@ class TestUriPathEscaping < ActionDispatch::IntegrationTest
assert_equal 'a b/c+d', @response.body
end
end
+
+class TestUnicodePaths < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ match "/#{Rack::Utils.escape("ほげ")}" => lambda { |env|
+ path_params = env['action_dispatch.request.path_parameters']
+ [200, { 'Content-Type' => 'text/plain' }, []]
+ }, :as => :unicode_path
+ end
+ end
+
+ include Routes.url_helpers
+ def app; Routes end
+
+ test 'recognizes unicode path' do
+ get "/#{Rack::Utils.escape("ほげ")}"
+ assert_equal "200", @response.code
+ end
+end
diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb
index 4a6d5ddbf7..45f8fc11b3 100644
--- a/actionpack/test/dispatch/show_exceptions_test.rb
+++ b/actionpack/test/dispatch/show_exceptions_test.rb
@@ -11,7 +11,7 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest
when "/method_not_allowed"
raise ActionController::MethodNotAllowed
when "/not_found_original_exception"
- raise ActionView::Template::Error.new('template', {}, AbstractController::ActionNotFound.new)
+ raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new)
else
raise "puke!"
end
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index aa7304b3ed..45a8492d58 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -201,8 +201,8 @@ class AssetTagHelperTest < ActionView::TestCase
%(video_tag("error.avi", "size" => "x")) => %(<video src="/videos/error.avi" />),
%(video_tag("http://media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="http://media.rubyonrails.org/video/rails_blog_2.mov" />),
%(video_tag("//media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="//media.rubyonrails.org/video/rails_blog_2.mov" />),
- %(video_tag(["multiple.ogg", "multiple.avi"])) => %(<video><source src="multiple.ogg" /><source src="multiple.avi" /></video>),
- %(video_tag(["multiple.ogg", "multiple.avi"], :size => "160x120", :controls => true)) => %(<video controls="controls" height="120" width="160"><source src="multiple.ogg" /><source src="multiple.avi" /></video>)
+ %(video_tag(["multiple.ogg", "multiple.avi"])) => %(<video><source src="/videos/multiple.ogg" /><source src="/videos/multiple.avi" /></video>),
+ %(video_tag(["multiple.ogg", "multiple.avi"], :size => "160x120", :controls => true)) => %(<video controls="controls" height="120" width="160"><source src="/videos/multiple.ogg" /><source src="/videos/multiple.avi" /></video>)
}
AudioPathToTag = {
@@ -224,6 +224,8 @@ class AssetTagHelperTest < ActionView::TestCase
%(audio_tag("rss.wav", :autoplay => true, :controls => true)) => %(<audio autoplay="autoplay" controls="controls" src="/audios/rss.wav" />),
%(audio_tag("http://media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="http://media.rubyonrails.org/audio/rails_blog_2.mov" />),
%(audio_tag("//media.rubyonrails.org/audio/rails_blog_2.mov")) => %(<audio src="//media.rubyonrails.org/audio/rails_blog_2.mov" />),
+ %(audio_tag(["audio.mp3", "audio.ogg"])) => %(<audio><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>),
+ %(audio_tag(["audio.mp3", "audio.ogg"], :autobuffer => true, :controls => true)) => %(<audio autobuffer="autobuffer" controls="controls"><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>)
}
def test_auto_discovery_link_tag
diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb
index e3d3d5ff77..ef3d7d97ee 100644
--- a/actionpack/test/template/date_helper_i18n_test.rb
+++ b/actionpack/test/template/date_helper_i18n_test.rb
@@ -118,4 +118,12 @@ class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase
I18n.expects(:translate).with(:'date.order', :locale => 'en').returns [:year, :month, :day]
datetime_select('post', 'updated_at', :locale => 'en')
end
+
+ def test_date_or_time_select_given_invalid_order
+ I18n.expects(:translate).with(:'date.order', :locale => 'en').returns [:invalid, :month, :day]
+
+ assert_raise StandardError do
+ datetime_select('post', 'updated_at', :locale => 'en')
+ end
+ end
end
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index fadfb59572..9e2f4ec347 100644
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -1587,7 +1587,7 @@ class DateHelperTest < ActionView::TestCase
start_year = Time.now.year-5
end_year = Time.now.year+5
- expected = '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i"/>' + "\n"
+ expected = '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i" value="1"/>' + "\n"
expected << %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n}
expected << "<option value=\"\"></option>\n"
start_year.upto(end_year) { |i| expected << %(<option value="#{i}">#{i}</option>\n) }
@@ -1601,6 +1601,40 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, date_select("post", "written_on", :order=>[:year, :month], :include_blank=>true)
end
+ def test_date_select_with_nil_and_blank_and_discard_month
+ @post = Post.new
+
+ start_year = Time.now.year-5
+ end_year = Time.now.year+5
+
+ expected = %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n}
+ expected << "<option value=\"\"></option>\n"
+ start_year.upto(end_year) { |i| expected << %(<option value="#{i}">#{i}</option>\n) }
+ expected << "</select>\n"
+ expected << '<input name="post[written_on(2i)]" type="hidden" id="post_written_on_2i" value="1"/>' + "\n"
+ expected << '<input name="post[written_on(3i)]" type="hidden" id="post_written_on_3i" value="1"/>' + "\n"
+
+ assert_dom_equal expected, date_select("post", "written_on", :discard_month => true, :include_blank=>true)
+ end
+
+ def test_date_select_with_nil_and_blank_and_discard_year
+ @post = Post.new
+
+ expected = '<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="1" />' + "\n"
+
+ expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]">\n}
+ expected << "<option value=\"\"></option>\n"
+ 1.upto(12) { |i| expected << %(<option value="#{i}">#{Date::MONTHNAMES[i]}</option>\n) }
+ expected << "</select>\n"
+
+ expected << %{<select id="post_written_on_3i" name="post[written_on(3i)]">\n}
+ expected << "<option value=\"\"></option>\n"
+ 1.upto(31) { |i| expected << %(<option value="#{i}">#{i}</option>\n) }
+ expected << "</select>\n"
+
+ assert_dom_equal expected, date_select("post", "written_on", :discard_year => true, :include_blank=>true)
+ end
+
def test_date_select_cant_override_discard_hour
@post = Post.new
@post.written_on = Date.new(2004, 6, 15)
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 5be6a2e4e5..39d4768861 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -115,6 +115,14 @@ class FormHelperTest < ActionView::TestCase
super
end
+ class FooTag < ActionView::Helpers::Tags::Base
+ def initialize; end
+ end
+
+ def test_tags_base_child_without_render_method
+ assert_raise(NotImplementedError) { FooTag.new.render }
+ end
+
def test_label
assert_dom_equal('<label for="post_title">Title</label>', label("post", "title"))
assert_dom_equal('<label for="post_title">The title goes here</label>', label("post", "title", "The title goes here"))
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 4a889beadd..a903e13bad 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -144,6 +144,13 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_range_options_for_select
+ assert_dom_equal(
+ "<option value=\"1\">1</option>\n<option value=\"2\">2</option>\n<option value=\"3\">3</option>",
+ options_for_select(1..3)
+ )
+ end
+
def test_array_options_for_string_include_in_other_string_bug_fix
assert_dom_equal(
"<option value=\"ruby\">ruby</option>\n<option value=\"rubyonrails\" selected=\"selected\">rubyonrails</option>",
@@ -671,6 +678,15 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_select_with_range
+ @post = Post.new
+ @post.category = 0
+ assert_dom_equal(
+ "<select id=\"post_category\" name=\"post[category]\"><option value=\"1\">1</option>\n<option value=\"2\">2</option>\n<option value=\"3\">3</option></select>",
+ select("post", "category", 1..3)
+ )
+ end
+
def test_collection_select
@post = Post.new
@post.author_name = "Babe"
diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionpack/test/template/html-scanner/sanitizer_test.rb
index b4d751e405..32c655c5fd 100644
--- a/actionpack/test/template/html-scanner/sanitizer_test.rb
+++ b/actionpack/test/template/html-scanner/sanitizer_test.rb
@@ -56,7 +56,6 @@ class SanitizerTest < ActionController::TestCase
assert_sanitized "a b c<script language=\"Javascript\">blah blah blah</script>d e f", "a b cd e f"
end
- # TODO: Clean up
def test_sanitize_js_handlers
raw = %{onthis="do that" <a href="#" onclick="hello" name="foo" onbogus="remove me">hello</a>}
assert_sanitized raw, %{onthis="do that" <a name="foo" href="#">hello</a>}
@@ -215,7 +214,6 @@ class SanitizerTest < ActionController::TestCase
assert_sanitized img_hack, "<img>"
end
- # TODO: Clean up
def test_should_sanitize_attributes
assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="'&gt;&lt;script&gt;alert()&lt;/script&gt;">blah</span>)
end
diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb
index 8d679aac1d..482d953907 100644
--- a/actionpack/test/template/number_helper_test.rb
+++ b/actionpack/test/template/number_helper_test.rb
@@ -57,6 +57,7 @@ class NumberHelperTest < ActionView::TestCase
assert_equal("1000.000%", number_to_percentage("1000"))
assert_equal("123.4%", number_to_percentage(123.400, :precision => 3, :strip_insignificant_zeros => true))
assert_equal("1.000,000%", number_to_percentage(1000, :delimiter => '.', :separator => ','))
+ assert_equal("1000.000 %", number_to_percentage(1000, :format => "%n %"))
end
def test_number_with_delimiter
@@ -267,6 +268,31 @@ class NumberHelperTest < ActionView::TestCase
assert_nil number_to_human(nil)
end
+ def test_number_helpers_do_not_mutate_options_hash
+ options = { 'raise' => true }
+
+ number_to_phone(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_to_currency(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_to_percentage(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_with_delimiter(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_with_precision(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_to_human_size(1, options)
+ assert_equal({ 'raise' => true }, options)
+
+ number_to_human(1, options)
+ assert_equal({ 'raise' => true }, options)
+ end
+
def test_number_helpers_should_return_non_numeric_param_unchanged
assert_equal("+1-x x 123", number_to_phone("x", :country_code => 1, :extension => 123))
assert_equal("x", number_to_phone("x"))
diff --git a/actionpack/test/template/template_error_test.rb b/actionpack/test/template/template_error_test.rb
index 3a874082d9..91424daeed 100644
--- a/actionpack/test/template/template_error_test.rb
+++ b/actionpack/test/template/template_error_test.rb
@@ -2,12 +2,12 @@ require "abstract_unit"
class TemplateErrorTest < ActiveSupport::TestCase
def test_provides_original_message
- error = ActionView::Template::Error.new("test", {}, Exception.new("original"))
+ error = ActionView::Template::Error.new("test", Exception.new("original"))
assert_equal "original", error.message
end
def test_provides_useful_inspect
- error = ActionView::Template::Error.new("test", {}, Exception.new("original"))
+ error = ActionView::Template::Error.new("test", Exception.new("original"))
assert_equal "#<ActionView::Template::Error: original>", error.inspect
end
end
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index d013a44e6c..cf4dafbac4 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -11,6 +11,9 @@ class UrlHelperTest < ActiveSupport::TestCase
# In those cases, we'll set up a simple mock
attr_accessor :controller, :request
+ cattr_accessor :request_forgery
+ self.request_forgery = false
+
routes = ActionDispatch::Routing::RouteSet.new
routes.draw do
match "/" => "foo#bar"
@@ -49,11 +52,22 @@ class UrlHelperTest < ActiveSupport::TestCase
assert_equal 'javascript:history.back()', url_for(:back)
end
- # todo: missing test cases
+ # TODO: missing test cases
def test_button_to_with_straight_url
assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com")
end
+ def test_button_to_with_straight_url_and_request_forgery
+ self.request_forgery = true
+
+ assert_dom_equal(
+ %{<form method="post" action="http://www.example.com" class="button_to"><div><input type="submit" value="Hello" /><input name="form_token" type="hidden" value="secret" /></div></form>},
+ button_to("Hello", "http://www.example.com")
+ )
+ ensure
+ self.request_forgery = false
+ end
+
def test_button_to_with_form_class
assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"custom-class\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :form_class => 'custom-class')
end
@@ -435,9 +449,16 @@ class UrlHelperTest < ActiveSupport::TestCase
assert mail_to("me@domain.com", "My email", :encode => "hex").html_safe?
end
- # TODO: button_to looks at this ... why?
def protect_against_forgery?
- false
+ self.request_forgery
+ end
+
+ def form_authenticity_token
+ "secret"
+ end
+
+ def request_forgery_protection_token
+ "form_token"
end
private
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index 432f3d4302..52f270ff33 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -325,14 +325,14 @@ module ActiveModel
end
@prefix, @suffix = options[:prefix] || '', options[:suffix] || ''
- @regex = /^(#{Regexp.escape(@prefix)})(.+?)(#{Regexp.escape(@suffix)})$/
+ @regex = /^(?:#{Regexp.escape(@prefix)})(.*)(?:#{Regexp.escape(@suffix)})$/
@method_missing_target = "#{@prefix}attribute#{@suffix}"
@method_name = "#{prefix}%s#{suffix}"
end
def match(method_name)
if @regex =~ method_name
- AttributeMethodMatch.new(method_missing_target, $2, method_name)
+ AttributeMethodMatch.new(method_missing_target, $1, method_name)
else
nil
end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 5cd8f77f0d..023c872055 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -219,7 +219,7 @@ module ActiveModel
# +attribute+.
# If no +message+ is supplied, <tt>:invalid</tt> is assumed.
#
- # If +message+ is a symbol, it will be translated using the appropriate scope (see +translate_error+).
+ # If +message+ is a symbol, it will be translated using the appropriate scope (see +generate_message+).
# If +message+ is a proc, it will be called, allowing for things like <tt>Time.now</tt> to be used within an error.
def add(attribute, message = nil, options = {})
message = normalize_message(attribute, message, options)
diff --git a/activemodel/lib/active_model/observing.rb b/activemodel/lib/active_model/observing.rb
index a8309bf682..32f2aa46bd 100644
--- a/activemodel/lib/active_model/observing.rb
+++ b/activemodel/lib/active_model/observing.rb
@@ -63,7 +63,7 @@ module ActiveModel
# raises an +ArgumentError+ exception.
def add_observer(observer)
unless observer.respond_to? :update
- raise ArgumentError, "observer needs to respond to `update'"
+ raise ArgumentError, "observer needs to respond to 'update'"
end
observer_instances << observer
end
diff --git a/activemodel/test/cases/validations/callbacks_test.rb b/activemodel/test/cases/validations/callbacks_test.rb
index 1cf09758f9..e4f602bd80 100644
--- a/activemodel/test/cases/validations/callbacks_test.rb
+++ b/activemodel/test/cases/validations/callbacks_test.rb
@@ -5,11 +5,10 @@ class Dog
include ActiveModel::Validations
include ActiveModel::Validations::Callbacks
- attr_accessor :name
- attr_writer :history
+ attr_accessor :name, :history
- def history
- @history ||= []
+ def initialize
+ @history = []
end
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index f7de341fbe..a458f9e6e4 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -72,6 +72,33 @@
## Rails 3.2.0 (unreleased) ##
+* Added a `with_lock` method to ActiveRecord objects, which starts
+ a transaction, locks the object (pessimistically) and yields to the block.
+ The method takes one (optional) parameter and passes it to `lock!`.
+
+ Before:
+
+ class Order < ActiveRecord::Base
+ def cancel!
+ transaction do
+ lock!
+ # ... cancelling logic
+ end
+ end
+ end
+
+ After:
+
+ class Order < ActiveRecord::Base
+ def cancel!
+ with_lock do
+ # ... cancelling logic
+ end
+ end
+ end
+
+ *Olek Janiszewski*
+
* 'on' and 'ON' boolean columns values are type casted to true
*Santiago Pastorino*
@@ -82,7 +109,7 @@
Example:
rake db:migrate SCOPE=blog
- *Piotr Sarnacki*
+ *Piotr Sarnacki*
* Migrations copied from engines are now scoped with engine's name,
for example 01_create_posts.blog.rb. *Piotr Sarnacki*
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index f8815fefc9..a1e34a3aa1 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -1,6 +1,5 @@
require 'active_support/core_ext/enumerable'
require 'active_support/deprecation'
-require 'thread'
module ActiveRecord
# = Active Record Attribute Methods
@@ -38,8 +37,6 @@ module ActiveRecord
def define_attribute_methods
# Use a mutex; we don't want two thread simaltaneously trying to define
# attribute methods.
- @attribute_methods_mutex ||= Mutex.new
-
@attribute_methods_mutex.synchronize do
return if attribute_methods_generated?
superclass.define_attribute_methods unless self == base_class
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 964c4123ef..3549cbb090 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -58,66 +58,68 @@ module ActiveRecord
end
protected
- # We want to generate the methods via module_eval rather than define_method,
- # because define_method is slower on dispatch and uses more memory (because it
- # creates a closure).
- #
- # But sometimes the database might return columns with characters that are not
- # allowed in normal method names (like 'my_column(omg)'. So to work around this
- # we first define with the __temp__ identifier, and then use alias method to
- # rename it to what we want.
- def define_method_attribute(attr_name)
- cast_code = attribute_cast_code(attr_name)
-
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def __temp__
- #{internal_attribute_access_code(attr_name, cast_code)}
- end
- alias_method '#{attr_name}', :__temp__
- undef_method :__temp__
- STR
-
- generated_external_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def __temp__(v, attributes, attributes_cache, attr_name)
- #{external_attribute_access_code(attr_name, cast_code)}
- end
- alias_method '#{attr_name}', :__temp__
- undef_method :__temp__
- STR
- end
+ # We want to generate the methods via module_eval rather than define_method,
+ # because define_method is slower on dispatch and uses more memory (because it
+ # creates a closure).
+ #
+ # But sometimes the database might return columns with characters that are not
+ # allowed in normal method names (like 'my_column(omg)'. So to work around this
+ # we first define with the __temp__ identifier, and then use alias method to
+ # rename it to what we want.
+ def define_method_attribute(attr_name)
+ cast_code = attribute_cast_code(attr_name)
+
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
+ def __temp__
+ #{internal_attribute_access_code(attr_name, cast_code)}
+ end
+ alias_method '#{attr_name}', :__temp__
+ undef_method :__temp__
+ STR
- private
- def cacheable_column?(column)
- attribute_types_cached_by_default.include?(column.type)
- end
+ generated_external_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
+ def __temp__(v, attributes, attributes_cache, attr_name)
+ #{external_attribute_access_code(attr_name, cast_code)}
+ end
+ alias_method '#{attr_name}', :__temp__
+ undef_method :__temp__
+ STR
+ end
- def internal_attribute_access_code(attr_name, cast_code)
- access_code = "(v=@attributes[attr_name]) && #{cast_code}"
+ private
+ def cacheable_column?(column)
+ attribute_types_cached_by_default.include?(column.type)
+ end
- unless attr_name == primary_key
- access_code.insert(0, "missing_attribute(attr_name, caller) unless @attributes.has_key?(attr_name); ")
- end
+ def internal_attribute_access_code(attr_name, cast_code)
+ if attr_name == primary_key
+ access_code = "v = @attributes[attr_name];"
+ else
+ access_code = "v = @attributes.fetch(attr_name) { missing_attribute(attr_name, caller) };"
+ end
- if cache_attribute?(attr_name)
- access_code = "@attributes_cache[attr_name] ||= (#{access_code})"
- end
+ access_code << "v && #{cast_code};"
- "attr_name = '#{attr_name}'; #{access_code}"
+ if cache_attribute?(attr_name)
+ access_code = "@attributes_cache[attr_name] ||= (#{access_code})"
end
- def external_attribute_access_code(attr_name, cast_code)
- access_code = "v && #{cast_code}"
+ "attr_name = '#{attr_name}'; #{access_code}"
+ end
- if cache_attribute?(attr_name)
- access_code = "attributes_cache[attr_name] ||= (#{access_code})"
- end
+ def external_attribute_access_code(attr_name, cast_code)
+ access_code = "v && #{cast_code}"
- access_code
+ if cache_attribute?(attr_name)
+ access_code = "attributes_cache[attr_name] ||= (#{access_code})"
end
- def attribute_cast_code(attr_name)
- columns_hash[attr_name].type_cast_code('v')
- end
+ access_code
+ end
+
+ def attribute_cast_code(attr_name)
+ columns_hash[attr_name].type_cast_code('v')
+ end
end
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index f93c7cd74a..44ac37c498 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -71,7 +71,8 @@ module ActiveRecord
when Date, Time then quoted_date(value)
when Symbol then value.to_s
else
- YAML.dump(value)
+ to_type = column ? " to #{column.type}" : ""
+ raise TypeError, "can't cast #{value.class}#{to_type}"
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 560773ca86..201c05d8f5 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -541,7 +541,7 @@ module ActiveRecord
if options.is_a?(Hash) && length = options[:length]
case length
when Hash
- column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name)}
+ column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?}
when Fixnum
column_names.each {|name| option_strings[name] += "(#{length})"}
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index e6ddf8bf8f..dbfb375ba8 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -171,15 +171,15 @@ module ActiveRecord
# Extracts the value from a PostgreSQL column default definition.
def self.extract_value_from_default(default)
+ # This is a performance optimization for Ruby 1.9.2 in development.
+ # If the value is nil, we return nil straight away without checking
+ # the regular expressions. If we check each regular expression,
+ # Regexp#=== will call NilClass#to_str, which will trigger
+ # method_missing (defined by whiny nil in ActiveSupport) which
+ # makes this method very very slow.
+ return default unless default
+
case default
- # This is a performance optimization for Ruby 1.9.2 in development.
- # If the value is nil, we return nil straight away without checking
- # the regular expressions. If we check each regular expression,
- # Regexp#=== will call NilClass#to_str, which will trigger
- # method_missing (defined by whiny nil in ActiveSupport) which
- # makes this method very very slow.
- when NilClass
- nil
# Numeric types
when /\A\(?(-?\d+(\.\d*)?\)?)\z/
$1
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 22574c4ce7..adba3f710c 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -1,4 +1,5 @@
require 'active_support/concern'
+require 'thread'
module ActiveRecord
module Core
@@ -44,10 +45,10 @@ module ActiveRecord
##
# :singleton-method:
- # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling
- # dates and times from the database. This is set to :local by default.
+ # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
+ # dates and times from the database. This is set to :utc by default.
config_attribute :default_timezone, :global => true
- self.default_timezone = :local
+ self.default_timezone = :utc
##
# :singleton-method:
@@ -80,6 +81,8 @@ module ActiveRecord
end
def initialize_generated_modules
+ @attribute_methods_mutex = Mutex.new
+
# force attribute methods to be higher in inheritance hierarchy than other generated methods
generated_attribute_methods
generated_feature_methods
@@ -152,16 +155,8 @@ module ActiveRecord
# User.new({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true)
def initialize(attributes = nil, options = {})
@attributes = self.class.initialize_attributes(self.class.column_defaults.dup)
- @association_cache = {}
- @aggregation_cache = {}
- @attributes_cache = {}
- @new_record = true
- @readonly = false
- @destroyed = false
- @marked_for_destruction = false
- @previously_changed = {}
- @changed_attributes = {}
- @relation = nil
+
+ init_internals
ensure_proper_type
@@ -185,13 +180,11 @@ module ActiveRecord
# post.title # => 'hello world'
def init_with(coder)
@attributes = self.class.initialize_attributes(coder['attributes'])
- @relation = nil
- @attributes_cache, @previously_changed, @changed_attributes = {}, {}, {}
- @association_cache = {}
- @aggregation_cache = {}
- @readonly = @destroyed = @marked_for_destruction = false
+ init_internals
+
@new_record = false
+
run_callbacks :find
run_callbacks :initialize
@@ -219,7 +212,8 @@ module ActiveRecord
@aggregation_cache = {}
@association_cache = {}
- @attributes_cache = {}
+ @attributes_cache = {}
+
@new_record = true
ensure_proper_type
@@ -330,5 +324,18 @@ module ActiveRecord
def to_ary # :nodoc:
nil
end
+
+ def init_internals
+ @relation = nil
+ @aggregation_cache = {}
+ @association_cache = {}
+ @attributes_cache = {}
+ @previously_changed = {}
+ @changed_attributes = {}
+ @readonly = false
+ @destroyed = false
+ @marked_for_destruction = false
+ @new_record = true
+ end
end
end
diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb
index c9c46b8d4f..224f5276eb 100644
--- a/activerecord/lib/active_record/counter_cache.rb
+++ b/activerecord/lib/active_record/counter_cache.rb
@@ -19,12 +19,6 @@ module ActiveRecord
counters.each do |association|
has_many_association = reflect_on_association(association.to_sym)
- expected_name = if has_many_association.options[:as]
- has_many_association.options[:as].to_s.classify
- else
- self.name
- end
-
foreign_key = has_many_association.foreign_key.to_s
child_class = has_many_association.klass
belongs_to = child_class.reflect_on_all_associations(:belongs_to)
diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb
index 66994e4797..58af92f0b1 100644
--- a/activerecord/lib/active_record/locking/pessimistic.rb
+++ b/activerecord/lib/active_record/locking/pessimistic.rb
@@ -38,6 +38,18 @@ module ActiveRecord
# account2.save!
# end
#
+ # You can start a transaction and acquire the lock in one go by calling
+ # <tt>with_lock</tt> with a block. The block is called from within
+ # a transaction, the object is already locked. Example:
+ #
+ # account = Account.first
+ # account.with_lock do
+ # # This block is called within a transaction,
+ # # account is already locked.
+ # account.balance -= 100
+ # account.save!
+ # end
+ #
# Database-specific information on row locking:
# MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
# PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
@@ -50,6 +62,16 @@ module ActiveRecord
reload(:lock => lock) if persisted?
self
end
+
+ # Wraps the passed block in a transaction, locking the object
+ # before yielding. You pass can the SQL locking clause
+ # as argument (see <tt>lock!</tt>).
+ def with_lock(lock = true)
+ transaction do
+ lock!(lock)
+ yield
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index b1c8ae5b77..058dd58efb 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -38,7 +38,8 @@ module ActiveRecord
# first time. Also, make it output to STDERR.
console do |app|
require "active_record/railties/console_sandbox" if app.sandbox?
- ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDERR)
+ console = ActiveSupport::Logger.new(STDERR)
+ Rails.logger.extend ActiveSupport::Logger.broadcast console
end
initializer "active_record.initialize_timezone" do
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 01019db2cc..ac70aeba67 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -496,6 +496,10 @@ module ActiveRecord
to_a.inspect
end
+ def pretty_print(q)
+ q.pp(self.to_a)
+ end
+
def with_default_scope #:nodoc:
if default_scoped? && default_scope = klass.send(:build_default_scope)
default_scope = default_scope.merge(self)
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index b5f202ef6a..a8ae7208fc 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -75,16 +75,16 @@ module ActiveRecord
# array, it actually returns a relation object and can have other query
# methods appended to it, such as the other methods in ActiveRecord::QueryMethods.
#
- # This method will also take multiple parameters:
+ # The argument to the method can also be an array of fields.
#
- # >> Model.select(:field, :other_field, :and_one_more)
+ # >> Model.select([:field, :other_field, :and_one_more])
# => [#<Model field: "value", other_field: "value", and_one_more: "value">]
#
- # Any attributes that do not have fields retrieved by a select
- # will return `nil` when the getter method for that attribute is used:
+ # Accessing attributes of an object that do not have fields retrieved by a select
+ # will throw <tt>ActiveModel::MissingAttributeError</tt>:
#
# >> Model.select(:field).first.other_field
- # => nil
+ # => ActiveModel::MissingAttributeError: missing attribute: other_field
def select(value = Proc.new)
if block_given?
to_a.select {|*block_args| value.call(*block_args) }
diff --git a/activerecord/lib/active_record/test_case.rb b/activerecord/lib/active_record/test_case.rb
index 64ecef2077..86687afdda 100644
--- a/activerecord/lib/active_record/test_case.rb
+++ b/activerecord/lib/active_record/test_case.rb
@@ -1,3 +1,7 @@
+require 'active_support/deprecation'
+require 'active_support/test_case'
+
+ActiveSupport::Deprecation.warn('ActiveRecord::TestCase is deprecated, please use ActiveSupport::TestCase')
module ActiveRecord
# = Active Record Test Case
#
@@ -26,36 +30,5 @@ module ActiveRecord
assert_equal expected.to_s, actual.to_s, message
end
end
-
- def assert_sql(*patterns_to_match)
- ActiveRecord::SQLCounter.log = []
- yield
- ActiveRecord::SQLCounter.log
- ensure
- failed_patterns = []
- patterns_to_match.each do |pattern|
- failed_patterns << pattern unless ActiveRecord::SQLCounter.log.any?{ |sql| pattern === sql }
- end
- assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{ActiveRecord::SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{ActiveRecord::SQLCounter.log.join("\n")}"}"
- end
-
- def assert_queries(num = 1)
- ActiveRecord::SQLCounter.log = []
- yield
- ensure
- assert_equal num, ActiveRecord::SQLCounter.log.size, "#{ActiveRecord::SQLCounter.log.size} instead of #{num} queries were executed.#{ActiveRecord::SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{ActiveRecord::SQLCounter.log.join("\n")}"}"
- end
-
- def assert_no_queries(&block)
- prev_ignored_sql = ActiveRecord::SQLCounter.ignored_sql
- ActiveRecord::SQLCounter.ignored_sql = []
- assert_queries(0, &block)
- ensure
- ActiveRecord::SQLCounter.ignored_sql = prev_ignored_sql
- end
-
- def sqlite3? connection
- connection.class.name.split('::').last == "SQLite3Adapter"
- end
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
index e0152e7ccf..46da1b0a2b 100644
--- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -70,9 +70,9 @@ module ActiveRecord
assert_equal bd.to_f, @conn.type_cast(bd, nil)
end
- def test_type_cast_unknown
+ def test_type_cast_unknown_should_raise_error
obj = Class.new.new
- assert_equal YAML.dump(obj), @conn.type_cast(obj, nil)
+ assert_raise(TypeError) { @conn.type_cast(obj, nil) }
end
def test_quoted_id
diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb
index 0df9ffc0c5..764305459d 100644
--- a/activerecord/test/cases/attribute_methods/read_test.rb
+++ b/activerecord/test/cases/attribute_methods/read_test.rb
@@ -1,5 +1,6 @@
require "cases/helper"
require 'active_support/core_ext/object/inclusion'
+require 'thread'
module ActiveRecord
module AttributeMethods
@@ -20,6 +21,13 @@ module ActiveRecord
include ActiveRecord::AttributeMethods
+ def self.define_attribute_methods
+ # Created in the inherited/included hook for "proper" ARs
+ @attribute_methods_mutex ||= Mutex.new
+
+ super
+ end
+
def self.column_names
%w{ one two three }
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index f5c139e85f..0ea1b824e1 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -187,6 +187,31 @@ class BasicsTest < ActiveRecord::TestCase
end
end
+ def test_previously_changed
+ topic = Topic.find :first
+ topic.title = '<3<3<3'
+ assert_equal({}, topic.previous_changes)
+
+ topic.save!
+ expected = ["The First Topic", "<3<3<3"]
+ assert_equal(expected, topic.previous_changes['title'])
+ end
+
+ def test_previously_changed_dup
+ topic = Topic.find :first
+ topic.title = '<3<3<3'
+ topic.save!
+
+ t2 = topic.dup
+
+ assert_equal(topic.previous_changes, t2.previous_changes)
+
+ topic.title = "lolwut"
+ topic.save!
+
+ assert_not_equal(topic.previous_changes, t2.previous_changes)
+ end
+
def test_preserving_time_objects
assert_kind_of(
Time, Topic.find(1).bonus_time,
@@ -664,7 +689,7 @@ class BasicsTest < ActiveRecord::TestCase
}
topic = Topic.find(1)
topic.attributes = attributes
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
+ assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
end
def test_multiparameter_attributes_on_time_with_no_date
@@ -913,7 +938,7 @@ class BasicsTest < ActiveRecord::TestCase
}
topic = Topic.find(1)
topic.attributes = attributes
- assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
+ assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
end
def test_boolean
@@ -967,10 +992,9 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal "b", duped_topic.title
# test if the attribute values have been duped
- topic.title = {"a" => "b"}
duped_topic = topic.dup
- duped_topic.title["a"] = "c"
- assert_equal "b", topic.title["a"]
+ duped_topic.title.replace "c"
+ assert_equal "a", topic.title
# test if attributes set as part of after_initialize are duped correctly
assert_equal topic.author_email_address, duped_topic.author_email_address
@@ -981,8 +1005,7 @@ class BasicsTest < ActiveRecord::TestCase
assert_not_equal duped_topic.id, topic.id
duped_topic.reload
- # FIXME: I think this is poor behavior, and will fix it with #5686
- assert_equal({'a' => 'c'}.to_yaml, duped_topic.title)
+ assert_equal("c", duped_topic.title)
end
def test_dup_with_aggregate_of_same_name_as_attribute
@@ -1868,7 +1891,7 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal [], NonExistentTable.attribute_names
end
- def test_attribtue_names_on_abstract_class
+ def test_attribute_names_on_abstract_class
assert_equal [], AbstractCompany.attribute_names
end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index d16cccdaea..b4598ab32a 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -6,8 +6,8 @@ require 'minitest/autorun'
require 'stringio'
require 'mocha'
+require 'cases/test_case'
require 'active_record'
-require 'active_record/test_case'
require 'active_support/dependencies'
require 'active_support/logger'
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 0c458d5318..807274ca67 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -388,6 +388,26 @@ unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter) || in_memory_db?
end
end
+ def test_with_lock_commits_transaction
+ person = Person.find 1
+ person.with_lock do
+ person.first_name = 'fooman'
+ person.save!
+ end
+ assert_equal 'fooman', person.reload.first_name
+ end
+
+ def test_with_lock_rolls_back_transaction
+ person = Person.find 1
+ old = person.first_name
+ person.with_lock do
+ person.first_name = 'fooman'
+ person.save!
+ raise 'oops'
+ end rescue nil
+ assert_equal old, person.reload.first_name
+ end
+
if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
def test_no_locks_no_wait
first, second = duel { Person.find 1 }
diff --git a/activerecord/test/cases/migration/index_test.rb b/activerecord/test/cases/migration/index_test.rb
index 26d7aeb148..89cf0f5e93 100644
--- a/activerecord/test/cases/migration/index_test.rb
+++ b/activerecord/test/cases/migration/index_test.rb
@@ -55,7 +55,7 @@ module ActiveRecord
assert_raise(ArgumentError) { connection.remove_index(table_name, "no_such_index") }
end
- def test_add_index_length_limit
+ def test_add_index_name_length_limit
good_index_name = 'x' * connection.index_name_length
too_long_index_name = good_index_name + 'x'
@@ -103,6 +103,12 @@ module ActiveRecord
assert connection.index_exists?(:testings, :foo, :name => "custom_index_name")
end
+ def test_add_index_attribute_length_limit
+ connection.add_index :testings, [:foo, :bar], :length => {:foo => 10, :bar => nil}
+
+ assert connection.index_exists?(:testings, [:foo, :bar])
+ end
+
def test_add_index
connection.add_index("testings", "last_name")
connection.remove_index("testings", "last_name")
diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb
new file mode 100644
index 0000000000..f0fefe6c48
--- /dev/null
+++ b/activerecord/test/cases/test_case.rb
@@ -0,0 +1,63 @@
+require 'active_support/test_case'
+
+module ActiveRecord
+ # = Active Record Test Case
+ #
+ # Defines some test assertions to test against SQL queries.
+ class TestCase < ActiveSupport::TestCase #:nodoc:
+ setup :cleanup_identity_map
+
+ def setup
+ cleanup_identity_map
+ end
+
+ def teardown
+ ActiveRecord::SQLCounter.log.clear
+ end
+
+ def cleanup_identity_map
+ ActiveRecord::IdentityMap.clear
+ end
+
+ def assert_date_from_db(expected, actual, message = nil)
+ # SybaseAdapter doesn't have a separate column type just for dates,
+ # so the time is in the string and incorrectly formatted
+ if current_adapter?(:SybaseAdapter)
+ assert_equal expected.to_s, actual.to_date.to_s, message
+ else
+ assert_equal expected.to_s, actual.to_s, message
+ end
+ end
+
+ def assert_sql(*patterns_to_match)
+ ActiveRecord::SQLCounter.log = []
+ yield
+ ActiveRecord::SQLCounter.log
+ ensure
+ failed_patterns = []
+ patterns_to_match.each do |pattern|
+ failed_patterns << pattern unless ActiveRecord::SQLCounter.log.any?{ |sql| pattern === sql }
+ end
+ assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{ActiveRecord::SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{ActiveRecord::SQLCounter.log.join("\n")}"}"
+ end
+
+ def assert_queries(num = 1)
+ ActiveRecord::SQLCounter.log = []
+ yield
+ ensure
+ assert_equal num, ActiveRecord::SQLCounter.log.size, "#{ActiveRecord::SQLCounter.log.size} instead of #{num} queries were executed.#{ActiveRecord::SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{ActiveRecord::SQLCounter.log.join("\n")}"}"
+ end
+
+ def assert_no_queries(&block)
+ prev_ignored_sql = ActiveRecord::SQLCounter.ignored_sql
+ ActiveRecord::SQLCounter.ignored_sql = []
+ assert_queries(0, &block)
+ ensure
+ ActiveRecord::SQLCounter.ignored_sql = prev_ignored_sql
+ end
+
+ def sqlite3? connection
+ connection.class.name.split('::').last == "SQLite3Adapter"
+ end
+ end
+end
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 548990cb70..c0d51797ee 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -25,29 +25,29 @@ module ActiveResource
#
# == Automated mapping
#
- # Active Resource objects represent your RESTful resources as manipulatable Ruby objects. To map resources
+ # Active Resource objects represent your RESTful resources as manipulatable Ruby objects. To map resources
# to Ruby objects, Active Resource only needs a class name that corresponds to the resource name (e.g., the class
# Person maps to the resources people, very similarly to Active Record) and a +site+ value, which holds the
# URI of the resources.
#
# class Person < ActiveResource::Base
- # self.site = "http://api.people.com:3000/"
+ # self.site = "https://api.people.com"
# end
#
- # Now the Person class is mapped to RESTful resources located at <tt>http://api.people.com:3000/people/</tt>, and
+ # Now the Person class is mapped to RESTful resources located at <tt>https://api.people.com/people/</tt>, and
# you can now use Active Resource's life cycle methods to manipulate resources. In the case where you already have
# an existing model with the same name as the desired RESTful resource you can set the +element_name+ value.
#
# class PersonResource < ActiveResource::Base
- # self.site = "http://api.people.com:3000/"
+ # self.site = "https://api.people.com"
# self.element_name = "person"
# end
#
# If your Active Resource object is required to use an HTTP proxy you can set the +proxy+ value which holds a URI.
#
# class PersonResource < ActiveResource::Base
- # self.site = "http://api.people.com:3000/"
- # self.proxy = "http://user:password@proxy.people.com:8080"
+ # self.site = "https://api.people.com"
+ # self.proxy = "https://user:password@proxy.people.com:8080"
# end
#
#
@@ -103,7 +103,7 @@ module ActiveResource
# You can validate resources client side by overriding validation methods in the base class.
#
# class Person < ActiveResource::Base
- # self.site = "http://api.people.com:3000/"
+ # self.site = "https://api.people.com"
# protected
# def validate
# errors.add("last", "has invalid characters") unless last =~ /[a-zA-Z]*/
@@ -114,47 +114,64 @@ module ActiveResource
#
# == Authentication
#
- # Many REST APIs will require authentication, usually in the form of basic
- # HTTP authentication. Authentication can be specified by:
+ # Many REST APIs require authentication. The HTTP spec describes two ways to
+ # make requests with a username and password (see RFC 2617).
#
- # === HTTP Basic Authentication
- # * putting the credentials in the URL for the +site+ variable.
+ # Basic authentication simply sends a username and password along with HTTP
+ # requests. These sensitive credentials are sent unencrypted, visible to
+ # any onlooker, so this scheme should only be used with SSL.
+ #
+ # Digest authentication sends a crytographic hash of the username, password,
+ # HTTP method, URI, and a single-use secret key provided by the server.
+ # Sensitive credentials aren't visible to onlookers, so digest authentication
+ # doesn't require SSL. However, this doesn't mean the connection is secure!
+ # Just the username and password.
+ #
+ # (You really, really want to use SSL. There's little reason not to.)
+ #
+ # === Picking an authentication scheme
+ #
+ # Basic authentication is the default. To switch to digest authentication,
+ # set +auth_type+ to +:digest+:
#
# class Person < ActiveResource::Base
- # self.site = "http://ryan:password@api.people.com:3000/"
+ # self.auth_type = :digest
# end
#
- # * defining +user+ and/or +password+ variables
+ # === Setting the username and password
+ #
+ # Set +user+ and +password+ on the class, or include them in the +site+ URL.
#
# class Person < ActiveResource::Base
- # self.site = "http://api.people.com:3000/"
+ # # Set user and password directly:
# self.user = "ryan"
# self.password = "password"
- # end
- #
- # For obvious security reasons, it is probably best if such services are available
- # over HTTPS.
#
- # Note: Some values cannot be provided in the URL passed to site. e.g. email addresses
- # as usernames. In those situations you should use the separate user and password option.
+ # # Or include them in the site:
+ # self.site = "https://ryan:password@api.people.com"
+ # end
#
# === Certificate Authentication
#
- # * End point uses an X509 certificate for authentication. <tt>See ssl_options=</tt> for all options.
+ # You can also authenticate using an X509 certificate. <tt>See ssl_options=</tt> for all options.
#
# class Person < ActiveResource::Base
# self.site = "https://secure.api.people.com/"
- # self.ssl_options = {:cert => OpenSSL::X509::Certificate.new(File.open(pem_file))
- # :key => OpenSSL::PKey::RSA.new(File.open(pem_file)),
- # :ca_path => "/path/to/OpenSSL/formatted/CA_Certs",
- # :verify_mode => OpenSSL::SSL::VERIFY_PEER}
+ #
+ # File.open(pem_file_path, 'rb') do |pem_file|
+ # self.ssl_options = {
+ # cert: OpenSSL::X509::Certificate.new(pem_file),
+ # key: OpenSSL::PKey::RSA.new(pem_file),
+ # ca_path: "/path/to/OpenSSL/formatted/CA_Certs",
+ # verify_mode: OpenSSL::SSL::VERIFY_PEER }
+ # end
# end
#
#
# == Errors & Validation
#
# Error handling and validation is handled in much the same manner as you're used to seeing in
- # Active Record. Both the response code in the HTTP response and the body of the response are used to
+ # Active Record. Both the response code in the HTTP response and the body of the response are used to
# indicate that an error occurred.
#
# === Resource errors
@@ -163,7 +180,7 @@ module ActiveResource
# response code will be returned from the server which will raise an ActiveResource::ResourceNotFound
# exception.
#
- # # GET http://api.people.com:3000/people/999.json
+ # # GET https://api.people.com/people/999.json
# ryan = Person.find(999) # 404, raises ActiveResource::ResourceNotFound
#
#
@@ -185,7 +202,7 @@ module ActiveResource
# * Other - ActiveResource::ConnectionError
#
# These custom exceptions allow you to deal with resource errors more naturally and with more precision
- # rather than returning a general HTTP error. For example:
+ # rather than returning a general HTTP error. For example:
#
# begin
# ryan = Person.find(my_id)
@@ -199,7 +216,7 @@ module ActiveResource
# an ActiveResource::MissingPrefixParam will be raised.
#
# class Comment < ActiveResource::Base
- # self.site = "http://someip.com/posts/:post_id/"
+ # self.site = "https://someip.com/posts/:post_id"
# end
#
# Comment.find(1)
@@ -208,8 +225,8 @@ module ActiveResource
# === Validation errors
#
# Active Resource supports validations on resources and will return errors if any of these validations fail
- # (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by
- # a response code of <tt>422</tt> and an XML or JSON representation of the validation errors. The save operation will
+ # (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by
+ # a response code of <tt>422</tt> and an XML or JSON representation of the validation errors. The save operation will
# then fail (with a <tt>false</tt> return value) and the validation errors can be accessed on the resource in question.
#
# ryan = Person.find(1)
@@ -217,9 +234,9 @@ module ActiveResource
# ryan.save # => false
#
# # When
- # # PUT http://api.people.com:3000/people/1.json
+ # # PUT https://api.people.com/people/1.json
# # or
- # # PUT http://api.people.com:3000/people/1.json
+ # # PUT https://api.people.com/people/1.json
# # is requested with invalid values, the response is:
# #
# # Response (422):
@@ -240,7 +257,7 @@ module ActiveResource
# amount of time before Active Resource times out with the +timeout+ variable.
#
# class Person < ActiveResource::Base
- # self.site = "http://api.people.com:3000/"
+ # self.site = "https://api.people.com"
# self.timeout = 5
# end
#
@@ -383,22 +400,22 @@ module ActiveResource
@known_attributes ||= []
end
- # Gets the URI of the REST resources to map for this class. The site variable is required for
+ # Gets the URI of the REST resources to map for this class. The site variable is required for
# Active Resource's mapping to work.
def site
# Not using superclass_delegating_reader because don't want subclasses to modify superclass instance
#
# With superclass_delegating_reader
#
- # Parent.site = 'http://anonymous@test.com'
- # Subclass.site # => 'http://anonymous@test.com'
+ # Parent.site = 'https://anonymous@test.com'
+ # Subclass.site # => 'https://anonymous@test.com'
# Subclass.site.user = 'david'
- # Parent.site # => 'http://david@test.com'
+ # Parent.site # => 'https://david@test.com'
#
# Without superclass_delegating_reader (expected behavior)
#
- # Parent.site = 'http://anonymous@test.com'
- # Subclass.site # => 'http://anonymous@test.com'
+ # Parent.site = 'https://anonymous@test.com'
+ # Subclass.site # => 'https://anonymous@test.com'
# Subclass.site.user = 'david' # => TypeError: can't modify frozen object
#
if defined?(@site)
@@ -592,7 +609,7 @@ module ActiveResource
prefix(options)
end
- # An attribute reader for the source string for the resource path \prefix. This
+ # An attribute reader for the source string for the resource path \prefix. This
# method is regenerated at runtime based on what the \prefix is set to.
def prefix_source
prefix # generate #prefix and #prefix_source methods first
@@ -625,7 +642,7 @@ module ActiveResource
alias_method :set_element_name, :element_name= #:nodoc:
alias_method :set_collection_name, :collection_name= #:nodoc:
- # Gets the element path for the given ID in +id+. If the +query_options+ parameter is omitted, Rails
+ # Gets the element path for the given ID in +id+. If the +query_options+ parameter is omitted, Rails
# will split from the \prefix options.
#
# ==== Options
@@ -638,7 +655,7 @@ module ActiveResource
# # => /posts/1.json
#
# class Comment < ActiveResource::Base
- # self.site = "http://37s.sunrise.i/posts/:post_id/"
+ # self.site = "https://37s.sunrise.com/posts/:post_id"
# end
#
# Comment.element_path(1, :post_id => 5)
@@ -668,7 +685,7 @@ module ActiveResource
# # => /posts/new.json
#
# class Comment < ActiveResource::Base
- # self.site = "http://37s.sunrise.i/posts/:post_id/"
+ # self.site = "https://37s.sunrise.com/posts/:post_id"
# end
#
# Comment.collection_path(:post_id => 5)
@@ -677,7 +694,7 @@ module ActiveResource
"#{prefix(prefix_options)}#{collection_name}/new.#{format.extension}"
end
- # Gets the collection path for the REST resources. If the +query_options+ parameter is omitted, Rails
+ # Gets the collection path for the REST resources. If the +query_options+ parameter is omitted, Rails
# will split from the +prefix_options+.
#
# ==== Options
@@ -725,8 +742,8 @@ module ActiveResource
# ryan = Person.new(:first => 'ryan')
# ryan.save
#
- # Returns the newly created resource. If a failure has occurred an
- # exception will be raised (see <tt>save</tt>). If the resource is invalid and
+ # Returns the newly created resource. If a failure has occurred an
+ # exception will be raised (see <tt>save</tt>). If the resource is invalid and
# has not been saved then <tt>valid?</tt> will return <tt>false</tt>,
# while <tt>new?</tt> will still return <tt>true</tt>.
#
@@ -747,11 +764,11 @@ module ActiveResource
self.new(attributes).tap { |resource| resource.save }
end
- # Core method for finding resources. Used similarly to Active Record's +find+ method.
+ # Core method for finding resources. Used similarly to Active Record's +find+ method.
#
# ==== Arguments
- # The first argument is considered to be the scope of the query. That is, how many
- # resources are returned from the request. It can be one of the following.
+ # The first argument is considered to be the scope of the query. That is, how many
+ # resources are returned from the request. It can be one of the following.
#
# * <tt>:one</tt> - Returns a single resource.
# * <tt>:first</tt> - Returns the first resource found.
@@ -834,7 +851,7 @@ module ActiveResource
find(:last, *args)
end
- # This is an alias for find(:all). You can pass in all the same
+ # This is an alias for find(:all). You can pass in all the same
# arguments to this method as you can to <tt>find(:all)</tt>
def all(*args)
find(:all, *args)
@@ -939,12 +956,12 @@ module ActiveResource
# Accepts a URI and creates the site URI from that.
def create_site_uri_from(site)
- site.is_a?(URI) ? site.dup : URI.parser.parse(site)
+ site.is_a?(URI) ? site.dup : URI.parse(site)
end
# Accepts a URI and creates the proxy URI from that.
def create_proxy_uri_from(proxy)
- proxy.is_a?(URI) ? proxy.dup : URI.parser.parse(proxy)
+ proxy.is_a?(URI) ? proxy.dup : URI.parse(proxy)
end
# contains a set of the current prefix parameters.
@@ -1015,7 +1032,7 @@ module ActiveResource
# not_ryan.new? # => true
#
# Any active resource member attributes will NOT be cloned, though all other
- # attributes are. This is to prevent the conflict between any +prefix_options+
+ # attributes are. This is to prevent the conflict between any +prefix_options+
# that refer to the original parent resource and the newly cloned parent
# resource that does not exist.
#
@@ -1031,7 +1048,7 @@ module ActiveResource
# Clone all attributes except the pk and any nested ARes
cloned = Hash[attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.map { |k, v| [k, v.clone] }]
# Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
- # attempts to convert hashes into member objects and arrays into collections of objects. We want
+ # attempts to convert hashes into member objects and arrays into collections of objects. We want
# the raw objects to be cloned so we bypass load by directly setting the attributes hash.
resource = self.class.new({})
resource.prefix_options = self.prefix_options
@@ -1083,7 +1100,7 @@ module ActiveResource
attributes[self.class.primary_key] = id
end
- # Test for equality. Resource are equal if and only if +other+ is the same object or
+ # Test for equality. Resource are equal if and only if +other+ is the same object or
# is an instance of the same class, is not <tt>new?</tt>, and has the same +id+.
#
# ==== Examples
@@ -1139,7 +1156,7 @@ module ActiveResource
end
end
- # Saves (+POST+) or \updates (+PUT+) a resource. Delegates to +create+ if the object is \new,
+ # Saves (+POST+) or \updates (+PUT+) a resource. Delegates to +create+ if the object is \new,
# +update+ if it exists. If the response to the \save includes a body, it will be assumed that this body
# is Json for the final object as it looked after the \save (which would include attributes like +created_at+
# that weren't part of the original submit).
@@ -1190,7 +1207,7 @@ module ActiveResource
end
# Evaluates to <tt>true</tt> if this resource is not <tt>new?</tt> and is
- # found on the remote service. Using this method, you can check for
+ # found on the remote service. Using this method, you can check for
# resources that may have been deleted between the object's instantiation
# and actions on it.
#
@@ -1232,7 +1249,7 @@ module ActiveResource
end
# A method to manually load attributes from a \hash. Recursively loads collections of
- # resources. This method is called in +initialize+ and +create+ when a \hash of attributes
+ # resources. This method is called in +initialize+ and +create+ when a \hash of attributes
# is provided.
#
# ==== Examples
@@ -1289,12 +1306,12 @@ module ActiveResource
#
# Note: Unlike ActiveRecord::Base.update_attribute, this method <b>is</b>
# subject to normal validation routines as an update sends the whole body
- # of the resource in the request. (See Validations).
+ # of the resource in the request. (See Validations).
#
# As such, this method is equivalent to calling update_attributes with a single attribute/value pair.
#
# If the saving fails because of a connection or remote service error, an
- # exception will be raised. If saving fails because the resource is
+ # exception will be raised. If saving fails because the resource is
# invalid then <tt>false</tt> will be returned.
def update_attribute(name, value)
self.send("#{name}=".to_sym, value)
@@ -1305,7 +1322,7 @@ module ActiveResource
# and requests that the record be saved.
#
# If the saving fails because of a connection or remote service error, an
- # exception will be raised. If saving fails because the resource is
+ # exception will be raised. If saving fails because the resource is
# invalid then <tt>false</tt> will be returned.
#
# Note: Though this request can be made with a partial set of the
diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb
index 94839c8c25..46060b6f74 100644
--- a/activeresource/lib/active_resource/connection.rb
+++ b/activeresource/lib/active_resource/connection.rb
@@ -39,14 +39,14 @@ module ActiveResource
# Set URI for remote service.
def site=(site)
- @site = site.is_a?(URI) ? site : URI.parser.parse(site)
+ @site = site.is_a?(URI) ? site : URI.parse(site)
@user = URI.parser.unescape(@site.user) if @site.user
@password = URI.parser.unescape(@site.password) if @site.password
end
# Set the proxy for remote service.
def proxy=(proxy)
- @proxy = proxy.is_a?(URI) ? proxy : URI.parser.parse(proxy)
+ @proxy = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
end
# Sets the user for remote service.
@@ -166,38 +166,28 @@ module ActiveResource
end
def configure_http(http)
- http = apply_ssl_options(http)
-
- # Net::HTTP timeouts default to 60 seconds.
- if @timeout
- http.open_timeout = @timeout
- http.read_timeout = @timeout
+ apply_ssl_options(http).tap do |https|
+ # Net::HTTP timeouts default to 60 seconds.
+ if defined? @timeout
+ https.open_timeout = @timeout
+ https.read_timeout = @timeout
+ end
end
-
- http
end
def apply_ssl_options(http)
- return http unless @site.is_a?(URI::HTTPS)
-
- http.use_ssl = true
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
- return http unless defined?(@ssl_options)
-
- http.ca_path = @ssl_options[:ca_path] if @ssl_options[:ca_path]
- http.ca_file = @ssl_options[:ca_file] if @ssl_options[:ca_file]
+ http.tap do |https|
+ # Skip config if site is already a https:// URI.
+ if defined? @ssl_options
+ http.use_ssl = true
- http.cert = @ssl_options[:cert] if @ssl_options[:cert]
- http.key = @ssl_options[:key] if @ssl_options[:key]
+ # Default to no cert verification (WTF? FIXME)
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
- http.cert_store = @ssl_options[:cert_store] if @ssl_options[:cert_store]
- http.ssl_timeout = @ssl_options[:ssl_timeout] if @ssl_options[:ssl_timeout]
-
- http.verify_mode = @ssl_options[:verify_mode] if @ssl_options[:verify_mode]
- http.verify_callback = @ssl_options[:verify_callback] if @ssl_options[:verify_callback]
- http.verify_depth = @ssl_options[:verify_depth] if @ssl_options[:verify_depth]
-
- http
+ # All the SSL options have corresponding http settings.
+ @ssl_options.each { |key, value| http.send "#{key}=", value }
+ end
+ end
end
def default_header
diff --git a/activeresource/lib/active_resource/custom_methods.rb b/activeresource/lib/active_resource/custom_methods.rb
index 2a651dd48e..a0eb28ed13 100644
--- a/activeresource/lib/active_resource/custom_methods.rb
+++ b/activeresource/lib/active_resource/custom_methods.rb
@@ -2,7 +2,7 @@ require 'active_support/core_ext/object/blank'
module ActiveResource
# A module to support custom REST methods and sub-resources, allowing you to break out
- # of the "default" REST methods with your own custom resource requests. For example,
+ # of the "default" REST methods with your own custom resource requests. For example,
# say you use Rails to expose a REST service and configure your routes with:
#
# map.resources :people, :new => { :register => :post },
@@ -20,7 +20,7 @@ module ActiveResource
# standard methods.
#
# class Person < ActiveResource::Base
- # self.site = "http://37s.sunrise.i:3000"
+ # self.site = "https://37s.sunrise.com"
# end
#
# Person.new(:name => 'Ryan').post(:register) # POST /people/new/register.json
diff --git a/activeresource/lib/active_resource/http_mock.rb b/activeresource/lib/active_resource/http_mock.rb
index 36f52d61d3..666b961f87 100644
--- a/activeresource/lib/active_resource/http_mock.rb
+++ b/activeresource/lib/active_resource/http_mock.rb
@@ -4,7 +4,7 @@ require 'active_support/core_ext/object/inclusion'
module ActiveResource
class InvalidRequestError < StandardError; end #:nodoc:
- # One thing that has always been a pain with remote web services is testing. The HttpMock
+ # One thing that has always been a pain with remote web services is testing. The HttpMock
# class makes it easy to test your Active Resource models by creating a set of mock responses to specific
# requests.
#
@@ -15,17 +15,17 @@ module ActiveResource
#
# mock.http_method(path, request_headers = {}, body = nil, status = 200, response_headers = {})
#
- # * <tt>http_method</tt> - The HTTP method to listen for. This can be +get+, +post+, +put+, +delete+ or
+ # * <tt>http_method</tt> - The HTTP method to listen for. This can be +get+, +post+, +put+, +delete+ or
# +head+.
# * <tt>path</tt> - A string, starting with a "/", defining the URI that is expected to be
# called.
- # * <tt>request_headers</tt> - Headers that are expected along with the request. This argument uses a
- # hash format, such as <tt>{ "Content-Type" => "application/json" }</tt>. This mock will only trigger
+ # * <tt>request_headers</tt> - Headers that are expected along with the request. This argument uses a
+ # hash format, such as <tt>{ "Content-Type" => "application/json" }</tt>. This mock will only trigger
# if your tests sends a request with identical headers.
- # * <tt>body</tt> - The data to be returned. This should be a string of Active Resource parseable content,
+ # * <tt>body</tt> - The data to be returned. This should be a string of Active Resource parseable content,
# such as Json.
# * <tt>status</tt> - The HTTP response code, as an integer, to return with the response.
- # * <tt>response_headers</tt> - Headers to be returned with the response. Uses the same hash format as
+ # * <tt>response_headers</tt> - Headers to be returned with the response. Uses the same hash format as
# <tt>request_headers</tt> listed above.
#
# In order for a mock to deliver its content, the incoming request must match by the <tt>http_method</tt>,
@@ -291,12 +291,9 @@ module ActiveResource
if resp_cls && !resp_cls.body_permitted?
@body = nil
end
-
- if @body.nil?
- self['Content-Length'] = "0"
- else
- self['Content-Length'] = body.size.to_s
- end
+
+ self['Content-Length'] = @body.nil? ? "0" : body.size.to_s
+
end
# Returns true if code is 2xx,
diff --git a/activeresource/lib/active_resource/validations.rb b/activeresource/lib/active_resource/validations.rb
index ca265d053e..a63f02cb57 100644
--- a/activeresource/lib/active_resource/validations.rb
+++ b/activeresource/lib/active_resource/validations.rb
@@ -41,7 +41,7 @@ module ActiveResource
# Module to support validation and errors with Active Resource objects. The module overrides
# Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned
# in the web service response. The module also adds an +errors+ collection that mimics the interface
- # of the errors provided by ActiveRecord::Errors.
+ # of the errors provided by ActiveModel::Errors.
#
# ==== Example
#
diff --git a/activeresource/test/cases/authorization_test.rb b/activeresource/test/cases/authorization_test.rb
index 0185e5432d..fbfe086599 100644
--- a/activeresource/test/cases/authorization_test.rb
+++ b/activeresource/test/cases/authorization_test.rb
@@ -9,8 +9,18 @@ class AuthorizationTest < ActiveSupport::TestCase
@david = { :person => { :id => 2, :name => 'David' } }.to_json
@authenticated_conn = ActiveResource::Connection.new("http://david:test123@localhost")
@basic_authorization_request_header = { 'Authorization' => 'Basic ZGF2aWQ6dGVzdDEyMw==' }
+ end
- @nonce = "MTI0OTUxMzc4NzpjYWI3NDM3NDNmY2JmODU4ZjQ2ZjcwNGZkMTJiMjE0NA=="
+ private
+ def decode(response)
+ @authenticated_conn.format.decode(response.body)
+ end
+end
+
+class BasicAuthorizationTest < AuthorizationTest
+ def setup
+ super
+ @authenticated_conn.auth_type = :basic
ActiveResource::HttpMock.respond_to do |mock|
mock.get "/people/2.json", @basic_authorization_request_header, @david
@@ -19,34 +29,48 @@ class AuthorizationTest < ActiveSupport::TestCase
mock.delete "/people/2.json", @basic_authorization_request_header, nil, 200
mock.post "/people/2/addresses.json", @basic_authorization_request_header, nil, 201, 'Location' => '/people/1/addresses/5'
mock.head "/people/2.json", @basic_authorization_request_header, nil, 200
+ end
+ end
- mock.get "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "fad396f6a34aeba28e28b9b96ddbb671") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
- mock.get "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "c064d5ba8891a25290c76c8c7d31fb7b") }, @david, 200
- mock.get "/people/1.json", { 'Authorization' => request_digest_auth_header("/people/1.json", "f9c0b594257bb8422af4abd429c5bb70") }, @matz, 200
+ def test_get
+ david = decode(@authenticated_conn.get("/people/2.json"))
+ assert_equal "David", david["name"]
+ end
- mock.put "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "50a685d814f94665b9d160fbbaa3958a") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
- mock.put "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "5a75cde841122d8e0f20f8fd1f98a743") }, nil, 204
+ def test_post
+ response = @authenticated_conn.post("/people/2/addresses.json")
+ assert_equal "/people/1/addresses/5", response["Location"]
+ end
- mock.delete "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "846f799107eab5ca4285b909ee299a33") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
- mock.delete "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "9f5b155224edbbb69fd99d8ce094681e") }, nil, 200
+ def test_put
+ response = @authenticated_conn.put("/people/2.json")
+ assert_equal 204, response.code
+ end
- mock.post "/people/2/addresses.json", { 'Authorization' => blank_digest_auth_header("/people/2/addresses.json", "6984d405ff3d9ed07bbf747dcf16afb0") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
- mock.post "/people/2/addresses.json", { 'Authorization' => request_digest_auth_header("/people/2/addresses.json", "4bda6a28dbf930b5af9244073623bd04") }, nil, 201, 'Location' => '/people/1/addresses/5'
+ def test_delete
+ response = @authenticated_conn.delete("/people/2.json")
+ assert_equal 200, response.code
+ end
- mock.head "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "15e5ed84ba5c4cfcd5c98a36c2e4f421") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
- mock.head "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "d4c6d2bcc8717abb2e2ccb8c49ee6a91") }, nil, 200
- end
+ def test_head
+ response = @authenticated_conn.head("/people/2.json")
+ assert_equal 200, response.code
+ end
- # Make client nonce deterministic
- class << @authenticated_conn
- private
+ def test_retry_on_401_doesnt_happen_with_basic_auth
+ assert_raise(ActiveResource::UnauthorizedAccess) { @authenticated_conn.get("/people/1.json") }
+ assert_equal "", @authenticated_conn.send(:response_auth_header)
+ end
- def client_nonce
- 'i-am-a-client-nonce'
- end
- end
+ def test_raises_invalid_request_on_unauthorized_requests
+ assert_raise(ActiveResource::InvalidRequestError) { @conn.get("/people/2.json") }
+ assert_raise(ActiveResource::InvalidRequestError) { @conn.post("/people/2/addresses.json") }
+ assert_raise(ActiveResource::InvalidRequestError) { @conn.put("/people/2.json") }
+ assert_raise(ActiveResource::InvalidRequestError) { @conn.delete("/people/2.json") }
+ assert_raise(ActiveResource::InvalidRequestError) { @conn.head("/people/2.json") }
end
+
def test_authorization_header
authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
assert_equal @basic_authorization_request_header['Authorization'], authorization_header['Authorization']
@@ -116,7 +140,6 @@ class AuthorizationTest < ActiveSupport::TestCase
end
def test_authorization_header_if_credentials_supplied_and_auth_type_is_basic
- @authenticated_conn.auth_type = :basic
authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
assert_equal @basic_authorization_request_header['Authorization'], authorization_header['Authorization']
authorization = authorization_header["Authorization"].to_s.split
@@ -125,76 +148,77 @@ class AuthorizationTest < ActiveSupport::TestCase
assert_equal ["david", "test123"], ::Base64.decode64(authorization[1]).split(":")[0..1]
end
- def test_authorization_header_if_credentials_supplied_and_auth_type_is_digest
- @authenticated_conn.auth_type = :digest
- authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
- assert_equal blank_digest_auth_header("/people/2.json", "fad396f6a34aeba28e28b9b96ddbb671"), authorization_header['Authorization']
+ def test_client_nonce_is_not_nil
+ assert_not_nil ActiveResource::Connection.new("http://david:test123@localhost").send(:client_nonce)
end
+end
- def test_authorization_header_with_query_string_if_auth_type_is_digest
+class DigestAuthorizationTest < AuthorizationTest
+ def setup
+ super
@authenticated_conn.auth_type = :digest
- authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json?only=name'))
- assert_equal blank_digest_auth_header("/people/2.json?only=name", "f8457b0b5d21b6b80737a386217afb24"), authorization_header['Authorization']
- end
- def test_get
- david = decode(@authenticated_conn.get("/people/2.json"))
- assert_equal "David", david["name"]
- end
+ # Make client nonce deterministic
+ def @authenticated_conn.client_nonce; 'i-am-a-client-nonce' end
- def test_post
- response = @authenticated_conn.post("/people/2/addresses.json")
- assert_equal "/people/1/addresses/5", response["Location"]
- end
+ @nonce = "MTI0OTUxMzc4NzpjYWI3NDM3NDNmY2JmODU4ZjQ2ZjcwNGZkMTJiMjE0NA=="
- def test_put
- response = @authenticated_conn.put("/people/2.json")
- assert_equal 204, response.code
+ ActiveResource::HttpMock.respond_to do |mock|
+ mock.get "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "fad396f6a34aeba28e28b9b96ddbb671") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
+ mock.get "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "c064d5ba8891a25290c76c8c7d31fb7b") }, @david, 200
+ mock.get "/people/1.json", { 'Authorization' => request_digest_auth_header("/people/1.json", "f9c0b594257bb8422af4abd429c5bb70") }, @matz, 200
+
+ mock.put "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "50a685d814f94665b9d160fbbaa3958a") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
+ mock.put "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "5a75cde841122d8e0f20f8fd1f98a743") }, nil, 204
+
+ mock.delete "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "846f799107eab5ca4285b909ee299a33") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
+ mock.delete "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "9f5b155224edbbb69fd99d8ce094681e") }, nil, 200
+
+ mock.post "/people/2/addresses.json", { 'Authorization' => blank_digest_auth_header("/people/2/addresses.json", "6984d405ff3d9ed07bbf747dcf16afb0") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
+ mock.post "/people/2/addresses.json", { 'Authorization' => request_digest_auth_header("/people/2/addresses.json", "4bda6a28dbf930b5af9244073623bd04") }, nil, 201, 'Location' => '/people/1/addresses/5'
+
+ mock.head "/people/2.json", { 'Authorization' => blank_digest_auth_header("/people/2.json", "15e5ed84ba5c4cfcd5c98a36c2e4f421") }, nil, 401, { 'WWW-Authenticate' => response_digest_auth_header }
+ mock.head "/people/2.json", { 'Authorization' => request_digest_auth_header("/people/2.json", "d4c6d2bcc8717abb2e2ccb8c49ee6a91") }, nil, 200
+ end
end
- def test_delete
- response = @authenticated_conn.delete("/people/2.json")
- assert_equal 200, response.code
+ def test_authorization_header_if_credentials_supplied_and_auth_type_is_digest
+ authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json'))
+ assert_equal blank_digest_auth_header("/people/2.json", "fad396f6a34aeba28e28b9b96ddbb671"), authorization_header['Authorization']
end
- def test_head
- response = @authenticated_conn.head("/people/2.json")
- assert_equal 200, response.code
+ def test_authorization_header_with_query_string_if_auth_type_is_digest
+ authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json?only=name'))
+ assert_equal blank_digest_auth_header("/people/2.json?only=name", "f8457b0b5d21b6b80737a386217afb24"), authorization_header['Authorization']
end
def test_get_with_digest_auth_handles_initial_401_response_and_retries
- @authenticated_conn.auth_type = :digest
response = @authenticated_conn.get("/people/2.json")
assert_equal "David", decode(response)["name"]
end
def test_post_with_digest_auth_handles_initial_401_response_and_retries
- @authenticated_conn.auth_type = :digest
response = @authenticated_conn.post("/people/2/addresses.json")
assert_equal "/people/1/addresses/5", response["Location"]
assert_equal 201, response.code
end
def test_put_with_digest_auth_handles_initial_401_response_and_retries
- @authenticated_conn.auth_type = :digest
- response = @authenticated_conn.put("/people/2.json")
- assert_equal 204, response.code
+ response = @authenticated_conn.put("/people/2.json")
+ assert_equal 204, response.code
end
def test_delete_with_digest_auth_handles_initial_401_response_and_retries
- @authenticated_conn.auth_type = :digest
response = @authenticated_conn.delete("/people/2.json")
assert_equal 200, response.code
end
def test_head_with_digest_auth_handles_initial_401_response_and_retries
- @authenticated_conn.auth_type = :digest
response = @authenticated_conn.head("/people/2.json")
assert_equal 200, response.code
end
def test_get_with_digest_auth_caches_nonce
- @authenticated_conn.auth_type = :digest
response = @authenticated_conn.get("/people/2.json")
assert_equal "David", decode(response)["name"]
@@ -203,19 +227,6 @@ class AuthorizationTest < ActiveSupport::TestCase
assert_equal "Matz", decode(response)["name"]
end
- def test_retry_on_401_only_happens_with_digest_auth
- assert_raise(ActiveResource::UnauthorizedAccess) { @authenticated_conn.get("/people/1.json") }
- assert_equal "", @authenticated_conn.send(:response_auth_header)
- end
-
- def test_raises_invalid_request_on_unauthorized_requests
- assert_raise(ActiveResource::InvalidRequestError) { @conn.get("/people/2.json") }
- assert_raise(ActiveResource::InvalidRequestError) { @conn.post("/people/2/addresses.json") }
- assert_raise(ActiveResource::InvalidRequestError) { @conn.put("/people/2.json") }
- assert_raise(ActiveResource::InvalidRequestError) { @conn.delete("/people/2.json") }
- assert_raise(ActiveResource::InvalidRequestError) { @conn.head("/people/2.json") }
- end
-
def test_raises_invalid_request_on_unauthorized_requests_with_digest_auth
@conn.auth_type = :digest
assert_raise(ActiveResource::InvalidRequestError) { @conn.get("/people/2.json") }
@@ -225,17 +236,7 @@ class AuthorizationTest < ActiveSupport::TestCase
assert_raise(ActiveResource::InvalidRequestError) { @conn.head("/people/2.json") }
end
- def test_client_nonce_is_not_nil
- assert_not_nil ActiveResource::Connection.new("http://david:test123@localhost").send(:client_nonce)
- end
-
- protected
- def assert_response_raises(klass, code)
- assert_raise(klass, "Expected response code #{code} to raise #{klass}") do
- @conn.__send__(:handle_response, Response.new(code))
- end
- end
-
+ private
def blank_digest_auth_header(uri, response)
%Q(Digest username="david", realm="", qop="", uri="#{uri}", nonce="", nc="0", cnonce="i-am-a-client-nonce", opaque="", response="#{response}")
end
@@ -247,8 +248,4 @@ class AuthorizationTest < ActiveSupport::TestCase
def response_digest_auth_header
%Q(Digest realm="RailsTestApp", qop="auth", algorithm=MD5, nonce="#{@nonce}", opaque="ef6dfb078ba22298d366f99567814ffb")
end
-
- def decode(response)
- @authenticated_conn.format.decode(response.body)
- end
end
diff --git a/activeresource/test/cases/connection_test.rb b/activeresource/test/cases/connection_test.rb
index 653912f000..0a07ead15e 100644
--- a/activeresource/test/cases/connection_test.rb
+++ b/activeresource/test/cases/connection_test.rb
@@ -224,7 +224,6 @@ class ConnectionTest < ActiveSupport::TestCase
http = Net::HTTP.new('')
@conn.site="https://secure"
@conn.ssl_options={:verify_mode => OpenSSL::SSL::VERIFY_PEER}
- @conn.timeout = 10 # prevent warning about uninitialized.
@conn.send(:configure_http, http)
assert http.use_ssl?
diff --git a/activeresource/test/fixtures/street_address.rb b/activeresource/test/fixtures/street_address.rb
index 94a86702b0..6a8adb98b5 100644
--- a/activeresource/test/fixtures/street_address.rb
+++ b/activeresource/test/fixtures/street_address.rb
@@ -1,4 +1,4 @@
class StreetAddress < ActiveResource::Base
- self.site = "http://37s.sunrise.i:3000/people/:person_id/"
+ self.site = "http://37s.sunrise.i:3000/people/:person_id"
self.element_name = 'address'
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index c339e93808..02a989db22 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Remove ActiveSupport::TestCase#pending method, use `skip` instead. *Carlos Antonio da Silva*
+
* Deprecates the compatibility method Module#local_constant_names,
use Module#local_constants instead (which returns symbols). *fxn*
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index d4a9b93ff2..5eaeac2cb3 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -357,9 +357,9 @@ module ActiveSupport
# calculating which callbacks can be omitted because of per_key conditions.
#
def __run_callbacks(key, kind, object, &blk) #:nodoc:
- name = __callback_runner_name(key, kind)
+ name = __callback_runner_name(kind)
unless object.respond_to?(name)
- str = send("_#{kind}_callbacks").compile(key, object)
+ str = object.send("_#{kind}_callbacks").compile(key, object)
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{name}() #{str} end
protected :#{name}
@@ -369,11 +369,11 @@ module ActiveSupport
end
def __reset_runner(symbol)
- name = __callback_runner_name(nil, symbol)
+ name = __callback_runner_name(symbol)
undef_method(name) if method_defined?(name)
end
- def __callback_runner_name(key, kind)
+ def __callback_runner_name(kind)
"_run__#{self.name.hash.abs}__#{kind}__callbacks"
end
diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
index 6dd321ecf9..6f730e4b6f 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -1,8 +1,12 @@
+require 'active_support/deprecation'
+
class DateTime
class << self
- # DateTimes aren't aware of DST rules, so use a consistent non-DST offset when creating a DateTime with an offset in the local zone
+ # *DEPRECATED*: Use +DateTime.civil_from_format+ directly.
def local_offset
- ::Time.local(2007).utc_offset.to_r / 86400
+ ActiveSupport::Deprecation.warn 'DateTime.local_offset is deprecated. ' \
+ 'Use DateTime.civil_from_format directly.', caller
+ ::Time.local(2012).utc_offset.to_r / 86400
end
# Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise returns <tt>Time.now.to_datetime</tt>.
diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
index d7b3ad7d8d..dc55e9c33c 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -58,32 +58,27 @@ class DateTime
alias_method :default_inspect, :inspect
alias_method :inspect, :readable_inspect
- # Converts self to a Ruby Date object; time portion is discarded.
- def to_date
- ::Date.new(year, month, day)
- end unless instance_methods(false).include?(:to_date)
-
# Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class.
# If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time.
def to_time
self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec, sec_fraction * 1000000) : self
end
- # To be able to keep Times, Dates and DateTimes interchangeable on conversions.
- def to_datetime
- self
- end unless instance_methods(false).include?(:to_datetime)
-
+ # Returns DateTime with local offset for given year if format is local else offset is zero
+ #
+ # DateTime.civil_from_format :local, 2012
+ # # => Sun, 01 Jan 2012 00:00:00 +0300
+ # DateTime.civil_from_format :local, 2012, 12, 17
+ # # => Mon, 17 Dec 2012 00:00:00 +0000
def self.civil_from_format(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0)
- offset = utc_or_local.to_sym == :local ? local_offset : 0
+ if utc_or_local.to_sym == :local
+ offset = ::Time.local(year, month, day).utc_offset.to_r / 86400
+ else
+ offset = 0
+ end
civil(year, month, day, hour, min, sec, offset)
end
- # Converts datetime to an appropriate format for use in XML.
- def xmlschema
- strftime("%Y-%m-%dT%H:%M:%S%Z")
- end unless instance_methods(false).include?(:xmlschema)
-
# Converts self to a floating-point number of seconds since the Unix epoch.
def to_f
seconds_since_unix_epoch.to_f
diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb
index 7de824a77f..ac2a63d3a1 100644
--- a/activesupport/lib/active_support/core_ext/module/delegation.rb
+++ b/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -81,25 +81,25 @@ class Module
# no matter whether +nil+ responds to the delegated method. You can get a
# +nil+ instead with the +:allow_nil+ option.
#
- # class Foo
- # attr_accessor :bar
- # def initialize(bar = nil)
- # @bar = bar
- # end
- # delegate :zoo, :to => :bar
- # end
- #
- # Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
- #
- # class Foo
- # attr_accessor :bar
- # def initialize(bar = nil)
- # @bar = bar
- # end
- # delegate :zoo, :to => :bar, :allow_nil => true
- # end
- #
- # Foo.new.zoo # returns nil
+ # class Foo
+ # attr_accessor :bar
+ # def initialize(bar = nil)
+ # @bar = bar
+ # end
+ # delegate :zoo, :to => :bar
+ # end
+ #
+ # Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
+ #
+ # class Foo
+ # attr_accessor :bar
+ # def initialize(bar = nil)
+ # @bar = bar
+ # end
+ # delegate :zoo, :to => :bar, :allow_nil => true
+ # end
+ #
+ # Foo.new.zoo # returns nil
#
def delegate(*methods)
options = methods.pop
diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb
index 1e57b586d9..2194dafe4d 100644
--- a/activesupport/lib/active_support/core_ext/string/inflections.rb
+++ b/activesupport/lib/active_support/core_ext/string/inflections.rb
@@ -100,8 +100,8 @@ class String
#
# +underscore+ will also change '::' to '/' to convert namespaces to paths.
#
- # "ActiveRecord".underscore # => "active_record"
- # "ActiveRecord::Errors".underscore # => active_record/errors
+ # "ActiveModel".underscore # => "active_model"
+ # "ActiveModel::Errors".underscore # => "active_model/errors"
def underscore
ActiveSupport::Inflector.underscore(self)
end
diff --git a/activesupport/lib/active_support/core_ext/uri.rb b/activesupport/lib/active_support/core_ext/uri.rb
index 0b219ce44a..bfe0832b37 100644
--- a/activesupport/lib/active_support/core_ext/uri.rb
+++ b/activesupport/lib/active_support/core_ext/uri.rb
@@ -20,7 +20,7 @@ end
module URI
class << self
def parser
- @parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI
+ @parser ||= URI::Parser.new
end
end
end
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 7f325aee94..c245b5b53c 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -42,10 +42,10 @@ module ActiveSupport
# +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
#
# Examples:
- # "active_record".camelize # => "ActiveRecord"
- # "active_record".camelize(:lower) # => "activeRecord"
- # "active_record/errors".camelize # => "ActiveRecord::Errors"
- # "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
+ # "active_model".camelize # => "ActiveModel"
+ # "active_model".camelize(:lower) # => "activeModel"
+ # "active_model/errors".camelize # => "ActiveModel::Errors"
+ # "active_model/errors".camelize(:lower) # => "activeModel::Errors"
#
# As a rule of thumb you can think of +camelize+ as the inverse of +underscore+,
# though there are cases where that does not hold:
@@ -66,8 +66,8 @@ module ActiveSupport
# Changes '::' to '/' to convert namespaces to paths.
#
# Examples:
- # "ActiveRecord".underscore # => "active_record"
- # "ActiveRecord::Errors".underscore # => active_record/errors
+ # "ActiveModel".underscore # => "active_model"
+ # "ActiveModel::Errors".underscore # => "active_model/errors"
#
# As a rule of thumb you can think of +underscore+ as the inverse of +camelize+,
# though there are cases where that does not hold:
diff --git a/activesupport/lib/active_support/log_subscriber.rb b/activesupport/lib/active_support/log_subscriber.rb
index 6296c1d4b8..58938cdc3d 100644
--- a/activesupport/lib/active_support/log_subscriber.rb
+++ b/activesupport/lib/active_support/log_subscriber.rb
@@ -92,7 +92,7 @@ module ActiveSupport
begin
send(method, ActiveSupport::Notifications::Event.new(message, *args))
rescue Exception => e
- logger.error "Could not log #{message.inspect} event. #{e.class}: #{e.message}"
+ logger.error "Could not log #{message.inspect} event. #{e.class}: #{e.message} #{e.backtrace}"
end
end
@@ -100,9 +100,9 @@ module ActiveSupport
%w(info debug warn error fatal unknown).each do |level|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
- def #{level}(*args, &block)
+ def #{level}(progname = nil, &block)
return unless logger
- logger.#{level}(*args, &block)
+ logger.#{level}(progname, &block)
end
METHOD
end
diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb
index 66e8fcadb4..d055767eab 100644
--- a/activesupport/lib/active_support/logger.rb
+++ b/activesupport/lib/active_support/logger.rb
@@ -2,6 +2,41 @@ require 'logger'
module ActiveSupport
class Logger < ::Logger
+ # Broadcasts logs to multiple loggers
+ def self.broadcast(logger) # :nodoc:
+ Module.new do
+ define_method(:add) do |*args, &block|
+ logger.add(*args, &block)
+ super(*args, &block)
+ end
+
+ define_method(:<<) do |x|
+ logger << x
+ super(x)
+ end
+
+ define_method(:close) do
+ logger.close
+ super()
+ end
+
+ define_method(:progname=) do |name|
+ logger.progname = name
+ super(name)
+ end
+
+ define_method(:formatter=) do |formatter|
+ logger.formatter = formatter
+ super(formatter)
+ end
+
+ define_method(:level=) do |level|
+ logger.level = level
+ super(level)
+ end
+ end
+ end
+
def initialize(*args)
super
@formatter = SimpleFormatter.new
diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb
index bf81567d22..9e5a5d0246 100644
--- a/activesupport/lib/active_support/ordered_options.rb
+++ b/activesupport/lib/active_support/ordered_options.rb
@@ -30,8 +30,9 @@ module ActiveSupport #:nodoc:
end
def method_missing(name, *args)
- if name.to_s =~ /(.*)=$/
- self[$1] = args.first
+ name_string = name.to_s
+ if name_string.chomp!('=')
+ self[name_string] = args.first
else
self[name]
end
diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb
index b60bc94db4..f6ad861353 100644
--- a/activesupport/lib/active_support/tagged_logging.rb
+++ b/activesupport/lib/active_support/tagged_logging.rb
@@ -1,62 +1,58 @@
require 'active_support/core_ext/object/blank'
require 'logger'
+require 'active_support/logger'
module ActiveSupport
- # Wraps any standard Logger class to provide tagging capabilities. Examples:
+ # Wraps any standard Logger object to provide tagging capabilities. Examples:
#
- # Logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
- # Logger.tagged("BCX") { Logger.info "Stuff" } # Logs "[BCX] Stuff"
- # Logger.tagged("BCX", "Jason") { Logger.info "Stuff" } # Logs "[BCX] [Jason] Stuff"
- # Logger.tagged("BCX") { Logger.tagged("Jason") { Logger.info "Stuff" } } # Logs "[BCX] [Jason] Stuff"
+ # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
+ # logger.tagged("BCX") { logger.info "Stuff" } # Logs "[BCX] Stuff"
+ # logger.tagged("BCX", "Jason") { logger.info "Stuff" } # Logs "[BCX] [Jason] Stuff"
+ # logger.tagged("BCX") { logger.tagged("Jason") { logger.info "Stuff" } } # Logs "[BCX] [Jason] Stuff"
#
# This is used by the default Rails.logger as configured by Railties to make it easy to stamp log lines
# with subdomains, request ids, and anything else to aid debugging of multi-user production applications.
- class TaggedLogging
- def initialize(logger)
- @logger = logger
+ module TaggedLogging
+ class Formatter < ActiveSupport::Logger::SimpleFormatter # :nodoc:
+ # This method is invoked when a log event occurs
+ def call(severity, timestamp, progname, msg)
+ super(severity, timestamp, progname, "#{tags_text}#{msg}")
+ end
+
+ def clear!
+ current_tags.clear
+ end
+
+ def current_tags
+ Thread.current[:activesupport_tagged_logging_tags] ||= []
+ end
+
+ private
+ def tags_text
+ tags = current_tags
+ if tags.any?
+ tags.collect { |tag| "[#{tag}] " }.join
+ end
+ end
+ end
+
+ def self.new(logger)
+ logger.formatter = Formatter.new
+ logger.extend(self)
end
def tagged(*new_tags)
- tags = current_tags
- new_tags = Array(new_tags).flatten.reject(&:blank?)
+ tags = formatter.current_tags
+ new_tags = new_tags.flatten.reject(&:blank?)
tags.concat new_tags
yield
ensure
tags.pop(new_tags.size)
end
- def add(severity, message = nil, progname = nil, &block)
- @logger.add(severity, "#{tags_text}#{message}", progname, &block)
- end
-
- %w( fatal error warn info debug unknown ).each do |severity|
- eval <<-EOM, nil, __FILE__, __LINE__ + 1
- def #{severity}(progname = nil, &block) # def warn(progname = nil, &block)
- add(Logger::#{severity.upcase}, progname, &block) # add(Logger::WARN, progname, &block)
- end # end
- EOM
- end
-
def flush
- current_tags.clear
- @logger.flush if @logger.respond_to?(:flush)
- end
-
- def method_missing(method, *args)
- @logger.send(method, *args)
- end
-
- protected
-
- def tags_text
- tags = current_tags
- if tags.any?
- tags.collect { |tag| "[#{tag}] " }.join
- end
- end
-
- def current_tags
- Thread.current[:activesupport_tagged_logging_tags] ||= []
+ formatter.clear!
+ super if defined?(super)
end
end
end
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index 4169557286..9a52c916ec 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -3,7 +3,6 @@ require 'active_support/testing/setup_and_teardown'
require 'active_support/testing/assertions'
require 'active_support/testing/deprecation'
require 'active_support/testing/declarative'
-require 'active_support/testing/pending'
require 'active_support/testing/isolation'
require 'active_support/testing/mochaing'
require 'active_support/core_ext/kernel/reporting'
@@ -40,7 +39,6 @@ module ActiveSupport
include ActiveSupport::Testing::SetupAndTeardown
include ActiveSupport::Testing::Assertions
include ActiveSupport::Testing::Deprecation
- include ActiveSupport::Testing::Pending
extend ActiveSupport::Testing::Declarative
# test/unit backwards compatibility methods
diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb
index 5d5de4798d..1a0681e850 100644
--- a/activesupport/lib/active_support/testing/isolation.rb
+++ b/activesupport/lib/active_support/testing/isolation.rb
@@ -37,10 +37,6 @@ module ActiveSupport
!ENV["NO_FORK"] && ((RbConfig::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
end
- def self.included(base)
- base.send :include, MiniTest
- end
-
def _run_class_setup # class setup method should only happen in parent
unless defined?(@@ran_class_setup) || ENV['ISOLATION_TEST']
self.class.setup if self.class.respond_to?(:setup)
@@ -48,18 +44,16 @@ module ActiveSupport
end
end
- module MiniTest
- def run(runner)
- _run_class_setup
+ def run(runner)
+ _run_class_setup
- serialized = run_in_isolation do |isolated_runner|
- super(isolated_runner)
- end
-
- retval, proxy = Marshal.load(serialized)
- proxy.__replay__(runner)
- retval
+ serialized = run_in_isolation do |isolated_runner|
+ super(isolated_runner)
end
+
+ retval, proxy = Marshal.load(serialized)
+ proxy.__replay__(runner)
+ retval
end
module Forking
diff --git a/activesupport/lib/active_support/testing/pending.rb b/activesupport/lib/active_support/testing/pending.rb
deleted file mode 100644
index 510f80f32c..0000000000
--- a/activesupport/lib/active_support/testing/pending.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# Some code from jeremymcanally's "pending"
-# https://github.com/jeremymcanally/pending/tree/master
-
-module ActiveSupport
- module Testing
- module Pending
-
- unless defined?(Spec)
-
- @@pending_cases = []
- @@at_exit = false
-
- def pending(description = "", &block)
- skip(description.blank? ? nil : description)
- end
- end
-
- end
- end
-end
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
index 209bfac19f..244ee1a224 100644
--- a/activesupport/lib/active_support/testing/performance.rb
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -13,7 +13,6 @@ module ActiveSupport
included do
superclass_delegating_accessor :profile_options
self.profile_options = {}
- include ForMiniTest
end
# each implementation should define metrics and freeze the defaults
@@ -36,40 +35,38 @@ module ActiveSupport
"#{self.class.name}##{method_name}"
end
- module ForMiniTest
- def run(runner)
- @runner = runner
+ def run(runner)
+ @runner = runner
- run_warmup
- if full_profile_options && metrics = full_profile_options[:metrics]
- metrics.each do |metric_name|
- if klass = Metrics[metric_name.to_sym]
- run_profile(klass.new)
- end
+ run_warmup
+ if full_profile_options && metrics = full_profile_options[:metrics]
+ metrics.each do |metric_name|
+ if klass = Metrics[metric_name.to_sym]
+ run_profile(klass.new)
end
end
-
- return
end
- def run_test(metric, mode)
- result = '.'
+ return
+ end
+
+ def run_test(metric, mode)
+ result = '.'
+ begin
+ run_callbacks :setup
+ setup
+ metric.send(mode) { __send__ method_name }
+ rescue Exception => e
+ result = @runner.puke(self.class, method_name, e)
+ ensure
begin
- run_callbacks :setup
- setup
- metric.send(mode) { __send__ method_name }
+ teardown
+ run_callbacks :teardown, :enumerator => :reverse_each
rescue Exception => e
result = @runner.puke(self.class, method_name, e)
- ensure
- begin
- teardown
- run_callbacks :teardown, :enumerator => :reverse_each
- rescue Exception => e
- result = @runner.puke(self.class, method_name, e)
- end
end
- result
end
+ result
end
protected
diff --git a/activesupport/test/broadcast_logger_test.rb b/activesupport/test/broadcast_logger_test.rb
new file mode 100644
index 0000000000..6d4e3b74f7
--- /dev/null
+++ b/activesupport/test/broadcast_logger_test.rb
@@ -0,0 +1,82 @@
+require 'abstract_unit'
+
+module ActiveSupport
+ class BroadcastLoggerTest < TestCase
+ attr_reader :logger, :log1, :log2
+ def setup
+ @log1 = FakeLogger.new
+ @log2 = FakeLogger.new
+ @log1.extend Logger.broadcast @log2
+ @logger = @log1
+ end
+
+ def test_debug
+ logger.debug "foo"
+ assert_equal 'foo', log1.adds.first[2]
+ assert_equal 'foo', log2.adds.first[2]
+ end
+
+ def test_close
+ logger.close
+ assert log1.closed, 'should be closed'
+ assert log2.closed, 'should be closed'
+ end
+
+ def test_chevrons
+ logger << "foo"
+ assert_equal %w{ foo }, log1.chevrons
+ assert_equal %w{ foo }, log2.chevrons
+ end
+
+ def test_level
+ assert_nil logger.level
+ logger.level = 10
+ assert_equal 10, log1.level
+ assert_equal 10, log2.level
+ end
+
+ def test_progname
+ assert_nil logger.progname
+ logger.progname = 10
+ assert_equal 10, log1.progname
+ assert_equal 10, log2.progname
+ end
+
+ def test_formatter
+ assert_nil logger.formatter
+ logger.formatter = 10
+ assert_equal 10, log1.formatter
+ assert_equal 10, log2.formatter
+ end
+
+ class FakeLogger
+ attr_reader :adds, :closed, :chevrons
+ attr_accessor :level, :progname, :formatter
+
+ def initialize
+ @adds = []
+ @closed = false
+ @chevrons = []
+ @level = nil
+ @progname = nil
+ @formatter = nil
+ end
+
+ def debug msg, &block
+ add(:omg, nil, msg, &block)
+ end
+
+ def << x
+ @chevrons << x
+ end
+
+ def add(*args)
+ @adds << args
+ end
+
+ def close
+ @closed = true
+ end
+ end
+ end
+end
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index 2c2a420619..032787f0f4 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -344,6 +344,54 @@ module CallbacksTest
end
end
+ module ExtendModule
+ def self.extended(base)
+ base.class_eval do
+ set_callback :save, :before, :record3
+ end
+ end
+ def record3
+ @recorder << 3
+ end
+ end
+
+ module IncludeModule
+ def self.included(base)
+ base.class_eval do
+ set_callback :save, :before, :record2
+ end
+ end
+ def record2
+ @recorder << 2
+ end
+ end
+
+ class ExtendCallbacks
+
+ include ActiveSupport::Callbacks
+
+ define_callbacks :save
+ set_callback :save, :before, :record1
+
+ include IncludeModule
+
+ def save
+ run_callbacks :save
+ end
+
+ attr_reader :recorder
+
+ def initialize
+ @recorder = []
+ end
+
+ private
+
+ def record1
+ @recorder << 1
+ end
+ end
+
class AroundCallbacksTest < ActiveSupport::TestCase
def test_save_around
around = AroundPerson.new
@@ -645,4 +693,12 @@ module CallbacksTest
end
end
+ class ExtendCallbacksTest < ActiveSupport::TestCase
+ def test_save
+ model = ExtendCallbacks.new.extend ExtendModule
+ model.save
+ assert_equal [1, 2, 3], model.recorder
+ end
+ end
+
end
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index 433dafde83..57b5b95a66 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -43,8 +43,8 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase
end
def test_civil_from_format
- assert_equal DateTime.civil(2010, 5, 4, 0, 0, 0, DateTime.local_offset), DateTime.civil_from_format(:local, 2010, 5, 4)
- assert_equal DateTime.civil(2010, 5, 4, 0, 0, 0, 0), DateTime.civil_from_format(:utc, 2010, 5, 4)
+ assert_equal Time.local(2010, 5, 4, 0, 0, 0), DateTime.civil_from_format(:local, 2010, 5, 4)
+ assert_equal Time.utc(2010, 5, 4, 0, 0, 0), DateTime.civil_from_format(:utc, 2010, 5, 4)
end
def test_seconds_since_midnight
@@ -331,15 +331,6 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase
assert DateTime.new.acts_like_time?
end
- def test_local_offset
- with_env_tz 'US/Eastern' do
- assert_equal Rational(-5, 24), DateTime.local_offset
- end
- with_env_tz 'US/Central' do
- assert_equal Rational(-6, 24), DateTime.local_offset
- end
- end
-
def test_utc?
assert_equal true, DateTime.civil(2005, 2, 21, 10, 11, 12).utc?
assert_equal true, DateTime.civil(2005, 2, 21, 10, 11, 12, 0).utc?
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index cfd5a27f08..d45ab70f53 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -618,14 +618,14 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30), Time.utc(2005, 2, 21, 17, 44, 30)
assert_equal Time.time_with_datetime_fallback(:local, 2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30)
assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, 0)
- assert_equal Time.time_with_datetime_fallback(:local, 2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, DateTime.local_offset)
+ assert_equal Time.time_with_datetime_fallback(:local, 2039, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 2039, 2, 21, 17, 44, 30)
assert_equal Time.time_with_datetime_fallback(:utc, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, 0)
assert_equal Time.time_with_datetime_fallback(:utc, 2005), Time.utc(2005)
assert_equal Time.time_with_datetime_fallback(:utc, 2039), DateTime.civil(2039, 1, 1, 0, 0, 0, 0)
assert_equal Time.time_with_datetime_fallback(:utc, 2005, 2, 21, 17, 44, 30, 1), Time.utc(2005, 2, 21, 17, 44, 30, 1) #with usec
# This won't overflow on 64bit linux
unless time_is_64bits?
- assert_equal Time.time_with_datetime_fallback(:local, 1900, 2, 21, 17, 44, 30), DateTime.civil(1900, 2, 21, 17, 44, 30, DateTime.local_offset, 0)
+ assert_equal Time.time_with_datetime_fallback(:local, 1900, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 1900, 2, 21, 17, 44, 30)
assert_equal Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1),
DateTime.civil(2039, 2, 21, 17, 44, 30, 0, 0)
assert_equal ::Date::ITALY, Time.time_with_datetime_fallback(:utc, 2039, 2, 21, 17, 44, 30, 1).start # use Ruby's default start value
@@ -647,10 +647,10 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
def test_local_time
assert_equal Time.local_time(2005, 2, 21, 17, 44, 30), Time.local(2005, 2, 21, 17, 44, 30)
- assert_equal Time.local_time(2039, 2, 21, 17, 44, 30), DateTime.civil(2039, 2, 21, 17, 44, 30, DateTime.local_offset)
+ assert_equal Time.local_time(2039, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 2039, 2, 21, 17, 44, 30)
unless time_is_64bits?
- assert_equal Time.local_time(1901, 2, 21, 17, 44, 30), DateTime.civil(1901, 2, 21, 17, 44, 30, DateTime.local_offset)
+ assert_equal Time.local_time(1901, 2, 21, 17, 44, 30), DateTime.civil_from_format(:local, 1901, 2, 21, 17, 44, 30)
end
end
diff --git a/activesupport/test/core_ext/uri_ext_test.rb b/activesupport/test/core_ext/uri_ext_test.rb
index 4a6cbb8801..03e388dd7a 100644
--- a/activesupport/test/core_ext/uri_ext_test.rb
+++ b/activesupport/test/core_ext/uri_ext_test.rb
@@ -7,11 +7,7 @@ class URIExtTest < ActiveSupport::TestCase
def test_uri_decode_handle_multibyte
str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
- if URI.const_defined?(:Parser)
- parser = URI::Parser.new
- assert_equal str, parser.unescape(parser.escape(str))
- else
- assert_equal str, URI.unescape(URI.escape(str))
- end
+ parser = URI::Parser.new
+ assert_equal str, parser.unescape(parser.escape(str))
end
end
diff --git a/activesupport/test/log_subscriber_test.rb b/activesupport/test/log_subscriber_test.rb
index 0c1f3c51ed..8e160714b1 100644
--- a/activesupport/test/log_subscriber_test.rb
+++ b/activesupport/test/log_subscriber_test.rb
@@ -118,6 +118,6 @@ class SyncLogSubscriberTest < ActiveSupport::TestCase
assert_equal 'some_event.my_log_subscriber', @logger.logged(:info).last
assert_equal 1, @logger.logged(:error).size
- assert_equal 'Could not log "puke.my_log_subscriber" event. RuntimeError: puke', @logger.logged(:error).last
+ assert_match 'Could not log "puke.my_log_subscriber" event. RuntimeError: puke', @logger.logged(:error).last
end
-end \ No newline at end of file
+end
diff --git a/rails.gemspec b/rails.gemspec
index 1d4c6c36c8..cd7c5d1ee9 100644
--- a/rails.gemspec
+++ b/rails.gemspec
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
s.description = 'Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.'
s.required_ruby_version = '>= 1.9.3'
- s.required_rubygems_version = ">= 1.3.6"
+ s.required_rubygems_version = ">= 1.8.11"
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
diff --git a/railties/guides/code/getting_started/Gemfile b/railties/guides/code/getting_started/Gemfile
index 898510dcaa..768985070c 100644
--- a/railties/guides/code/getting_started/Gemfile
+++ b/railties/guides/code/getting_started/Gemfile
@@ -1,8 +1,9 @@
-source 'http://rubygems.org'
+source 'https://rubygems.org'
+
+gem 'rails', '3.2.0'
-gem 'rails', '3.1.0'
# Bundle edge Rails instead:
-# gem 'rails', :git => 'git://github.com/rails/rails.git'
+# gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'sqlite3'
@@ -10,13 +11,23 @@ gem 'sqlite3'
# Gems used only for assets and not required
# in production environments by default.
group :assets do
- gem 'sass-rails', " ~> 3.1.0"
- gem 'coffee-rails', "~> 3.1.0"
- gem 'uglifier'
+ gem 'sass-rails', '~> 3.2.3'
+ gem 'coffee-rails', '~> 3.2.1'
+
+ # See https://github.com/sstephenson/execjs#readme for more supported runtimes
+ # gem 'therubyracer'
+
+ gem 'uglifier', '>= 1.0.3'
end
gem 'jquery-rails'
+# To use ActiveModel has_secure_password
+# gem 'bcrypt-ruby', '~> 3.0.0'
+
+# To use Jbuilder templates for JSON
+# gem 'jbuilder'
+
# Use unicorn as the web server
# gem 'unicorn'
diff --git a/railties/guides/code/getting_started/app/assets/javascripts/application.js b/railties/guides/code/getting_started/app/assets/javascripts/application.js
index 37c7bfcdb5..9097d830e2 100644
--- a/railties/guides/code/getting_started/app/assets/javascripts/application.js
+++ b/railties/guides/code/getting_started/app/assets/javascripts/application.js
@@ -1,9 +1,15 @@
-// This is a manifest file that'll be compiled into including all the files listed below.
-// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
-// be included in the compiled file accessible from http://example.com/assets/application.js
+// This is a manifest file that'll be compiled into application.js, which will include all the files
+// listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
+// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
+//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
+// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
+// GO AFTER THE REQUIRES BELOW.
+//
//= require jquery
//= require jquery_ujs
//= require_tree .
diff --git a/railties/guides/code/getting_started/app/assets/stylesheets/application.css b/railties/guides/code/getting_started/app/assets/stylesheets/application.css
index fc25b5723f..3b5cc6648e 100644
--- a/railties/guides/code/getting_started/app/assets/stylesheets/application.css
+++ b/railties/guides/code/getting_started/app/assets/stylesheets/application.css
@@ -1,7 +1,13 @@
/*
- * This is a manifest file that'll automatically include all the stylesheets available in this directory
- * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
- * the top of the compiled file, but it's generally better to create a new file per style scope.
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
+ * listed below.
+ *
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
+ *
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
+ * compiled file, but it's generally better to create a new file per style scope.
+ *
*= require_self
- *= require_tree .
-*/ \ No newline at end of file
+ *= require_tree .
+*/
diff --git a/railties/guides/code/getting_started/app/views/layouts/application.html.erb b/railties/guides/code/getting_started/app/views/layouts/application.html.erb
index 7fd6b4f516..6578a41da2 100644
--- a/railties/guides/code/getting_started/app/views/layouts/application.html.erb
+++ b/railties/guides/code/getting_started/app/views/layouts/application.html.erb
@@ -6,7 +6,7 @@
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
-<body style="background: #EEEEEE;">
+<body>
<%= yield %>
diff --git a/railties/guides/code/getting_started/config/application.rb b/railties/guides/code/getting_started/config/application.rb
index 5f9010fced..d2cd5c028b 100644
--- a/railties/guides/code/getting_started/config/application.rb
+++ b/railties/guides/code/getting_started/config/application.rb
@@ -4,7 +4,7 @@ require 'rails/all'
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
- Bundler.require *Rails.groups(:assets => %w(development test))
+ Bundler.require(*Rails.groups(:assets => %w(development test)))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
@@ -37,13 +37,19 @@ module Blog
# Use SQL instead of Active Record's schema dumper when creating the database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
- # like if you have constraints or database-specific column types
+ # like if you have constraints or database-specific column types.
# config.active_record.schema_format = :sql
- # Enable the asset pipeline
+ # Enforce whitelist mode for mass assignment.
+ # This will create an empty whitelist of attributes available for mass-assignment for all models
+ # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
+ # parameters by using an attr_accessible or attr_protected declaration.
+ # config.active_record.whitelist_attributes = true
+
+ # Enable the asset pipeline.
config.assets.enabled = true
- # Version of your assets, change this if you want to expire all your assets
+ # Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
end
end
diff --git a/railties/guides/code/getting_started/config/environments/development.rb b/railties/guides/code/getting_started/config/environments/development.rb
index aefd25c6b6..cec2b20c0b 100644
--- a/railties/guides/code/getting_started/config/environments/development.rb
+++ b/railties/guides/code/getting_started/config/environments/development.rb
@@ -1,34 +1,34 @@
Blog::Application.configure do
- # Settings specified here will take precedence over those in config/application.rb
+ # Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
- # Show full error reports and disable caching
+ # Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
- # Don't care if the mailer can't send
+ # Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
- # Print deprecation notices to the Rails logger
+ # Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
- # Only use best-standards-support built into browsers
+ # Only use best-standards-support built into browsers.
config.action_dispatch.best_standards_support = :builtin
- # Raise exception on mass assignment protection for ActiveRecord models
+ # Raise exception on mass assignment protection for ActiveRecord models.
config.active_record.mass_assignment_sanitizer = :strict
# Log the query plan for queries taking more than this (works
- # with SQLite, MySQL, and PostgreSQL)
+ # with SQLite, MySQL, and PostgreSQL).
config.active_record.auto_explain_threshold_in_seconds = 0.5
- # Do not compress assets
+ # Do not compress assets.
config.assets.compress = false
- # Expands the lines which load the assets
+ # Expands the lines which load the assets.
config.assets.debug = true
end
diff --git a/railties/guides/code/getting_started/config/environments/production.rb b/railties/guides/code/getting_started/config/environments/production.rb
index c9b2f41c39..cfb8c960d6 100644
--- a/railties/guides/code/getting_started/config/environments/production.rb
+++ b/railties/guides/code/getting_started/config/environments/production.rb
@@ -1,67 +1,67 @@
Blog::Application.configure do
- # Settings specified here will take precedence over those in config/application.rb
+ # Settings specified here will take precedence over those in config/application.rb.
- # Code is not reloaded between requests
+ # Code is not reloaded between requests.
config.cache_classes = true
- # Full error reports are disabled and caching is turned on
+ # Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
- # Disable Rails's static asset server (Apache or nginx will already do this)
+ # Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_assets = false
- # Compress JavaScripts and CSS
+ # Compress JavaScripts and CSS.
config.assets.compress = true
- # Don't fallback to assets pipeline if a precompiled asset is missed
+ # Don't fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
- # Generate digests for assets URLs
+ # Generate digests for assets URLs.
config.assets.digest = true
- # Defaults to Rails.root.join("public/assets")
+ # Defaults to Rails.root.join("public/assets").
# config.assets.manifest = YOUR_PATH
- # Specifies the header that your server uses for sending files
+ # Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
- # See everything in the log (default is :info)
+ # See everything in the log (default is :info).
# config.log_level = :debug
- # Prepend all log lines with the following tags
+ # Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
- # Use a different logger for distributed setups
+ # Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
- # Use a different cache store in production
+ # Use a different cache store in production.
# config.cache_store = :mem_cache_store
- # Enable serving of images, stylesheets, and JavaScripts from an asset server
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = "http://assets.example.com"
- # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
+ # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added).
# config.assets.precompile += %w( search.js )
- # Disable delivery errors, bad email addresses will be ignored
+ # Disable delivery errors, bad email addresses will be ignored.
# config.action_mailer.raise_delivery_errors = false
- # Enable threaded mode
+ # Enable threaded mode.
# config.threadsafe!
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
- # the I18n.default_locale when a translation can not be found)
+ # the I18n.default_locale when a translation can not be found).
config.i18n.fallbacks = true
- # Send deprecation notices to registered listeners
+ # Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Log the query plan for queries taking more than this (works
- # with SQLite, MySQL, and PostgreSQL)
+ # with SQLite, MySQL, and PostgreSQL).
# config.active_record.auto_explain_threshold_in_seconds = 0.5
end
diff --git a/railties/guides/code/getting_started/config/environments/test.rb b/railties/guides/code/getting_started/config/environments/test.rb
index 1d45541d5c..f2bc932fb3 100644
--- a/railties/guides/code/getting_started/config/environments/test.rb
+++ b/railties/guides/code/getting_started/config/environments/test.rb
@@ -1,5 +1,5 @@
Blog::Application.configure do
- # Settings specified here will take precedence over those in config/application.rb
+ # Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
@@ -7,28 +7,28 @@ Blog::Application.configure do
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
- # Configure static asset server for tests with Cache-Control for performance
+ # Configure static asset server for tests with Cache-Control for performance.
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
- # Show full error reports and disable caching
+ # Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
- # Raise exceptions instead of rendering exception templates
+ # Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
- # Disable request forgery protection in test environment
- config.action_controller.allow_forgery_protection = false
+ # Disable request forgery protection in test environment.
+ config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
- # Print deprecation notices to the stderr
- config.active_support.deprecation = :stderr
+ # Raise exception on mass assignment protection for Active Record models.
+ config.active_record.mass_assignment_sanitizer = :strict
- # Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets
- config.assets.allow_debugging = true
+ # Print deprecation notices to the stderr.
+ config.active_support.deprecation = :stderr
end
diff --git a/railties/guides/code/getting_started/config/initializers/inflections.rb b/railties/guides/code/getting_started/config/initializers/inflections.rb
index 9e8b0131f8..5d8d9be237 100644
--- a/railties/guides/code/getting_started/config/initializers/inflections.rb
+++ b/railties/guides/code/getting_started/config/initializers/inflections.rb
@@ -8,3 +8,8 @@
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
+#
+# These inflection rules are supported but not enabled by default:
+# ActiveSupport::Inflector.inflections do |inflect|
+# inflect.acronym 'RESTful'
+# end
diff --git a/railties/guides/code/getting_started/config/routes.rb b/railties/guides/code/getting_started/config/routes.rb
index 31f0d210db..b048ac68f1 100644
--- a/railties/guides/code/getting_started/config/routes.rb
+++ b/railties/guides/code/getting_started/config/routes.rb
@@ -1,7 +1,7 @@
Blog::Application.routes.draw do
- resources :posts do
- resources :comments
- end
+ resources :posts do
+ resources :comments
+ end
get "home/index"
@@ -60,5 +60,5 @@ Blog::Application.routes.draw do
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
- # match ':controller(/:action(/:id(.:format)))'
+ # match ':controller(/:action(/:id))(.:format)'
end
diff --git a/railties/guides/code/getting_started/public/500.html b/railties/guides/code/getting_started/public/500.html
index b80307fc16..f3648a0dbc 100644
--- a/railties/guides/code/getting_started/public/500.html
+++ b/railties/guides/code/getting_started/public/500.html
@@ -20,7 +20,6 @@
<!-- This file lives in public/500.html -->
<div class="dialog">
<h1>We're sorry, but something went wrong.</h1>
- <p>We've been notified about this issue and we'll take a look at it shortly.</p>
</div>
</body>
</html>
diff --git a/railties/guides/source/3_2_release_notes.textile b/railties/guides/source/3_2_release_notes.textile
index 439cd5f714..d669a7fdfa 100644
--- a/railties/guides/source/3_2_release_notes.textile
+++ b/railties/guides/source/3_2_release_notes.textile
@@ -27,6 +27,7 @@ h4. What to update in your apps
** <tt>rails = 3.2.0</tt>
** <tt>sass-rails ~> 3.2.3</tt>
** <tt>coffee-rails ~> 3.2.1</tt>
+** <tt>uglifier >= 1.0.3</tt>
* Rails 3.2 deprecates <tt>vendor/plugins</tt> and Rails 4.0 will remove them completely. You can start replacing these plugins by extracting them as gems and adding them in your Gemfile. If you choose not to make them gems, you can move them into, say, <tt>lib/my_plugin/*</tt> and add an appropriate initializer in <tt>config/initializers/my_plugin.rb</tt>.
@@ -138,10 +139,16 @@ will create indexes for +title+ and +author+ with the latter being an unique ind
* Remove old <tt>config.paths.app.controller</tt> API in favor of <tt>config.paths["app/controller"]</tt>.
-h4. Deprecations
+h4(#railties_deprecations). Deprecations
* +Rails::Plugin+ is deprecated and will be removed in Rails 4.0. Instead of adding plugins to +vendor/plugins+ use gems or bundler with path or git dependencies.
+h3. Action Mailer
+
+* Upgraded <tt>mail</tt> version to 2.4.0.
+
+* Removed the old Action Mailer API which was deprecated since Rails 3.0.
+
h3. Action Pack
h4. Action Controller
@@ -198,7 +205,7 @@ We now no longer write out HTTP_COOKIE and the cookie jar is persistent between
* Assets should use the request protocol by default or default to relative if no request is available.
-h5. Deprecations
+h5(#actioncontroller_deprecations). Deprecations
* Deprecated implied layout lookup in controllers whose parent had a explicit layout set:
@@ -219,8 +226,6 @@ In the example above, Posts controller will no longer automatically look up for
* Deprecated <tt>method_missing</tt> in favour of +action_missing+ for missing actions.
-* Deprecated <tt>ActionController#performed?</tt> in favour of checking for the presence of <tt>response_body</tt>.
-
* Deprecated <tt>ActionController#rescue_action</tt>, <tt>ActionController#initialize_template_class</tt> and <tt>ActionController#assign_shortcuts</tt>.
h4. Action Dispatch
@@ -233,7 +238,7 @@ h4. Action Dispatch
* Allow rescue responses to be configured through a railtie as in <tt>config.action_dispatch.rescue_responses</tt>.
-h5. Deprecations
+h5(#actiondispatch_deprecations). Deprecations
* Deprecated the ability to set a default charset at the controller level, use the new <tt>config.action_dispatch.default_charset</tt> instead.
@@ -280,17 +285,19 @@ end
* Added +font_path+ helper method that computes the path to a font asset in <tt>public/fonts</tt>.
-h5. Deprecations
+h5(#actionview_deprecations). Deprecations
* Passing formats or handlers to render :template and friends like <tt>render :template => "foo.html.erb"</tt> is deprecated. Instead, you can provide :handlers and :formats directly as an options: <tt> render :template => "foo", :formats => [:html, :js], :handlers => :erb</tt>.
-h3. Sprockets
+h4. Sprockets
* Adds a configuration option <tt>config.assets.logger</tt> to control Sprockets logging. Set it to +false+ to turn off logging and to +nil+ to default to +Rails.logger+.
h3. Active Record
-* Boolean columns with 'on' and 'ON' values are type casted to true.
+* Boolean columns with 'on' and 'ON' values are type cast to true.
+
+* When the +timestamps+ method creates the +created_at+ and +updated_at+ columns, it makes them non-nullable by default.
* Implemented <tt>ActiveRecord::Relation#explain</tt>.
@@ -365,7 +372,34 @@ has_many :clients, :class_name => :Client # Note that the symbol need to be capi
User.where(:first_name => "Scarlett").first_or_create!(:last_name => "Johansson")
</ruby>
-h4. Deprecations
+* Added a <tt>with_lock</tt> method to Active Record objects, which starts a transaction, locks the object (pessimistically) and yields to the block. The method takes one (optional) parameter and passes it to +lock!+.
+
+This makes it possible to write the following:
+
+<ruby>
+class Order < ActiveRecord::Base
+ def cancel!
+ transaction do
+ lock!
+ # ... cancelling logic
+ end
+ end
+end
+</ruby>
+
+as:
+
+<ruby>
+class Order < ActiveRecord::Base
+ def cancel!
+ with_lock do
+ # ... cancelling logic
+ end
+ end
+end
+</ruby>
+
+h4(#activerecord_deprecations). Deprecations
* Automatic closure of connections in threads is deprecated. For example the following code is deprecated:
@@ -413,7 +447,7 @@ h3. Active Model
* Provide mass_assignment_sanitizer as an easy API to replace the sanitizer behavior. Also support both :logger (default) and :strict sanitizer behavior.
-h4. Deprecations
+h4(#activemodel_deprecations). Deprecations
* Deprecated <tt>define_attr_method</tt> in <tt>ActiveModel::AttributeMethods</tt> because this only existed to support methods like +set_table_name+ in Active Record, which are themselves being deprecated.
@@ -473,7 +507,7 @@ Event.where(:created_at => Time.now.all_day)
* Removed <tt>ActiveSupport::SecureRandom</tt> in favor of <tt>SecureRandom</tt> from the standard library.
-h4. Deprecations
+h4(#activesupport_deprecations). Deprecations
* +ActiveSupport::Base64+ is deprecated in favor of <tt>::Base64</tt>.
diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile
index beada85ce3..84687e2e4f 100644
--- a/railties/guides/source/active_record_querying.textile
+++ b/railties/guides/source/active_record_querying.textile
@@ -692,6 +692,17 @@ Item.transaction do
end
</ruby>
+If you already have an instance of your model, you can start a transaction and acquire the lock in one go using the following code:
+
+<ruby>
+item = Item.first
+item.with_lock do
+ # This block is called within a transaction,
+ # item is already locked.
+ item.increment!(:views)
+end
+</ruby>
+
h3. Joining Tables
Active Record provides a finder method called +joins+ for specifying +JOIN+ clauses on the resulting SQL. There are multiple ways to use the +joins+ method.
@@ -954,7 +965,7 @@ If you're working with dates or times within scopes, due to how they are evaluat
<ruby>
class Post < ActiveRecord::Base
- scope :last_week, lambda { where("created_at < ?", Time.zone.now ) }
+ scope :created_before_now, lambda { where("created_at < ?", Time.zone.now ) }
end
</ruby>
@@ -966,21 +977,21 @@ When a +lambda+ is used for a +scope+, it can take arguments:
<ruby>
class Post < ActiveRecord::Base
- scope :1_week_before, lambda { |time| where("created_at < ?", time) }
+ scope :created_before, lambda { |time| where("created_at < ?", time) }
end
</ruby>
This may then be called using this:
<ruby>
-Post.1_week_before(Time.zone.now)
+Post.created_before(Time.zone.now)
</ruby>
However, this is just duplicating the functionality that would be provided to you by a class method.
<ruby>
class Post < ActiveRecord::Base
- def self.1_week_before(time)
+ def self.created_before(time)
where("created_at < ?", time)
end
end
@@ -989,7 +1000,7 @@ end
Using a class method is the preferred way to accept arguments for scopes. These methods will still be accessible on the association objects:
<ruby>
-category.posts.1_week_before(time)
+category.posts.created_before(time)
</ruby>
h4. Working with scopes
diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile
index a27c292a4c..15d24f9ac1 100644
--- a/railties/guides/source/active_record_validations_callbacks.textile
+++ b/railties/guides/source/active_record_validations_callbacks.textile
@@ -614,7 +614,7 @@ As shown in the example, you can also combine standard validations with your own
h4. Custom Methods
-You can also create methods that verify the state of your models and add messages to the +errors+ collection when they are invalid. You must then register these methods by using one or more of the +validate+, +validate_on_create+ or +validate_on_update+ class methods, passing in the symbols for the validation methods' names.
+You can also create methods that verify the state of your models and add messages to the +errors+ collection when they are invalid. You must then register these methods by using the +validate+ class method, passing in the symbols for the validation methods' names.
You can pass more than one symbol for each class method and the respective validations will be run in the same order as they were registered.
@@ -637,12 +637,24 @@ class Invoice < ActiveRecord::Base
end
</ruby>
+By default such validations will run every time you call +valid?+. It is also possible to control when to run these custom validations by giving an +:on+ option to the +validate+ method, with either: +:create+ or +:update+.
+
+<ruby>
+class Invoice < ActiveRecord::Base
+ validate :active_customer, :on => :create
+
+ def active_customer
+ errors.add(:customer_id, "is not active") unless customer.active?
+ end
+end
+</ruby>
+
You can even create your own validation helpers and reuse them in several different models. For example, an application that manages surveys may find it useful to express that a certain field corresponds to a set of choices:
<ruby>
ActiveRecord::Base.class_eval do
def self.validates_as_choice(attr_name, n, options={})
- validates attr_name, :inclusion => { {:in => 1..n}.merge(options) }
+ validates attr_name, :inclusion => { { :in => 1..n }.merge!(options) }
end
end
</ruby>
@@ -659,7 +671,7 @@ h3. Working with Validation Errors
In addition to the +valid?+ and +invalid?+ methods covered earlier, Rails provides a number of methods for working with the +errors+ collection and inquiring about the validity of objects.
-The following is a list of the most commonly used methods. Please refer to the +ActiveRecord::Errors+ documentation for a list of all the available methods.
+The following is a list of the most commonly used methods. Please refer to the +ActiveModel::Errors+ documentation for a list of all the available methods.
h4(#working_with_validation_errors-errors). +errors+
@@ -889,13 +901,8 @@ Below is a simple example where we change the Rails behavior to always display t
<ruby>
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
- if instance.error_message.kind_of?(Array)
- %(#{html_tag}<span class="validation-error">&nbsp;
- #{instance.error_message.join(',')}</span>).html_safe
- else
- %(#{html_tag}<span class="validation-error">&nbsp;
- #{instance.error_message}</span>).html_safe
- end
+ errors = Array(instance.error_message).join(',')
+ %(#{html_tag}<span class="validation-error">&nbsp;#{errors}</span>).html_safe
end
</ruby>
@@ -949,6 +956,7 @@ h4. Creating an Object
* +before_validation+
* +after_validation+
* +before_save+
+* +around_save+
* +before_create+
* +around_create+
* +after_create+
@@ -959,6 +967,7 @@ h4. Updating an Object
* +before_validation+
* +after_validation+
* +before_save+
+* +around_save+
* +before_update+
* +around_update+
* +after_update+
@@ -967,8 +976,8 @@ h4. Updating an Object
h4. Destroying an Object
* +before_destroy+
-* +after_destroy+
* +around_destroy+
+* +after_destroy+
WARNING. +after_save+ runs both on create and update, but always _after_ the more specific callbacks +after_create+ and +after_update+, no matter the order in which the macro calls were executed.
@@ -1013,7 +1022,7 @@ The following methods trigger callbacks:
* +increment!+
* +save+
* +save!+
-* +save(false)+
+* +save(:validate => false)+
* +toggle!+
* +update+
* +update_attribute+
diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile
index 851aac1a3f..37abb8a640 100644
--- a/railties/guides/source/active_resource_basics.textile
+++ b/railties/guides/source/active_resource_basics.textile
@@ -71,7 +71,7 @@ person.destroy
h3. Validations
-Module to support validation and errors with Active Resource objects. The module overrides Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned in the web service response. The module also adds an errors collection that mimics the interface of the errors provided by ActiveRecord::Errors.
+Module to support validation and errors with Active Resource objects. The module overrides Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned in the web service response. The module also adds an errors collection that mimics the interface of the errors provided by ActiveModel::Errors.
h4. Validating client side resources by overriding validation methods in base class
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index c77bc93cfb..bed14ef6a8 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -853,7 +853,7 @@ below:
</erb>
Now when you refresh the +/posts+ page, you'll see a gray background to the
-page. This same gray background will be used throughout all the views for posts.
+page. This same gray background will be used throughout all the views.
h4. Creating New Posts
@@ -1668,7 +1668,7 @@ right in the form where you create the post. First, create a new model to hold
the tags:
<shell>
-$ rails generate model tag name:string post:references
+$ rails generate model Tag name:string post:references
</shell>
Again, run the migration to create the database table:
diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile
index 16ad35f345..25201888e7 100644
--- a/railties/guides/source/i18n.textile
+++ b/railties/guides/source/i18n.textile
@@ -819,13 +819,13 @@ h5. Action View Helper Methods
* The +number_to_currency+, +number_with_precision+, +number_to_percentage+, +number_with_delimiter+, and +number_to_human_size+ helpers use the number format settings located in the "number":https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L2 scope.
-h5. Active Record Methods
+h5. Active Model Methods
* +model_name.human+ and +human_attribute_name+ use translations for model names and attribute names if available in the "activerecord.models":https://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml#L29 scope. They also support translations for inherited class names (e.g. for use with STI) as explained above in "Error message scopes".
-* +ActiveRecord::Errors#generate_message+ (which is used by Active Record validations but may also be used manually) uses +model_name.human+ and +human_attribute_name+ (see above). It also translates the error message and supports translations for inherited class names as explained above in "Error message scopes".
+* +ActiveModel::Errors#generate_message+ (which is used by Active Model validations but may also be used manually) uses +model_name.human+ and +human_attribute_name+ (see above). It also translates the error message and supports translations for inherited class names as explained above in "Error message scopes".
-* +ActiveRecord::Errors#full_messages+ prepends the attribute name to the error message using a separator that will be looked up from "activerecord.errors.format.separator":https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L91 (and which defaults to +'&nbsp;'+).
+* +ActiveModel::Errors#full_messages+ prepends the attribute name to the error message using a separator that will be looked up from "errors.format":https://github.com/rails/rails/blob/master/activemodel/lib/active_model/locale/en.yml#L4 (and which defaults to +"%{attribute} %{message}"+).
h5. Active Support Methods
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index b9944bed26..7da495211d 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -2,7 +2,6 @@ module Rails
class Application
module Finisher
include Initializable
- $rails_rake_task = nil
initializer :add_generator_templates do
config.generators.templates.unshift(*paths["lib/templates"].existent)
@@ -49,7 +48,7 @@ module Rails
end
initializer :eager_load! do
- if config.cache_classes && !$rails_rake_task
+ if config.cache_classes && !(defined?($rails_rake_task) && $rails_rake_task)
ActiveSupport.run_load_hooks(:before_eager_load, self)
eager_load!
end
diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb
index 20484a10c8..0b757cbe28 100644
--- a/railties/lib/rails/commands/server.rb
+++ b/railties/lib/rails/commands/server.rb
@@ -67,6 +67,13 @@ module Rails
FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make))
end
+ unless options[:daemonize]
+ wrapped_app # touch the app so the logger is set up
+
+ console = ActiveSupport::Logger.new($stdout)
+ Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
+ end
+
super
ensure
# The '-h' option calls exit before @options is set.
@@ -76,7 +83,6 @@ module Rails
def middleware
middlewares = []
- middlewares << [Rails::Rack::LogTailer, log_path] unless options[:daemonize]
middlewares << [Rails::Rack::Debugger] if options[:debugger]
middlewares << [::Rack::ContentLength]
Hash.new(middlewares)
@@ -89,6 +95,7 @@ module Rails
def default_options
super.merge({
:Port => 3000,
+ :DoNotReverseLookup => true,
:environment => (ENV['RAILS_ENV'] || "development").dup,
:daemonize => false,
:debugger => false,
diff --git a/railties/lib/rails/deprecation.rb b/railties/lib/rails/deprecation.rb
index 71adcd61f4..c5811b2629 100644
--- a/railties/lib/rails/deprecation.rb
+++ b/railties/lib/rails/deprecation.rb
@@ -1,39 +1,18 @@
-require "active_support/string_inquirer"
-require "active_support/basic_object"
+require 'active_support/deprecation/proxy_wrappers'
module Rails
- module Initializer
- def self.run(&block)
- klass = Class.new(Rails::Application)
- klass.instance_exec(klass.config, &block)
- klass.initialize!
- end
- end
-
- class DeprecatedConstant < ActiveSupport::BasicObject
- def self.deprecate(old, new)
- constant = self.new(old, new)
+ class DeprecatedConstant < ActiveSupport::Deprecation::DeprecatedConstantProxy
+ def self.deprecate(old, current)
+ constant = new(old, current)
eval "::#{old} = constant"
end
- def initialize(old, new)
- @old, @new = old, new
- @target = ::Kernel.eval "proc { #{@new} }"
- @warned = false
- end
-
- def method_missing(meth, *args, &block)
- ::ActiveSupport::Deprecation.warn("#{@old} is deprecated. Please use #{@new}") unless @warned
- @warned = true
+ private
- target = @target.call
- if target.respond_to?(meth)
- target.send(meth, *args, &block)
- else
- super
- end
+ def target
+ ::Kernel.eval @new_const.to_s
end
end
- DeprecatedConstant.deprecate("RAILS_CACHE", "::Rails.cache")
+ DeprecatedConstant.deprecate('RAILS_CACHE', '::Rails.cache')
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 20321a502d..77a68eb7f1 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -228,7 +228,7 @@ module Rails
# resources :articles
# end
#
- # The routes above will automatically point to <tt>MyEngine::ApplicationController</tt>. Furthermore, you don't
+ # The routes above will automatically point to <tt>MyEngine::ArticlesController</tt>. Furthermore, you don't
# need to use longer url helpers like <tt>my_engine_articles_path</tt>. Instead, you should simply use
# <tt>articles_path</tt> as you would do with your application.
#
diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb
index 96997021ee..29a2ad3111 100644
--- a/railties/lib/rails/generators/generated_attribute.rb
+++ b/railties/lib/rails/generators/generated_attribute.rb
@@ -32,8 +32,8 @@ module Rails
case type
when /(string|text|binary|integer)\{(\d+)\}/
return $1, :limit => $2.to_i
- when /decimal\{(\d+),(\d+)\}/
- return :decimal, :precision => $1.to_i, :scale => $2.to_i
+ when /decimal\{(\d+)(,|\.|\-)(\d+)\}/
+ return :decimal, :precision => $1.to_i, :scale => $3.to_i
else
return type, {}
end
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 712068a942..5e9c385ab8 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -2,8 +2,6 @@ source 'https://rubygems.org'
<%= rails_gemfile_entry -%>
-gem 'rack', :git => 'https://github.com/rack/rack.git'
-
<%= database_gemfile_entry -%>
<%= "gem 'jruby-openssl'\n" if defined?(JRUBY_VERSION) -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
index bcd3a2ad24..3517956e4a 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -13,9 +13,9 @@ require "active_resource/railtie"
<% end -%>
if defined?(Bundler)
- # If you precompile assets before deploying to production, use this line
+ # If you precompile assets before deploying to production, use this line.
Bundler.require(*Rails.groups(:assets => %w(development test)))
- # If you want your assets lazily compiled in production, use this line
+ # If you want your assets lazily compiled in production, use this line.
# Bundler.require(:default, :assets, Rails.env)
end
@@ -47,7 +47,7 @@ module <%= app_const_base %>
# Use SQL instead of Active Record's schema dumper when creating the database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
- # like if you have constraints or database-specific column types
+ # like if you have constraints or database-specific column types.
# config.active_record.schema_format = :sql
# Enforce whitelist mode for mass assignment.
@@ -57,10 +57,10 @@ module <%= app_const_base %>
# config.active_record.whitelist_attributes = true
<% unless options.skip_sprockets? -%>
- # Enable the asset pipeline
+ # Enable the asset pipeline.
config.assets.enabled = true
- # Version of your assets, change this if you want to expire all your assets
+ # Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
<% end -%>
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
index 5f7cc5af61..eb4dfa7c89 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -1,38 +1,38 @@
<%= app_const %>.configure do
- # Settings specified here will take precedence over those in config/application.rb
+ # Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
- # Show full error reports and disable caching
+ # Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
- # Don't care if the mailer can't send
+ # Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
- # Print deprecation notices to the Rails logger
+ # Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
- # Only use best-standards-support built into browsers
+ # Only use best-standards-support built into browsers.
config.action_dispatch.best_standards_support = :builtin
<%- unless options.skip_active_record? -%>
- # Raise exception on mass assignment protection for Active Record models
+ # Raise exception on mass assignment protection for Active Record models.
config.active_record.mass_assignment_sanitizer = :strict
# Log the query plan for queries taking more than this (works
- # with SQLite, MySQL, and PostgreSQL)
+ # with SQLite, MySQL, and PostgreSQL).
config.active_record.auto_explain_threshold_in_seconds = 0.5
<%- end -%>
<%- unless options.skip_sprockets? -%>
- # Do not compress assets
+ # Do not compress assets.
config.assets.compress = false
- # Expands the lines which load the assets
+ # Expands the lines which load the assets.
config.assets.debug = true
<%- end -%>
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 0f571f7c1a..e9a86d175e 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -1,73 +1,73 @@
<%= app_const %>.configure do
- # Settings specified here will take precedence over those in config/application.rb
+ # Settings specified here will take precedence over those in config/application.rb.
- # Code is not reloaded between requests
+ # Code is not reloaded between requests.
config.cache_classes = true
- # Full error reports are disabled and caching is turned on
+ # Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
- # Disable Rails's static asset server (Apache or nginx will already do this)
+ # Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_assets = false
<%- unless options.skip_sprockets? -%>
- # Compress JavaScripts and CSS
+ # Compress JavaScripts and CSS.
config.assets.compress = true
- # Don't fallback to assets pipeline if a precompiled asset is missed
+ # Don't fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
- # Generate digests for assets URLs
+ # Generate digests for assets URLs.
config.assets.digest = true
- # Defaults to Rails.root.join("public/assets")
+ # Defaults to Rails.root.join("public/assets").
# config.assets.manifest = YOUR_PATH
<%- end -%>
- # Specifies the header that your server uses for sending files
+ # Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
- # See everything in the log (default is :info)
+ # See everything in the log (default is :info).
# config.log_level = :debug
- # Prepend all log lines with the following tags
+ # Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
- # Use a different logger for distributed setups
+ # Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
- # Use a different cache store in production
+ # Use a different cache store in production.
# config.cache_store = :mem_cache_store
- # Enable serving of images, stylesheets, and JavaScripts from an asset server
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = "http://assets.example.com"
<%- unless options.skip_sprockets? -%>
- # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
+ # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added).
# config.assets.precompile += %w( search.js )
<%- end -%>
- # Disable delivery errors, bad email addresses will be ignored
+ # Disable delivery errors, bad email addresses will be ignored.
# config.action_mailer.raise_delivery_errors = false
- # Enable threaded mode
+ # Enable threaded mode.
# config.threadsafe!
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
- # the I18n.default_locale when a translation can not be found)
+ # the I18n.default_locale when a translation can not be found).
config.i18n.fallbacks = true
- # Send deprecation notices to registered listeners
+ # Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
<%- unless options.skip_active_record? -%>
# Log the query plan for queries taking more than this (works
- # with SQLite, MySQL, and PostgreSQL)
+ # with SQLite, MySQL, and PostgreSQL).
# config.active_record.auto_explain_threshold_in_seconds = 0.5
<%- end -%>
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
index 50656ac637..b725dd19f6 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
@@ -1,5 +1,5 @@
<%= app_const %>.configure do
- # Settings specified here will take precedence over those in config/application.rb
+ # Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
@@ -7,19 +7,19 @@
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
- # Configure static asset server for tests with Cache-Control for performance
+ # Configure static asset server for tests with Cache-Control for performance.
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
- # Show full error reports and disable caching
+ # Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
- # Raise exceptions instead of rendering exception templates
+ # Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
- # Disable request forgery protection in test environment
- config.action_controller.allow_forgery_protection = false
+ # Disable request forgery protection in test environment.
+ config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
@@ -27,10 +27,10 @@
config.action_mailer.delivery_method = :test
<%- unless options.skip_active_record? -%>
- # Raise exception on mass assignment protection for Active Record models
+ # Raise exception on mass assignment protection for Active Record models.
config.active_record.mass_assignment_sanitizer = :strict
<%- end -%>
- # Print deprecation notices to the stderr
+ # Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
end
diff --git a/railties/lib/rails/rack/log_tailer.rb b/railties/lib/rails/rack/log_tailer.rb
index 830d840894..18f22e8089 100644
--- a/railties/lib/rails/rack/log_tailer.rb
+++ b/railties/lib/rails/rack/log_tailer.rb
@@ -4,10 +4,13 @@ module Rails
def initialize(app, log = nil)
@app = app
- path = Pathname.new(log || "#{File.expand_path(Rails.root)}/log/#{Rails.env}.log").cleanpath
- @cursor = ::File.size(path)
+ path = Pathname.new(log || "#{::File.expand_path(Rails.root)}/log/#{Rails.env}.log").cleanpath
- @file = ::File.open(path, 'r')
+ @cursor = @file = nil
+ if ::File.exists?(path)
+ @cursor = ::File.size(path)
+ @file = ::File.open(path, 'r')
+ end
end
def call(env)
@@ -17,6 +20,7 @@ module Rails
end
def tail!
+ return unless @cursor
@file.seek @cursor
unless @file.eof?
diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb
index 68fbd58061..4e08e5dae1 100644
--- a/railties/test/generators/migration_generator_test.rb
+++ b/railties/test/generators/migration_generator_test.rb
@@ -105,14 +105,14 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
def test_add_migration_with_attributes_index_declaration_and_attribute_options
migration = "add_title_and_content_to_books"
- run_generator [migration, "title:string{40}:index", "content:string{255}", "price:decimal{5,2}:index", "discount:decimal{3,2}:uniq"]
+ run_generator [migration, "title:string{40}:index", "content:string{255}", "price:decimal{1,2}:index", "discount:decimal{3.4}:uniq"]
assert_migration "db/migrate/#{migration}.rb" do |content|
assert_method :change, content do |up|
assert_match(/add_column :books, :title, :string, limit: 40/, up)
assert_match(/add_column :books, :content, :string, limit: 255/, up)
- assert_match(/add_column :books, :price, :decimal, precision: 5, scale: 2/, up)
- assert_match(/add_column :books, :discount, :decimal, precision: 3, scale: 2/, up)
+ assert_match(/add_column :books, :price, :decimal, precision: 1, scale: 2/, up)
+ assert_match(/add_column :books, :discount, :decimal, precision: 3, scale: 4/, up)
end
assert_match(/add_index :books, :title/, content)
assert_match(/add_index :books, :price/, content)