aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--actionmailer/lib/action_mailer/base.rb3
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb9
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb16
-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/date_helper.rb16
-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/text_field.rb8
-rw-r--r--actionpack/test/abstract_unit.rb15
-rw-r--r--actionpack/test/controller/routing_test.rb82
-rw-r--r--actionpack/test/dispatch/cookies_test.rb11
-rw-r--r--actionpack/test/dispatch/routing_test.rb3
-rw-r--r--actionpack/test/template/date_helper_i18n_test.rb8
-rw-r--r--actionpack/test/template/date_helper_test.rb39
-rw-r--r--actionpack/test/template/form_helper_test.rb8
-rw-r--r--activemodel/lib/active_model/observing.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb3
-rw-r--r--activerecord/lib/active_record/counter_cache.rb6
-rw-r--r--activerecord/lib/active_record/relation.rb4
-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/base_test.rb8
-rw-r--r--activerecord/test/cases/helper.rb2
-rw-r--r--activerecord/test/cases/test_case.rb63
-rw-r--r--activeresource/lib/active_resource/base.rb137
-rw-r--r--activeresource/lib/active_resource/connection.rb42
-rw-r--r--activeresource/lib/active_resource/custom_methods.rb4
-rw-r--r--activeresource/lib/active_resource/http_mock.rb21
-rw-r--r--activeresource/test/cases/connection_test.rb1
-rw-r--r--activeresource/test/fixtures/street_address.rb2
-rw-r--r--activesupport/lib/active_support/callbacks.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb2
-rw-r--r--activesupport/test/callbacks_test.rb56
-rw-r--r--rails.gemspec2
-rw-r--r--railties/guides/source/active_record_querying.textile10
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile2
41 files changed, 514 insertions, 216 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/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 457ee24a0f..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'
@@ -611,7 +610,7 @@ module ActionMailer #:nodoc:
# Call all the procs (if any)
class_default = self.class.default
default_values = class_default.merge(class_default) do |k,v|
- v.respond_to?(:call) ? v.bind(self).call : v
+ v.respond_to?(:to_proc) ? instance_eval(&v) : v
end
# Handle defaults
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_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 5b7f1c989c..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
@@ -499,6 +503,16 @@ module ActionDispatch
private
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
match(*args, options, &block)
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/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index f5077b034a..db9f5f5e9d 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -734,7 +734,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 +742,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 +756,7 @@ module ActionView
def select_year
if !@datetime || @datetime == 0
- val = ''
+ val = '1'
middle_year = Date.today.year
else
val = middle_year = year
@@ -836,7 +836,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.
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/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/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/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/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index c6e6ed4d6b..8f843eb960 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -156,7 +156,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
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..b69c47b476 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,43 @@ 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
+
+ start_year = Time.now.year-5
+ end_year = Time.now.year+5
+
+ 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/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/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/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/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/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/base_test.rb b/activerecord/test/cases/base_test.rb
index 87482e4181..0ea1b824e1 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -992,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
@@ -1006,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
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/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 ed872c0883..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)
@@ -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 2a034f9269..46060b6f74 100644
--- a/activeresource/lib/active_resource/connection.rb
+++ b/activeresource/lib/active_resource/connection.rb
@@ -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/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/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..e42453389e 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -2,7 +2,7 @@ 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
def local_offset
- ::Time.local(2007).utc_offset.to_r / 86400
+ ::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/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/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/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile
index 5970a45839..84687e2e4f 100644
--- a/railties/guides/source/active_record_querying.textile
+++ b/railties/guides/source/active_record_querying.textile
@@ -965,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>
@@ -977,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
@@ -1000,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/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) -%>