aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md6
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb4
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb2
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb7
-rw-r--r--actionpack/lib/action_controller/railtie.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb5
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/request_id.rb5
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cache_store.rb1
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb6
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb68
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb8
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb7
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/tags/base.rb5
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb23
-rw-r--r--actionpack/lib/action_view/renderer/partial_renderer.rb2
-rw-r--r--actionpack/test/abstract/layouts_test.rb12
-rw-r--r--actionpack/test/controller/base_test.rb8
-rw-r--r--actionpack/test/controller/render_test.rb8
-rw-r--r--actionpack/test/controller/routing_test.rb6
-rw-r--r--actionpack/test/dispatch/routing_assertions_test.rb12
-rw-r--r--actionpack/test/template/form_options_helper_test.rb9
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb10
-rw-r--r--actionpack/test/template/sprockets_helper_with_routes_test.rb4
-rw-r--r--activemodel/CHANGELOG.md4
-rw-r--r--activemodel/README.rdoc19
-rw-r--r--activemodel/lib/active_model.rb1
-rw-r--r--activemodel/lib/active_model/model.rb76
-rw-r--r--activemodel/test/cases/model_test.rb26
-rw-r--r--activerecord/CHANGELOG.md4
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb2
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb27
-rw-r--r--activerecord/test/cases/adapters/sqlite3/quoting_test.rb9
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb10
-rw-r--r--activeresource/CHANGELOG.md4
-rw-r--r--activesupport/CHANGELOG.md4
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb36
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb8
-rw-r--r--activesupport/test/safe_buffer_test.rb38
-rw-r--r--railties/CHANGELOG.md4
-rw-r--r--railties/guides/source/routing.textile4
47 files changed, 400 insertions, 114 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 74a8d9f78a..96ad3a155c 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -111,7 +111,7 @@
HTML5 `mark` element. *Brian Cardarella*
-## Rails 3.2.2 (unreleased) ##
+## Rails 3.2.2 (March 1, 2012) ##
* Format lookup for partials is derived from the format in which the template is being rendered. Closes #5025 part 2 *Santiago Pastorino*
@@ -301,7 +301,7 @@
returned by the class method attribute_names will be wrapped. This fixes
the wrapping of nested attributes by adding them to attr_accessible.
-## Rails 3.1.4 (unreleased) ##
+## Rails 3.1.4 (March 1, 2012) ##
* Skip assets group in Gemfile and all assets configurations options
when the application is generated with --skip-sprockets option.
@@ -603,7 +603,7 @@
* Add Rack::Cache to the default stack. Create a Rails store that delegates to the Rails cache, so by default, whatever caching layer you are using will be used for HTTP caching. Note that Rack::Cache will be used if you use #expires_in, #fresh_when or #stale with :public => true. Otherwise, the caching rules will apply to the browser only. *Yehuda Katz, Carl Lerche*
-## Rails 3.0.12 (unreleased) ##
+## Rails 3.0.12 (March 1, 2012) ##
* Fix using `tranlate` helper with a html translation which uses the `:count` option for
pluralization.
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index aa39e21ba9..92e93cbee7 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -280,6 +280,10 @@ module AbstractController
<<-RUBY
lookup_context.find_all("#{_implied_layout_name}", #{prefixes.inspect}).first || super
RUBY
+ else
+ <<-RUBY
+ super
+ RUBY
end
layout_definition = case _layout
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/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 0b40b1fc4c..1177a703b3 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -1,7 +1,7 @@
-# Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
+# Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
# the <tt>_routes</tt> method. Otherwise, an exception will be raised.
#
-# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
+# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
# url options like the +host+. In order to do so, this module requires the host class
# to implement +env+ and +request+, which need to be a Rack-compatible.
#
@@ -18,7 +18,7 @@
# @url = root_path # named route from the application.
# end
# end
-#
+#
module ActionController
module UrlFor
extend ActiveSupport::Concern
@@ -42,6 +42,5 @@ module ActionController
@_url_options
end
end
-
end
end
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/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 80ffbe575b..f9dae5dad7 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -40,7 +40,9 @@ module ActionDispatch
rewritten_url << ":#{options.delete(:port)}" if options[:port]
end
- path = options.delete(:path) || ''
+ path = ""
+ path << options.delete(:script_name).to_s.chomp("/")
+ path << options.delete(:path).to_s
params = options[:params] || {}
params.reject! {|k,v| v.to_param.nil? }
diff --git a/actionpack/lib/action_dispatch/middleware/request_id.rb b/actionpack/lib/action_dispatch/middleware/request_id.rb
index d5a0b80fd5..6fff94707c 100644
--- a/actionpack/lib/action_dispatch/middleware/request_id.rb
+++ b/actionpack/lib/action_dispatch/middleware/request_id.rb
@@ -19,10 +19,7 @@ module ActionDispatch
def call(env)
env["action_dispatch.request_id"] = external_request_id(env) || internal_request_id
- status, headers, body = @app.call(env)
-
- headers["X-Request-Id"] = env["action_dispatch.request_id"]
- [ status, headers, body ]
+ @app.call(env).tap { |status, headers, body| headers["X-Request-Id"] = env["action_dispatch.request_id"] }
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/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index 35f901c575..62f906219c 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -16,7 +16,7 @@ module ActionDispatch
config.action_dispatch.rack_cache = {
:metastore => "rails:/",
:entitystore => "rails:/",
- :verbose => true
+ :verbose => false
}
initializer "action_dispatch.configure" do |app|
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 02a27110e4..80fcdab643 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -446,7 +446,11 @@ module ActionDispatch
_route = @set.named_routes.routes[name.to_sym]
_routes = @set
app.routes.define_mounted_helper(name)
- app.routes.class_eval do
+ app.routes.singleton_class.class_eval do
+ define_method :mounted? do
+ true
+ end
+
define_method :_generate_prefix do |options|
prefix_options = options.slice(*_route.segment_keys)
# we must actually delete prefix segment keys to avoid passing them to next url_for
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 57c6972078..30e9e5634b 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -191,14 +191,50 @@ module ActionDispatch
selector = url_helper_name(name, kind)
hash_access_method = hash_access_name(name, kind)
- @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
- remove_possible_method :#{selector}
- def #{selector}(*args)
- url_for(#{hash_access_method}(*args))
- end
- END_EVAL
+ if optimize_helper?(route)
+ @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
+ remove_possible_method :#{selector}
+ def #{selector}(*args)
+ if args.size == #{route.required_parts.size} && !args.last.is_a?(Hash) && optimize_routes_generation?
+ options = #{options.inspect}.merge!(url_options)
+ options[:path] = "#{optimized_helper(route)}"
+ ActionDispatch::Http::URL.url_for(options)
+ else
+ url_for(#{hash_access_method}(*args))
+ end
+ end
+ END_EVAL
+ else
+ @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
+ remove_possible_method :#{selector}
+ def #{selector}(*args)
+ url_for(#{hash_access_method}(*args))
+ end
+ END_EVAL
+ end
+
helpers << selector
end
+
+ # Clause check about when we need to generate an optimized helper.
+ def optimize_helper?(route) #:nodoc:
+ route.ast.grep(Journey::Nodes::Star).empty? && route.requirements.except(:controller, :action).empty?
+ end
+
+ # Generates the interpolation to be used in the optimized helper.
+ def optimized_helper(route)
+ string_route = route.ast.to_s
+
+ while string_route.gsub!(/\([^\)]*\)/, "")
+ true
+ end
+
+ route.required_parts.each_with_index do |part, i|
+ string_route.gsub!(part.inspect, "\#{Journey::Router::Utils.escape_fragment(args[#{i}].to_param)}")
+ end
+
+ string_route
+ end
end
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
@@ -323,7 +359,7 @@ module ActionDispatch
# Rails.application.routes.url_helpers.url_for(args)
@_routes = routes
class << self
- delegate :url_for, :to => '@_routes'
+ delegate :url_for, :optimize_routes_generation?, :to => '@_routes'
end
# Make named_routes available in the module singleton
@@ -557,6 +593,14 @@ module ActionDispatch
RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
:trailing_slash, :anchor, :params, :only_path, :script_name]
+ def mounted?
+ false
+ end
+
+ def optimize_routes_generation?
+ !mounted? && default_url_options.empty?
+ end
+
def _generate_prefix(options = {})
nil
end
@@ -568,19 +612,17 @@ module ActionDispatch
user, password = extract_authentication(options)
path_segments = options.delete(:_path_segments)
- script_name = options.delete(:script_name)
-
- path = (script_name.blank? ? _generate_prefix(options) : script_name.chomp('/')).to_s
+ script_name = options.delete(:script_name).presence || _generate_prefix(options)
path_options = options.except(*RESERVED_OPTIONS)
path_options = yield(path_options) if block_given?
- path_addition, params = generate(path_options, path_segments || {})
- path << path_addition
+ path, params = generate(path_options, path_segments || {})
params.merge!(options[:params] || {})
ActionDispatch::Http::URL.url_for(options.merge!({
:path => path,
+ :script_name => script_name,
:params => params,
:user => user,
:password => password
@@ -594,6 +636,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 +646,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/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index ee6616c5d3..94db36ce1f 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -102,6 +102,9 @@ module ActionDispatch
super
end
+ # Hook overriden in controller to add request information
+ # with `default_url_options`. Application logic should not
+ # go into url_options.
def url_options
default_url_options
end
@@ -152,6 +155,11 @@ module ActionDispatch
protected
+ def optimize_routes_generation?
+ return @_optimized_routes if defined?(@_optimized_routes)
+ @_optimized_routes = _routes.optimize_routes_generation? && default_url_options.empty?
+ end
+
def _with_routes(routes)
old_routes, @_routes = @_routes, routes
yield
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/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 17bbfe2efd..278139cadb 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -215,7 +215,7 @@ module ActionView
def flush_output_buffer #:nodoc:
if output_buffer && !output_buffer.empty?
response.body_parts << output_buffer
- self.output_buffer = output_buffer[0,0]
+ self.output_buffer = output_buffer.respond_to?(:clone_empty) ? output_buffer.clone_empty : output_buffer[0, 0]
nil
end
end
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 2cf1c9055c..9fad30a48f 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -525,10 +525,9 @@ module ActionView
# <% end %>
# # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
def field_set_tag(legend = nil, options = nil, &block)
- content = capture(&block)
output = tag(:fieldset, options, true)
output.safe_concat(content_tag(:legend, legend)) unless legend.blank?
- output.concat(content)
+ output.concat(capture(&block)) if block_given?
output.safe_concat("</fieldset>")
end
diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb
index c9c891daa1..22c16de057 100644
--- a/actionpack/lib/action_view/helpers/tags/base.rb
+++ b/actionpack/lib/action_view/helpers/tags/base.rb
@@ -133,12 +133,11 @@ module ActionView
def add_options(option_tags, options, value = nil)
if options[:include_blank]
- include_blank = options[:include_blank] if options[:include_blank].kind_of?(String)
- option_tags = content_tag(:option, include_blank, :value => '').safe_concat("\n").safe_concat(option_tags)
+ option_tags = content_tag('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\n" + option_tags
end
if value.blank? && options[:prompt]
prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select')
- option_tags = content_tag(:option, prompt, :value => '').safe_concat("\n").safe_concat(option_tags)
+ option_tags = content_tag('option', prompt, :value => '') + "\n" + option_tags
end
option_tags
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 8d7417809b..f4946e65b5 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -23,20 +23,25 @@ module ActionView
include ActionDispatch::Routing::UrlFor
include TagHelper
- def _routes_context
- controller
- end
+ # We need to override url_optoins, _routes_context
+ # and optimize_routes_generation? to consider the controller.
- # Need to map default url options to controller one.
- # def default_url_options(*args) #:nodoc:
- # controller.send(:default_url_options, *args)
- # end
- #
- def url_options
+ def url_options #:nodoc:
return super unless controller.respond_to?(:url_options)
controller.url_options
end
+ def _routes_context #:nodoc:
+ controller
+ end
+ protected :_routes_context
+
+ def optimize_routes_generation? #:nodoc:
+ controller.respond_to?(:optimize_routes_generation?) ?
+ controller.optimize_routes_generation? : super
+ end
+ protected :optimize_routes_generation?
+
# Returns the URL for the set of +options+ provided. This takes the
# same options as +url_for+ in Action Controller (see the
# documentation for <tt>ActionController::Base#url_for</tt>). Note that by default
diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb
index 3033294883..3628b935b7 100644
--- a/actionpack/lib/action_view/renderer/partial_renderer.rb
+++ b/actionpack/lib/action_view/renderer/partial_renderer.rb
@@ -272,6 +272,8 @@ module ActionView
@block = block
@details = extract_details(options)
+ @lookup_context.rendered_format ||= formats.first
+
if String === partial
@object = options[:object]
@path = partial
diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb
index fc25718d9e..e07a6de4a9 100644
--- a/actionpack/test/abstract/layouts_test.rb
+++ b/actionpack/test/abstract/layouts_test.rb
@@ -299,6 +299,18 @@ module AbstractControllerTests
controller.process(:index)
assert_equal "Overwrite Hello index!", controller.response_body
end
+
+ test "layout for anonymous controller" do
+ klass = Class.new(WithString) do
+ def index
+ render :text => 'index', :layout => true
+ end
+ end
+
+ controller = klass.new
+ controller.process(:index)
+ assert_equal "With String index", controller.response_body
+ end
end
end
end
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index 791edb9069..7d0609751f 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -56,7 +56,7 @@ class UrlOptionsController < ActionController::Base
end
def url_options
- super.merge(:host => 'www.override.com', :action => 'new', :locale => 'en')
+ super.merge(:host => 'www.override.com')
end
end
@@ -183,9 +183,9 @@ class UrlOptionsTest < ActionController::TestCase
get :from_view, :route => "from_view_url"
- assert_equal 'http://www.override.com/from_view?locale=en', @response.body
- assert_equal 'http://www.override.com/from_view?locale=en', @controller.send(:from_view_url)
- assert_equal 'http://www.override.com/default_url_options/new?locale=en', @controller.url_for(:controller => 'default_url_options')
+ assert_equal 'http://www.override.com/from_view', @response.body
+ assert_equal 'http://www.override.com/from_view', @controller.send(:from_view_url)
+ assert_equal 'http://www.override.com/default_url_options/index', @controller.url_for(:controller => 'default_url_options')
end
end
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index e040878b26..8167fc2fd2 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -1246,22 +1246,26 @@ class RenderTest < ActionController::TestCase
def test_partial_only
get :partial_only
assert_equal "only partial", @response.body
+ assert_equal "text/html", @response.content_type
end
def test_should_render_html_formatted_partial
get :partial
- assert_equal 'partial html', @response.body
+ assert_equal "partial html", @response.body
+ assert_equal "text/html", @response.content_type
end
def test_should_render_html_partial_with_formats
get :partial_formats_html
- assert_equal 'partial html', @response.body
+ assert_equal "partial html", @response.body
+ assert_equal "text/html", @response.content_type
end
def test_render_to_string_partial
get :render_to_string_with_partial
assert_equal "only partial", assigns(:partial_only)
assert_equal "Hello: david", assigns(:partial_with_locals)
+ assert_equal "text/html", @response.content_type
end
def test_partial_with_counter
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index 843ae1a813..2a7c1f86c6 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -59,11 +59,11 @@ end
class MockController
def self.build(helpers)
Class.new do
- def url_for(options)
+ def url_options
+ options = super
options[:protocol] ||= "http"
options[:host] ||= "test.host"
-
- super(options)
+ options
end
include helpers
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/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 6b8d62df62..606d454cb3 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -509,7 +509,7 @@ class FormOptionsHelperTest < ActionView::TestCase
def test_select_under_fields_for_with_string_and_given_prompt
@post = Post.new
- options = "<option value=\"abe\">abe</option><option value=\"mus\">mus</option><option value=\"hest\">hest</option>"
+ options = "<option value=\"abe\">abe</option><option value=\"mus\">mus</option><option value=\"hest\">hest</option>".html_safe
output_buffer = fields_for :post, @post do |f|
concat f.select(:category, options, :prompt => 'The prompt')
@@ -665,6 +665,13 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_select_escapes_options
+ assert_dom_equal(
+ '<select id="post_title" name="post[title]">&lt;script&gt;alert(1)&lt;/script&gt;</select>',
+ select('post', 'title', '<script>alert(1)</script>')
+ )
+ end
+
def test_select_with_selected_nil
@post = Post.new
@post.category = "<mus>"
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 6ef4cf4dd2..590a1967c5 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -513,6 +513,16 @@ class FormTagHelperTest < ActionView::TestCase
expected = %(<fieldset class="format">Hello world!</fieldset>)
assert_dom_equal expected, output_buffer
+
+ output_buffer = render_erb("<%= field_set_tag %>")
+
+ expected = %(<fieldset></fieldset>)
+ assert_dom_equal expected, output_buffer
+
+ output_buffer = render_erb("<%= field_set_tag('You legend!') %>")
+
+ expected = %(<fieldset><legend>You legend!</legend></fieldset>)
+ assert_dom_equal expected, output_buffer
end
def test_text_area_tag_options_symbolize_keys_side_effects
diff --git a/actionpack/test/template/sprockets_helper_with_routes_test.rb b/actionpack/test/template/sprockets_helper_with_routes_test.rb
index bcbd81a7dd..89b9940eb7 100644
--- a/actionpack/test/template/sprockets_helper_with_routes_test.rb
+++ b/actionpack/test/template/sprockets_helper_with_routes_test.rb
@@ -17,7 +17,7 @@ class SprocketsHelperWithRoutesTest < ActionView::TestCase
def setup
super
- @controller = BasicController.new
+ @controller = BasicController.new
@assets = Sprockets::Environment.new
@assets.append_path(FIXTURES.join("sprockets/app/javascripts"))
@@ -34,7 +34,7 @@ class SprocketsHelperWithRoutesTest < ActionView::TestCase
test "namespace conflicts on a named route called asset_path" do
# Testing this for sanity - asset_path is now a named route!
- assert_match asset_path('test_asset'), '/assets/test_asset'
+ assert_equal asset_path('test_asset'), '/assets/test_asset'
assert_match %r{/assets/logo-[0-9a-f]+.png},
path_to_asset("logo.png")
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 0d70edd0ba..42adbec8b9 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,5 @@
+* Added ActiveModel::Model, a mixin to make Ruby objects work with AP out of box *Guillermo Iguaran*
+
* `AM::Errors#to_json`: support `:full_messages` parameter *Bogdan Gusiev*
* Trim down Active Model API by removing `valid?` and `errors.full_messages` *José Valim*
@@ -61,7 +63,7 @@
* Add support for selectively enabling/disabling observers *Myron Marston*
-## Rails 3.0.12 (unreleased) ##
+## Rails 3.0.12 (March 1, 2012) ##
* No changes.
diff --git a/activemodel/README.rdoc b/activemodel/README.rdoc
index a7ba27ba73..9b121510a9 100644
--- a/activemodel/README.rdoc
+++ b/activemodel/README.rdoc
@@ -13,6 +13,25 @@ in code duplication and fragile applications that broke on upgrades. Active
Model solves this by defining an explicit API. You can read more about the
API in ActiveModel::Lint::Tests.
+Active Model provides a default module that implements the basic API required
+to integrate with Action Pack out of the box: +ActiveModel::Model+.
+
+ class Person
+ include ActiveModel::Model
+
+ attr_accessor :name, :age
+ validates_presence_of :name
+ end
+
+ person = Person.new(:name => 'bob', :age => '18')
+ person.name # => 'bob'
+ person.age # => 18
+ person.valid? # => false
+
+It includes model name instrospection, conversions, translations and
+validations, resulting in a class suitable to be used with ActionPack.
+See +ActiveModel::Model+ for more examples.
+
Active Model also provides the following functionality to have ORM-like
behavior out of the box:
diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb
index 85514e63fd..2586147a20 100644
--- a/activemodel/lib/active_model.rb
+++ b/activemodel/lib/active_model.rb
@@ -39,6 +39,7 @@ module ActiveModel
autoload :Errors
autoload :Lint
autoload :MassAssignmentSecurity
+ autoload :Model
autoload :Name, 'active_model/naming'
autoload :Naming
autoload :Observer, 'active_model/observing'
diff --git a/activemodel/lib/active_model/model.rb b/activemodel/lib/active_model/model.rb
new file mode 100644
index 0000000000..8445113b64
--- /dev/null
+++ b/activemodel/lib/active_model/model.rb
@@ -0,0 +1,76 @@
+module ActiveModel
+
+ # == Active Model Basic Model
+ #
+ # Includes the required interface for an object to interact with +ActionPack+,
+ # using different +ActiveModel+ modules. It includes model name instrospection,
+ # conversions, translations and validations . Besides that, it allows you to
+ # initialize the object with a hash of attributes, pretty much like
+ # +ActiveRecord+ does.
+ #
+ # A minimal implementation could be:
+ #
+ # class Person
+ # include ActiveModel::Model
+ # attr_accessor :name, :age
+ # end
+ #
+ # person = Person.new(:name => 'bob', :age => '18')
+ # person.name # => 'bob'
+ # person.age # => 18
+ #
+ # Note that, by default, +ActiveModel::Model+ implements +persisted?+ to
+ # return +false+, which is the most common case. You may want to override it
+ # in your class to simulate a different scenario:
+ #
+ # class Person
+ # include ActiveModel::Model
+ # attr_accessor :id, :name
+ #
+ # def persisted?
+ # self.id == 1
+ # end
+ # end
+ #
+ # person = Person.new(:id => 1, :name => 'bob')
+ # person.persisted? # => true
+ #
+ # Also, if for some reason you need to run code on +initialize+, make sure you
+ # call super if you want the attributes hash initialization to happen.
+ #
+ # class Person
+ # include ActiveModel::Model
+ # attr_accessor :id, :name, :omg
+ #
+ # def initialize(attributes)
+ # super
+ # @omg ||= true
+ # end
+ # end
+ #
+ # person = Person.new(:id => 1, :name => 'bob')
+ # person.omg # => true
+ #
+ # For more detailed information on other functionality available, please refer
+ # to the specific modules included in +ActiveModel::Model+ (see below).
+ module Model
+ def self.included(base)
+ base.class_eval do
+ extend ActiveModel::Naming
+ extend ActiveModel::Translation
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ end
+ end
+
+ def initialize(params={})
+ params.each do |attr, value|
+ self.public_send("#{attr}=", value)
+ end if params
+ end
+
+ def persisted?
+ false
+ end
+ end
+end
diff --git a/activemodel/test/cases/model_test.rb b/activemodel/test/cases/model_test.rb
new file mode 100644
index 0000000000..d93fd96b88
--- /dev/null
+++ b/activemodel/test/cases/model_test.rb
@@ -0,0 +1,26 @@
+require 'cases/helper'
+
+class ModelTest < ActiveModel::TestCase
+ include ActiveModel::Lint::Tests
+
+ class BasicModel
+ include ActiveModel::Model
+ attr_accessor :attr
+ end
+
+ def setup
+ @model = BasicModel.new
+ end
+
+ def test_initialize_with_params
+ object = BasicModel.new(:attr => "value")
+ assert_equal object.attr, "value"
+ end
+
+ def test_initialize_with_nil_or_empty_hash_params_does_not_explode
+ assert_nothing_raised do
+ BasicModel.new()
+ BasicModel.new({})
+ end
+ end
+end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index cea50aaa9d..92e0b47469 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -320,7 +320,7 @@
*Aaron Christy*
- ## Rails 3.1.4 (unreleased) ##
+## Rails 3.1.4 (March 1, 2012) ##
* Fix a custom primary key regression *GH 3987*
@@ -779,7 +779,7 @@
*Aaron Patterson*
-## Rails 3.0.12 (unreleased) ##
+## Rails 3.0.12 (March 1, 2012) ##
* No changes.
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/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 6bac05191d..2c210e5ba2 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -539,8 +539,8 @@ module ActiveRecord
# ===== Examples
# add_timestamps(:suppliers)
def add_timestamps(table_name)
- add_column table_name, :created_at, :datetime, :null => false
- add_column table_name, :updated_at, :datetime, :null => false
+ add_column table_name, :created_at, :datetime
+ add_column table_name, :updated_at, :datetime
end
# Removes the timestamp columns (created_at and updated_at) from the table definition.
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index c6af682d28..594649189d 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -57,7 +57,7 @@ module ActiveRecord
define_callbacks :checkout, :checkin
attr_accessor :visitor, :pool
- attr_reader :schema_cache, :last_use, :in_use
+ attr_reader :schema_cache, :last_use, :in_use, :logger
alias :in_use? :in_use
def initialize(connection, logger = nil, pool = nil) #:nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index c85c4c6e51..3d8dfab05c 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -202,7 +202,7 @@ module ActiveRecord
value = super
if column.type == :string && value.encoding == Encoding::ASCII_8BIT
- @logger.error "Binary data inserted for `string` type on column `#{column.name}`"
+ logger.error "Binary data inserted for `string` type on column `#{column.name}`" if logger
value.encode! 'utf-8'
end
value
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/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
index 46da1b0a2b..1dbeb66af6 100644
--- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -1,6 +1,7 @@
require "cases/helper"
require 'bigdecimal'
require 'yaml'
+require 'securerandom'
module ActiveRecord
module ConnectionAdapters
@@ -12,6 +13,14 @@ module ActiveRecord
:timeout => 100
end
+ def test_type_cast_binary_encoding_without_logger
+ @conn.extend(Module.new { def logger; end })
+ column = Struct.new(:type, :name).new(:string, "foo")
+ binary = SecureRandom.hex
+ expected = binary.dup.encode!('utf-8')
+ assert_equal expected, @conn.type_cast(binary, column)
+ end
+
def test_type_cast_symbol
assert_equal 'foo', @conn.type_cast(:foo, nil)
end
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/activeresource/CHANGELOG.md b/activeresource/CHANGELOG.md
index e092621a33..f305c3fd4a 100644
--- a/activeresource/CHANGELOG.md
+++ b/activeresource/CHANGELOG.md
@@ -16,7 +16,7 @@
*Jim Herz*
-## Rails 3.1.4 (unreleased) ##
+## Rails 3.1.4 (March 1, 2012) ##
* No changes
@@ -44,7 +44,7 @@
end
-## Rails 3.0.12 (unreleased) ##
+## Rails 3.0.12 (March 1, 2012) ##
* No changes.
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 3e40e08ca2..09ec4ed618 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -111,7 +111,7 @@
filehandle, or tune your filesystem.
-## Rails 3.1.4 (unreleased) ##
+## Rails 3.1.4 (March 1, 2012) ##
* No changes
@@ -183,7 +183,7 @@
* JSON decoding now uses the multi_json gem which also vendors a json engine called OkJson. The yaml backend has been removed in favor of OkJson as a default engine for 1.8.x, while the built in 1.9.x json implementation will be used by default. *Josh Kalderimis*
-## Rails 3.0.12 (unreleased) ##
+## Rails 3.0.12 (March 1, 2012) ##
* No changes.
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index dd780da157..4903687b73 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -103,29 +103,39 @@ module ActiveSupport #:nodoc:
end
end
- def[](*args)
- new_safe_buffer = super
- new_safe_buffer.instance_eval { @dirty = false }
- new_safe_buffer
+ def [](*args)
+ return super if args.size < 2
+
+ if html_safe?
+ new_safe_buffer = super
+ new_safe_buffer.instance_eval { @html_safe = true }
+ new_safe_buffer
+ else
+ to_str[*args]
+ end
end
def safe_concat(value)
- raise SafeConcatError if dirty?
+ raise SafeConcatError unless html_safe?
original_concat(value)
end
def initialize(*)
- @dirty = false
+ @html_safe = true
super
end
def initialize_copy(other)
super
- @dirty = other.dirty?
+ @html_safe = other.html_safe?
+ end
+
+ def clone_empty
+ self[0, 0]
end
def concat(value)
- if dirty? || value.html_safe?
+ if !html_safe? || value.html_safe?
super(value)
else
super(ERB::Util.h(value))
@@ -138,7 +148,7 @@ module ActiveSupport #:nodoc:
end
def html_safe?
- !dirty?
+ defined?(@html_safe) && @html_safe
end
def to_s
@@ -161,18 +171,12 @@ module ActiveSupport #:nodoc:
end # end
def #{unsafe_method}!(*args) # def capitalize!(*args)
- @dirty = true # @dirty = true
+ @html_safe = false # @html_safe = false
super # super
end # end
EOT
end
end
-
- protected
-
- def dirty?
- @dirty
- end
end
end
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/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb
index bdde5141a9..047b89be2a 100644
--- a/activesupport/test/safe_buffer_test.rb
+++ b/activesupport/test/safe_buffer_test.rb
@@ -84,13 +84,13 @@ class SafeBufferTest < ActiveSupport::TestCase
assert_equal "hello&lt;&gt;", clean + @buffer
end
- test "Should concat as a normal string when dirty" do
+ test "Should concat as a normal string when safe" do
clean = "hello".html_safe
@buffer.gsub!('', '<>')
assert_equal "<>hello", @buffer + clean
end
- test "Should preserve dirty? status on copy" do
+ test "Should preserve html_safe? status on copy" do
@buffer.gsub!('', '<>')
assert !@buffer.dup.html_safe?
end
@@ -102,20 +102,42 @@ class SafeBufferTest < ActiveSupport::TestCase
assert_equal "<script>", result_buffer
end
- test "Should raise an error when safe_concat is called on dirty buffers" do
+ test "Should raise an error when safe_concat is called on unsafe buffers" do
@buffer.gsub!('', '<>')
assert_raise ActiveSupport::SafeBuffer::SafeConcatError do
@buffer.safe_concat "BUSTED"
end
end
- test "should not fail if the returned object is not a string" do
+ test "Should not fail if the returned object is not a string" do
assert_kind_of NilClass, @buffer.slice("chipchop")
end
- test "Should initialize @dirty to false for new instance when sliced" do
- dirty = @buffer[0,0].send(:dirty?)
- assert_not_nil dirty
- assert !dirty
+ test "clone_empty returns an empty buffer" do
+ assert_equal '', ActiveSupport::SafeBuffer.new('foo').clone_empty
+ end
+
+ test "clone_empty keeps the original dirtyness" do
+ assert @buffer.clone_empty.html_safe?
+ assert !@buffer.gsub!('', '').clone_empty.html_safe?
+ end
+
+ test "Should be safe when sliced if original value was safe" do
+ new_buffer = @buffer[0,0]
+ assert_not_nil new_buffer
+ assert new_buffer.html_safe?, "should be safe"
+ end
+
+ test "Should continue unsafe on slice" do
+ x = 'foo'.html_safe.gsub!('f', '<script>alert("lolpwnd");</script>')
+
+ # calling gsub! makes the dirty flag true
+ assert !x.html_safe?, "should not be safe"
+
+ # getting a slice of it
+ y = x[0..-1]
+
+ # should still be unsafe
+ assert !y.html_safe?, "should not be safe"
end
end
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index f556ee210d..960b1ed8ca 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -71,7 +71,7 @@
* Remove old 'config.paths.app.controller' API in favor of 'config.paths["app/controller"]' API *Guillermo Iguaran*
-## Rails 3.1.4 (unreleased) ##
+## Rails 3.1.4 (March 1, 2012) ##
* Setting config.force_ssl also marks the session cookie as secure.
@@ -203,7 +203,7 @@
* Include all helpers from plugins and shared engines in application *Piotr Sarnacki*
-## Rails 3.0.12 (unreleased) ##
+## Rails 3.0.12 (March 1, 2012) ##
* No changes.
diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile
index 24e7d09a49..42665114be 100644
--- a/railties/guides/source/routing.textile
+++ b/railties/guides/source/routing.textile
@@ -295,13 +295,13 @@ 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+:
+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] %>