diff options
42 files changed, 384 insertions, 348 deletions
@@ -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 7d8852f961..457ee24a0f 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -409,7 +409,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 +602,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,7 +609,8 @@ 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| + class_default = self.class.default + default_values = class_default.merge(class_default) do |k,v| v.respond_to?(:call) ? v.bind(self).call : v end 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_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/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..e095f832d1 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -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/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/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/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/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/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/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/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 87a3a0deb9..87482e4181 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1893,7 +1893,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/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..82046a39fb 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>, 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/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/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/railties/guides/code/getting_started/config/application.rb b/railties/guides/code/getting_started/config/application.rb index dad91d7943..d2cd5c028b 100644 --- a/railties/guides/code/getting_started/config/application.rb +++ b/railties/guides/code/getting_started/config/application.rb @@ -37,7 +37,7 @@ 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 # Enforce whitelist mode for mass assignment. @@ -46,10 +46,10 @@ module Blog # parameters by using an attr_accessible or attr_protected declaration. # config.active_record.whitelist_attributes = true - # 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/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 e97f82c6bd..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 - # 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 - # Print deprecation notices to the stderr + # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr end 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/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/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) |