diff options
15 files changed, 76 insertions, 25 deletions
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index b8b43ea9ef..44d2f740e6 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -263,7 +263,7 @@ module ActionController # The quality of the implementation depends on a good choice. # A nonce might, for example, be constructed as the base 64 encoding of # - # => time-stamp H(time-stamp ":" ETag ":" private-key) + # time-stamp H(time-stamp ":" ETag ":" private-key) # # where time-stamp is a server-generated time or other non-repeating value, # ETag is the value of the HTTP ETag header associated with the requested entity, diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index a288e69649..3e170d7872 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -6,7 +6,7 @@ require "abstract_controller/railties/routes_helpers" require "action_controller/railties/paths" module ActionController - class Railtie < Rails::Railtie + class Railtie < Rails::Railtie #:nodoc: config.action_controller = ActiveSupport::OrderedOptions.new initializer "action_controller.logger" do diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index de014a9c00..796e0dbc45 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -17,7 +17,8 @@ module ActionDispatch include ActionDispatch::Http::Upload include ActionDispatch::Http::URL - LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze + LOCALHOST = Regexp.union [/^127\.0\.0\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/] + ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE PATH_TRANSLATED REMOTE_HOST REMOTE_IDENT REMOTE_USER REMOTE_ADDR @@ -250,7 +251,7 @@ module ActionDispatch # True if the request came from localhost, 127.0.0.1. def local? - LOCALHOST.any? { |local_ip| local_ip === remote_addr && local_ip === remote_ip } + LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip end private diff --git a/actionpack/lib/action_dispatch/middleware/session/cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/cache_store.rb index d3b6fd12fa..1db6194271 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cache_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cache_store.rb @@ -1,5 +1,4 @@ require 'action_dispatch/middleware/session/abstract_store' -require 'rack/session/memcache' module ActionDispatch module Session diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 57c6972078..0ec4e41470 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -594,6 +594,7 @@ module ActionDispatch def recognize_path(path, environment = {}) method = (environment[:method] || "GET").to_s.upcase path = Journey::Router::Utils.normalize_path(path) unless path =~ %r{://} + extras = environment[:extras] || {} begin env = Rack::MockRequest.env_for(path, {:method => method}) @@ -603,6 +604,7 @@ module ActionDispatch req = @request_class.new(env) @router.recognize(req) do |route, matches, params| + params.merge!(extras) params.each do |key, value| if value.is_a?(String) value = value.dup.force_encoding(Encoding::BINARY) diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 1552676fbb..1f4b905d18 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -39,10 +39,9 @@ module ActionDispatch # # Test a custom route # assert_recognizes({:controller => 'items', :action => 'show', :id => '1'}, 'view/item1') def assert_recognizes(expected_options, path, extras={}, message=nil) - request = recognized_request_for(path) + request = recognized_request_for(path, extras) expected_options = expected_options.clone - extras.each_key { |key| expected_options.delete key } unless extras.nil? expected_options.stringify_keys! @@ -181,7 +180,7 @@ module ActionDispatch private # Recognizes the route for a given path. - def recognized_request_for(path) + def recognized_request_for(path, extras = {}) if path.is_a?(Hash) method = path[:method] path = path[:path] @@ -209,7 +208,7 @@ module ActionDispatch request.request_method = method if method - params = @routes.recognize_path(path, { :method => method }) + params = @routes.recognize_path(path, { :method => method, :extras => extras }) request.path_parameters = params.with_indifferent_access request diff --git a/actionpack/test/dispatch/routing_assertions_test.rb b/actionpack/test/dispatch/routing_assertions_test.rb index 9f95d82129..e953029456 100644 --- a/actionpack/test/dispatch/routing_assertions_test.rb +++ b/actionpack/test/dispatch/routing_assertions_test.rb @@ -3,6 +3,7 @@ require 'controller/fake_controllers' class SecureArticlesController < ArticlesController; end class BlockArticlesController < ArticlesController; end +class QueryArticlesController < ArticlesController; end class RoutingAssertionsTest < ActionController::TestCase @@ -18,6 +19,10 @@ class RoutingAssertionsTest < ActionController::TestCase scope 'block', :constraints => lambda { |r| r.ssl? } do resources :articles, :controller => 'block_articles' end + + scope 'query', :constraints => lambda { |r| r.params[:use_query] == 'true' } do + resources :articles, :controller => 'query_articles' + end end end @@ -62,6 +67,13 @@ class RoutingAssertionsTest < ActionController::TestCase assert_recognizes({ :controller => 'block_articles', :action => 'index' }, 'https://test.host/block/articles') end + def test_assert_recognizes_with_query_constraint + assert_raise(ActionController::RoutingError) do + assert_recognizes({ :controller => 'query_articles', :action => 'index', :use_query => 'false' }, '/query/articles', { :use_query => 'false' }) + end + assert_recognizes({ :controller => 'query_articles', :action => 'index', :use_query => 'true' }, '/query/articles', { :use_query => 'true' }) + end + def test_assert_routing assert_routing('/articles', :controller => 'articles', :action => 'index') end diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index 20372c5c18..ac31b636db 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -58,6 +58,7 @@ module ActiveRecord end time = time.in_time_zone rescue nil if time write_attribute(:#{attr_name}, original_time) + #{attr_name}_will_change! @attributes_cache["#{attr_name}"] = time end EOV diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index 9e21039c4f..6bf0becad8 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -248,10 +248,18 @@ module ActiveRecord # exception is raised. If omitted, any number associations can be processed. # Note that the :limit option is only applicable to one-to-many associations. # [:update_only] - # Allows you to specify that an existing record may only be updated. - # A new record may only be created when there is no existing record. - # This option only works for one-to-one associations and is ignored for - # collection associations. This option is off by default. + # For a one-to-one association, this option allows you to specify how + # nested attributes are to be used when an associated record already + # exists. In general, an existing record may either be updated with the + # new set of attribute values or be replaced by a wholly new record + # containing those values. By default the :update_only option is +false+ + # and the nested attributes are used to update the existing record only + # if they include the record's <tt>:id</tt> value. Otherwise a new + # record will be instantiated and used to replace the existing one. + # However if the :update_only option is +true+, the nested attributes + # are used to update the record's attributes always, regardless of + # whether the <tt>:id</tt> is present. The option is ignored for collection + # associations. # # Examples: # # creates avatar_attributes= @@ -312,10 +320,13 @@ module ActiveRecord # Assigns the given attributes to the association. # - # If update_only is false and the given attributes include an <tt>:id</tt> - # that matches the existing record's id, then the existing record will be - # modified. If update_only is true, a new record is only created when no - # object exists. Otherwise a new record will be built. + # If an associated record does not yet exist, one will be instantiated. If + # an associated record already exists, the method's behavior depends on + # the value of the update_only option. If update_only is +false+ and the + # given attributes include an <tt>:id</tt> that matches the existing record's + # id, then the existing record will be modified. If no <tt>:id</tt> is provided + # it will be replaced with a new record. If update_only is +true+ the existing + # record will be modified regardless of whether an <tt>:id</tt> is provided. # # If the given attributes include a matching <tt>:id</tt> attribute, or # update_only is true, and a <tt>:_destroy</tt> key set to a truthy value, diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 4078b7eb0b..23bdb09514 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -625,6 +625,16 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end + def test_time_zone_aware_attribute_saved + in_time_zone 1 do + record = @target.create(:written_on => '2012-02-20 10:00') + + record.written_on = '2012-02-20 09:00' + record.save + assert_equal Time.zone.local(2012, 02, 20, 9), record.reload.written_on + end + end + def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil in_time_zone "Pacific Time (US & Canada)" do record = @target.new diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index c630bd21b1..48ea5653c7 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -209,12 +209,10 @@ module ActiveSupport def constantize(camel_cased_word) #:nodoc: names = camel_cased_word.split('::') names.shift if names.empty? || names.first.empty? - - constant = Object - names.each do |name| - constant = constant.const_get(name, false) + + names.inject(Object) do |constant, name| + constant.const_get(name, false) end - constant end # Tries to find a constant with the name specified in the argument string: diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index 72ac8d2db9..349d02c1f6 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -517,6 +517,18 @@ class Person < ActiveRecord::Base end </ruby> +h3. Strict Validations + +You can also specify validations to be strict and raise +ActiveModel::StrictValidationFailed+ when the object is invalid. + +<ruby> +class Person < ActiveRecord::Base + validates :name, :presence => { :strict => true } +end + +Person.new.valid? => ActiveModel::StrictValidationFailed: Name can't be blank +</ruby> + h3. Conditional Validation Sometimes it will make sense to validate an object just when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string or a +Proc+. You may use the +:if+ option when you want to specify when the validation *should* happen. If you want to specify when the validation *should not* happen, then you may use the +:unless+ option. diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile index 6419d32c13..e2c6c7a2a4 100644 --- a/railties/guides/source/caching_with_rails.textile +++ b/railties/guides/source/caching_with_rails.textile @@ -359,7 +359,7 @@ h4. ActiveSupport::Cache::NullStore This cache store implementation is meant to be used only in development or test environments and it never stores anything. This can be very useful in development when you have code that interacts directly with +Rails.cache+, but caching may interfere with being able to see the results of code changes. With this cache store, all +fetch+ and +read+ operations will result in a miss. <ruby> -ActionController::Base.cache_store = :null +ActionController::Base.cache_store = :null_store </ruby> h4. Custom Cache Stores diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile index be352cfe3d..4b4f9f3745 100644 --- a/railties/guides/source/layouts_and_rendering.textile +++ b/railties/guides/source/layouts_and_rendering.textile @@ -359,7 +359,7 @@ class ProductsController < ApplicationController end </ruby> -With this declaration, all of the methods within +ProductsController+ will use +app/views/layouts/inventory.html.erb+ for their layout. +With this declaration, all of the views rendered by the products controller will use +app/views/layouts/inventory.html.erb+ as their layout. To assign a specific layout for the entire application, use a +layout+ declaration in your +ApplicationController+ class: diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index df2bd9d0c9..42665114be 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -295,12 +295,18 @@ In this case, Rails will see that +@magazine+ is a +Magazine+ and +@ad+ is an +A <%= link_to "Ad details", [@magazine, @ad] %> </erb> -If you wanted to link to just a magazine, you could leave out the +Array+: +If you wanted to link to just a magazine: <erb> <%= link_to "Magazine details", @magazine %> </erb> +For other actions, you just need to insert the action name as the first element of the array: + +<erb> +<%= link_to "Edit Ad", [:edit, @magazine, @ad] %> +</erb> + This allows you to treat instances of your models as URLs, and is a key advantage to using the resourceful style. h4. Adding More RESTful Actions |