diff options
Diffstat (limited to 'actionpack')
-rw-r--r-- | actionpack/CHANGELOG.md | 127 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/base.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/routing/mapper.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/form_options_helper.rb | 40 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/tags/base.rb | 7 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/tags/collection_helpers.rb | 1 | ||||
-rw-r--r-- | actionpack/test/controller/routing_test.rb | 29 | ||||
-rw-r--r-- | actionpack/test/template/form_helper_test.rb | 100 |
8 files changed, 245 insertions, 63 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 6c56a37340..74a8d9f78a 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -110,6 +110,29 @@ * `ActionView::Helpers::TextHelper#highlight` now defaults to the HTML5 `mark` element. *Brian Cardarella* + +## Rails 3.2.2 (unreleased) ## + +* Format lookup for partials is derived from the format in which the template is being rendered. Closes #5025 part 2 *Santiago Pastorino* + +* Use the right format when a partial is missing. Closes #5025. *Santiago Pastorino* + +* Default responder will now always use your overridden block in `respond_with` to render your response. *Prem Sichanugrist* + +* check_box helper with :disabled => true will generate a disabled hidden field to conform with the HTML convention where disabled fields are not submitted with the form. + This is a behavior change, previously the hidden tag had a value of the disabled checkbox. + *Tadas Tamosauskas* + + +## Rails 3.2.1 (January 26, 2012) ## + +* Documentation improvements. + +* Allow `form.select` to accept ranges (regression). *Jeremy Walker* + +* `datetime_select` works with -/+ infinity dates. *Joe Van Dyk* + + ## Rails 3.2.0 (January 20, 2012) ## * Add `config.action_dispatch.default_charset` to configure default charset for ActionDispatch::Response. *Carlos Antonio da Silva* @@ -280,14 +303,24 @@ ## Rails 3.1.4 (unreleased) ## +* Skip assets group in Gemfile and all assets configurations options + when the application is generated with --skip-sprockets option. + + *Guillermo Iguaran* + +* Use ProcessedAsset#pathname in Sprockets helpers when debugging is on. Closes #3333 #3348 #3361. + + *Guillermo Iguaran* + * Allow to use asset_path on named_routes aliasing RailsHelper's asset_path to path_to_asset *Adrian Pike* -* Assets should use the request protocol by default or default to - relative if no request is available *Jonathan del Strother* +* Assets should use the request protocol by default or default to relative if no request is available *Jonathan del Strother* ## Rails 3.1.3 (November 20, 2011) ## +* Downgrade sprockets to ~> 2.0.3. Using 2.1.0 caused regressions. + * Fix using `translate` helper with a html translation which uses the `:count` option for pluralization. @@ -570,6 +603,96 @@ * 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) ## + +* Fix using `tranlate` helper with a html translation which uses the `:count` option for + pluralization. + + *Jon Leighton* + + +## Rails 3.0.11 (November 18, 2011) ## + +* Fix XSS security vulnerability in the `translate` helper method. When using interpolation + in combination with HTML-safe translations, the interpolated input would not get HTML + escaped. *GH 3664* + + Before: + + translate('foo_html', :something => '<script>') # => "...<script>..." + + After: + + translate('foo_html', :something => '<script>') # => "...<script>..." + + *Sergey Nartimov* + +* Implement a workaround for a bug in ruby-1.9.3p0 where an error would be + raised while attempting to convert a template from one encoding to another. + + Please see http://redmine.ruby-lang.org/issues/5564 for details of the bug. + + The workaround is to load all conversions into memory ahead of time, and will + only happen if the ruby version is exactly 1.9.3p0. The hope is obviously + that the underlying problem will be resolved in the next patchlevel release + of 1.9.3. + +* Fix assert_select_email to work on multipart and non-multipart emails as the method stopped working correctly in Rails 3.x due to changes in the new mail gem. + +* Fix url_for when passed a hash to prevent additional options (eg. :host, :protocol) from being added to the hash after calling it. + + +## Rails 3.0.10 (August 16, 2011) ## + +* Fixes an issue where cache sweepers with only after filters would have no + controller object, it would raise undefined method controller_name for nil [jeroenj] + +* Ensure status codes are logged when exceptions are raised. + +* Subclasses of OutputBuffer are respected. + +* Fixed ActionView::FormOptionsHelper#select with :multiple => false + +* Avoid extra call to Cache#read in case of a fragment cache hit + + +## Rails 3.0.9 (June 16, 2011) ## + +* json_escape will now return a SafeBuffer string if it receives SafeBuffer string [tenderlove] + +* Make sure escape_js returns SafeBuffer string if it receives SafeBuffer string [Prem Sichanugrist] + +* Fix text helpers to work correctly with the new SafeBuffer restriction [Paul Gallagher, Arun Agrawal, Prem Sichanugrist] + + +## Rails 3.0.8 (June 7, 2011) ## + +* It is prohibited to perform a in-place SafeBuffer mutation [tenderlove] + + The old behavior of SafeBuffer allowed you to mutate string in place via + method like `sub!`. These methods can add unsafe strings to a safe buffer, + and the safe buffer will continue to be marked as safe. + + An example problem would be something like this: + + <%= link_to('hello world', @user).sub!(/hello/, params[:xss]) %> + + In the above example, an untrusted string (`params[:xss]`) is added to the + safe buffer returned by `link_to`, and the untrusted content is successfully + sent to the client without being escaped. To prevent this from happening + `sub!` and other similar methods will now raise an exception when they are called on a safe buffer. + + In addition to the in-place versions, some of the versions of these methods which return a copy of the string will incorrectly mark strings as safe. For example: + + <%= link_to('hello world', @user).sub(/hello/, params[:xss]) %> + + The new versions will now ensure that *all* strings returned by these methods on safe buffers are marked unsafe. + + You can read more about this change in http://groups.google.com/group/rubyonrails-security/browse_thread/thread/2e516e7acc96c4fb + +* Fixed github issue #342 with asset paths and relative roots. + + ## Rails 3.0.7 (April 18, 2011) ## * No changes. diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index 3d915cf513..43cea3b79e 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -85,7 +85,7 @@ module AbstractController # Returns the full controller name, underscored, without the ending Controller. # For instance, MyApp::MyPostsController would return "my_app/my_posts" for - # controller_name. + # controller_path. # # ==== Returns # * <tt>string</tt> diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 4f55537fe2..02a27110e4 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -328,7 +328,7 @@ module ActionDispatch # +call+ or a string representing a controller's action. # # match 'path', :to => 'controller#action' - # match 'path', :to => lambda { [200, {}, "Success!"] } + # match 'path', :to => lambda { |env| [200, {}, "Success!"] } # match 'path', :to => RackApp # # [:on] diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index abb548c276..5be3da9b94 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -506,23 +506,24 @@ module ActionView # NOTE: Only the option tags are returned, you have to wrap this call in # a regular HTML select tag. def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone) - zone_options = "" + zone_options = "".html_safe zones = model.all convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } } if priority_zones if priority_zones.is_a?(Regexp) - priority_zones = model.all.find_all {|z| z =~ priority_zones} + priority_zones = zones.select { |z| z =~ priority_zones } end - zone_options += options_for_select(convert_zones[priority_zones], selected) - zone_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n" - zones = zones.reject { |z| priority_zones.include?( z ) } + zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected) + zone_options.safe_concat content_tag(:option, '-------------', :value => '', :disabled => 'disabled') + zone_options.safe_concat "\n" + + zones.reject! { |z| priority_zones.include?(z) } end - zone_options += options_for_select(convert_zones[zones], selected) - zone_options.html_safe + zone_options.safe_concat options_for_select(convert_zones[zones], selected) end # Returns radio button tags for the collection of existing return values @@ -577,9 +578,9 @@ module ActionView # b.label(:class => "radio_button") { b.radio_button(:class => "radio_button") } # end # - # There are also two special methods available: <tt>text</tt> and - # <tt>value</tt>, which are the current text and value methods for the - # item being rendered, respectively. You can use them like this: + # There are also three special methods available: <tt>object</tt>, <tt>text</tt> and + # <tt>value</tt>, which are the current item being rendered, its text and value methods, + # respectively. You can use them like this: # collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b| # b.label(:"data-value" => b.value) { b.radio_button + b.text } # end @@ -640,9 +641,9 @@ module ActionView # b.label(:class => "check_box") { b.check_box(:class => "check_box") } # end # - # There are also two special methods available: <tt>text</tt> and - # <tt>value</tt>, which are the current text and value methods for the - # item being rendered, respectively. You can use them like this: + # There are also three special methods available: <tt>object</tt>, <tt>text</tt> and + # <tt>value</tt>, which are the current item being rendered, its text and value methods, + # respectively. You can use them like this: # collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b| # b.label(:"data-value" => b.value) { b.check_box + b.text } # end @@ -659,11 +660,8 @@ module ActionView def option_text_and_value(option) # Options are [text, value] pairs or strings used for both. - case - when Array === option - option = option.reject { |e| Hash === e } - [option.first, option.last] - when !option.is_a?(String) && option.respond_to?(:first) && option.respond_to?(:last) + if !option.is_a?(String) && option.respond_to?(:first) && option.respond_to?(:last) + option = option.reject { |e| Hash === e } if Array === option [option.first, option.last] else [option, option] @@ -671,11 +669,7 @@ module ActionView end def option_value_selected?(value, selected) - if selected.respond_to?(:include?) && !selected.is_a?(String) - selected.include? value - else - value == selected - end + Array(selected).include? value end def extract_selected_and_disabled(selected) diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb index d949ff5194..c9c891daa1 100644 --- a/actionpack/lib/action_view/helpers/tags/base.rb +++ b/actionpack/lib/action_view/helpers/tags/base.rb @@ -133,13 +133,14 @@ module ActionView def add_options(option_tags, options, value = nil) if options[:include_blank] - option_tags = "<option value=\"\">#{ERB::Util.html_escape(options[:include_blank]) if options[:include_blank].kind_of?(String)}</option>\n" + option_tags + 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) end if value.blank? && options[:prompt] prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select') - option_tags = "<option value=\"\">#{ERB::Util.html_escape(prompt)}</option>\n" + option_tags + option_tags = content_tag(:option, prompt, :value => '').safe_concat("\n").safe_concat(option_tags) end - option_tags.html_safe + option_tags end end end diff --git a/actionpack/lib/action_view/helpers/tags/collection_helpers.rb b/actionpack/lib/action_view/helpers/tags/collection_helpers.rb index 6f950e552a..6a1479069f 100644 --- a/actionpack/lib/action_view/helpers/tags/collection_helpers.rb +++ b/actionpack/lib/action_view/helpers/tags/collection_helpers.rb @@ -59,6 +59,7 @@ module ActionView end end + html_options[:object] = @object html_options end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 807905c7b5..843ae1a813 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -147,6 +147,31 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_star_paths_are_greedy rs.draw do + match "/*path", :to => lambda { |env| + x = env["action_dispatch.request.path_parameters"][:path] + [200, {}, [x]] + }, :format => false + end + + u = URI('http://example.org/foo/bar.html') + assert_equal u.path.sub(/^\//, ''), get(u) + end + + def test_star_paths_are_greedy_but_not_too_much + rs.draw do + match "/*path", :to => lambda { |env| + x = JSON.dump env["action_dispatch.request.path_parameters"] + [200, {}, [x]] + } + end + + expected = { "path" => "foo/bar", "format" => "html" } + u = URI('http://example.org/foo/bar.html') + assert_equal expected, JSON.parse(get(u)) + end + + def test_optional_star_paths_are_greedy + rs.draw do match "/(*filters)", :to => lambda { |env| x = env["action_dispatch.request.path_parameters"][:filters] [200, {}, [x]] @@ -157,9 +182,9 @@ class LegacyRouteSetTests < ActiveSupport::TestCase assert_equal u.path.sub(/^\//, ''), get(u) end - def test_star_paths_are_greedy_but_not_too_much + def test_optional_star_paths_are_greedy_but_not_too_much rs.draw do - match "/(*filters).:format", :to => lambda { |env| + match "/(*filters)", :to => lambda { |env| x = JSON.dump env["action_dispatch.request.path_parameters"] [200, {}, [x]] } diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 3546bd3bee..63970d0a89 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -771,6 +771,44 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_form_for_with_collection_radio_buttons + post = Post.new + def post.active; false; end + form_for(post) do |f| + concat f.collection_radio_buttons(:active, [true, false], :to_s, :to_s) + end + + expected = whole_form("/posts", "new_post" , "new_post") do + "<input id='post_active_true' name='post[active]' type='radio' value='true' />" + + "<label for='post_active_true'>true</label>" + + "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" + + "<label for='post_active_false'>false</label>" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_collection_check_boxes + post = Post.new + def post.tag_ids; [1, 3]; end + collection = (1..3).map{|i| [i, "Tag #{i}"] } + form_for(post) do |f| + concat f.collection_check_boxes(:tag_ids, collection, :first, :last) + end + + expected = whole_form("/posts", "new_post" , "new_post") do + "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" + + "<label for='post_tag_ids_1'>Tag 1</label>" + + "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" + + "<label for='post_tag_ids_2'>Tag 2</label>" + + "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" + + "<label for='post_tag_ids_3'>Tag 3</label>" + + "<input name='post[tag_ids][]' type='hidden' value='' />" + end + + assert_dom_equal expected, output_buffer + end + def test_form_for_with_file_field_generate_multipart Post.send :attr_accessor, :file @@ -1999,37 +2037,6 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end - def hidden_fields(method = nil) - txt = %{<div style="margin:0;padding:0;display:inline">} - txt << %{<input name="utf8" type="hidden" value="✓" />} - if method && !method.to_s.in?(['get', 'post']) - txt << %{<input name="_method" type="hidden" value="#{method}" />} - end - txt << %{</div>} - end - - def form_text(action = "/", id = nil, html_class = nil, remote = nil, multipart = nil, method = nil) - txt = %{<form accept-charset="UTF-8" action="#{action}"} - txt << %{ enctype="multipart/form-data"} if multipart - txt << %{ data-remote="true"} if remote - txt << %{ class="#{html_class}"} if html_class - txt << %{ id="#{id}"} if id - method = method.to_s == "get" ? "get" : "post" - txt << %{ method="#{method}">} - end - - def whole_form(action = "/", id = nil, html_class = nil, options = nil) - contents = block_given? ? yield : "" - - if options.is_a?(Hash) - method, remote, multipart = options.values_at(:method, :remote, :multipart) - else - method = options - end - - form_text(action, id, html_class, remote, multipart, method) + hidden_fields(method) + contents + "</form>" - end - def test_default_form_builder old_default_form_builder, ActionView::Base.default_form_builder = ActionView::Base.default_form_builder, LabelledFormBuilder @@ -2213,6 +2220,37 @@ class FormHelperTest < ActionView::TestCase protected + def hidden_fields(method = nil) + txt = %{<div style="margin:0;padding:0;display:inline">} + txt << %{<input name="utf8" type="hidden" value="✓" />} + if method && !method.to_s.in?(['get', 'post']) + txt << %{<input name="_method" type="hidden" value="#{method}" />} + end + txt << %{</div>} + end + + def form_text(action = "/", id = nil, html_class = nil, remote = nil, multipart = nil, method = nil) + txt = %{<form accept-charset="UTF-8" action="#{action}"} + txt << %{ enctype="multipart/form-data"} if multipart + txt << %{ data-remote="true"} if remote + txt << %{ class="#{html_class}"} if html_class + txt << %{ id="#{id}"} if id + method = method.to_s == "get" ? "get" : "post" + txt << %{ method="#{method}">} + end + + def whole_form(action = "/", id = nil, html_class = nil, options = nil) + contents = block_given? ? yield : "" + + if options.is_a?(Hash) + method, remote, multipart = options.values_at(:method, :remote, :multipart) + else + method = options + end + + form_text(action, id, html_class, remote, multipart, method) + hidden_fields(method) + contents + "</form>" + end + def protect_against_forgery? false end |