diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2014-03-13 11:18:01 -0700 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2014-03-13 11:18:01 -0700 |
commit | 66e032117fa5c6953a7b1d791dcdc1ee029e4cef (patch) | |
tree | a6917f6738455335e040b8e724d66919418e191d /actionview | |
parent | 37ca1b43af423e61d9b0e8e134c3c126ed754316 (diff) | |
parent | e88da370f190cabd1e9750c5b3531735950ab415 (diff) | |
download | rails-66e032117fa5c6953a7b1d791dcdc1ee029e4cef.tar.gz rails-66e032117fa5c6953a7b1d791dcdc1ee029e4cef.tar.bz2 rails-66e032117fa5c6953a7b1d791dcdc1ee029e4cef.zip |
Merge branch 'master' into adequaterecord
* master: (108 commits)
make tests pass on Ruby 2.2
Use Sqlite3 adapter in examples
use the body proxy to freeze headers
just ask the response for the commit status, we do not need to ask the jar
only write the jar if the response isn't committed
Fix a grammatical error in the i18n guide [ci skip]
use method_defined? to check whether or not a method is defined
Enhance docs for update_attribute [ci-skip]
Change usec to 0 on tests that compare seconds
Unit test for mysql quote time usec
Changelog entry for mysql56 microseconds
Test microsecond on mysql 5.6
MySQL 5.6 and later supports microsecond precision in datetime.
[ci skip] Add documentation for original_fullpath.
Remove mocking on save, when not necessary
comment why we are modifying global state. [ci skip]
`change_table` supports `citext`. Follow up to #12523.
Removed unnecessary command "application"
register OID for PostgreSQL citex datatype [Troy Kruthoff & Lachlan Sylvester]
Fixes STI when 2+ levels deep.
...
Diffstat (limited to 'actionview')
-rw-r--r-- | actionview/CHANGELOG.md | 16 | ||||
-rw-r--r-- | actionview/lib/action_view/digestor.rb | 64 | ||||
-rw-r--r-- | actionview/lib/action_view/gem_version.rb | 15 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/cache_helper.rb | 2 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/date_helper.rb | 12 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/form_helper.rb | 4 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/form_tag_helper.rb | 18 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/rendering_helper.rb | 5 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/tag_helper.rb | 10 | ||||
-rw-r--r-- | actionview/lib/action_view/rendering.rb | 5 | ||||
-rw-r--r-- | actionview/lib/action_view/version.rb | 11 | ||||
-rw-r--r-- | actionview/test/fixtures/digestor/messages/new.html+iphone.erb | 15 | ||||
-rw-r--r-- | actionview/test/template/digestor_test.rb | 35 | ||||
-rw-r--r-- | actionview/test/template/form_tag_helper_test.rb | 5 |
14 files changed, 167 insertions, 50 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index 28508a5dfa..e46f55a875 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1 +1,17 @@ +* Fixed a problem where the default options for the `button_tag` helper is not + applied correctly. + + Fixes #14254. + + *Sergey Prikhodko* + +* Take variants into account when calculating template digests in ActionView::Digestor. + + The arguments to ActionView::Digestor#digest are now being passed as a hash + to support variants and allow more flexibility in the future. The support for + regular (required) arguments is deprecated and will be removed in Rails 5.0 or later. + + *Piotr Chmolowski, Łukasz Strzałkowski* + + Please check [4-1-stable](https://github.com/rails/rails/blob/4-1-stable/actionview/CHANGELOG.md) for previous changes. diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb index 5570e2a8dc..da43fef2e3 100644 --- a/actionview/lib/action_view/digestor.rb +++ b/actionview/lib/action_view/digestor.rb @@ -9,23 +9,56 @@ module ActionView @@digest_monitor = Monitor.new class << self - def digest(name, format, finder, options = {}) + # Supported options: + # + # * <tt>name</tt> - Template name + # * <tt>format</tt> - Template format + # * <tt>variant</tt> - Variant of +format+ (optional) + # * <tt>finder</tt> - An instance of ActionView::LookupContext + # * <tt>dependencies</tt> - An array of dependent views + # * <tt>partial</tt> - Specifies whether the template is a partial + def digest(*args) + options = _setup_options(*args) + + name = options[:name] + format = options[:format] + variant = options[:variant] + finder = options[:finder] + details_key = finder.details_key.hash dependencies = Array.wrap(options[:dependencies]) - cache_key = ([name, details_key, format] + dependencies).join('.') + cache_key = ([name, details_key, format, variant].compact + dependencies).join('.') # this is a correctly done double-checked locking idiom # (ThreadSafe::Cache's lookups have volatile semantics) @@cache[cache_key] || @@digest_monitor.synchronize do @@cache.fetch(cache_key) do # re-check under lock - compute_and_store_digest(cache_key, name, format, finder, options) + compute_and_store_digest(cache_key, options) end end end + def _setup_options(*args) + unless args.first.is_a?(Hash) + ActiveSupport::Deprecation.warn("Arguments to ActionView::Digestor should be provided as a hash. The support for regular arguments will be removed in Rails 5.0 or later") + + { + name: args.first, + format: args.second, + finder: args.third, + }.merge(args.fourth || {}) + else + options = args.first + options.assert_valid_keys(:name, :format, :variant, :finder, :dependencies, :partial) + + options + end + end + private - def compute_and_store_digest(cache_key, name, format, finder, options) # called under @@digest_monitor lock - klass = if options[:partial] || name.include?("/_") + + def compute_and_store_digest(cache_key, options) # called under @@digest_monitor lock + klass = if options[:partial] || options[:name].include?("/_") # Prevent re-entry or else recursive templates will blow the stack. # There is no need to worry about other threads seeing the +false+ value, # as they will then have to wait for this thread to let go of the @@digest_monitor lock. @@ -35,20 +68,25 @@ module ActionView Digestor end - digest = klass.new(name, format, finder, options).digest + digest = klass.new(options).digest # Store the actual digest if config.cache_template_loading is true @@cache[cache_key] = stored_digest = digest if ActionView::Resolver.caching? digest ensure # something went wrong or ActionView::Resolver.caching? is false, make sure not to corrupt the @@cache - @@cache.delete_pair(cache_key, false) if pre_stored && !stored_digest + @@cache.delete_pair(cache_key, false) if pre_stored && !stored_digest end end - attr_reader :name, :format, :finder, :options + attr_reader :name, :format, :variant, :finder, :options + + def initialize(*args) + @options = self.class._setup_options(*args) - def initialize(name, format, finder, options={}) - @name, @format, @finder, @options = name, format, finder, options + @name = @options.delete(:name) + @format = @options.delete(:format) + @variant = @options.delete(:variant) + @finder = @options.delete(:finder) end def digest @@ -68,7 +106,7 @@ module ActionView def nested_dependencies dependencies.collect do |dependency| - dependencies = PartialDigestor.new(dependency, format, finder).nested_dependencies + dependencies = PartialDigestor.new(name: dependency, format: format, finder: finder).nested_dependencies dependencies.any? ? { dependency => dependencies } : dependency end end @@ -88,7 +126,7 @@ module ActionView end def template - @template ||= finder.find(logical_name, [], partial?, formats: [ format ]) + @template ||= finder.find(logical_name, [], partial?, formats: [ format ], variants: [ variant ]) end def source @@ -97,7 +135,7 @@ module ActionView def dependency_digest template_digests = dependencies.collect do |template_name| - Digestor.digest(template_name, format, finder, partial: true) + Digestor.digest(name: template_name, format: format, finder: finder, partial: true) end (template_digests + injected_dependencies).join("-") diff --git a/actionview/lib/action_view/gem_version.rb b/actionview/lib/action_view/gem_version.rb new file mode 100644 index 0000000000..9266e55c47 --- /dev/null +++ b/actionview/lib/action_view/gem_version.rb @@ -0,0 +1,15 @@ +module ActionView + # Returns the version of the currently loaded ActionView as a <tt>Gem::Version</tt> + def self.gem_version + Gem::Version.new VERSION::STRING + end + + module VERSION + MAJOR = 4 + MINOR = 2 + TINY = 0 + PRE = "alpha" + + STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") + end +end diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb index b3af1d4da4..30e4e5e329 100644 --- a/actionview/lib/action_view/helpers/cache_helper.rb +++ b/actionview/lib/action_view/helpers/cache_helper.rb @@ -167,7 +167,7 @@ module ActionView if @virtual_path [ *Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name), - Digestor.digest(@virtual_path, formats.last.to_sym, lookup_context, dependencies: view_cache_dependencies) + Digestor.digest(name: @virtual_path, format: formats.last.to_sym, variant: request.variant, finder: lookup_context, dependencies: view_cache_dependencies) ] else name diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb index 698f0ca31c..1738df9cac 100644 --- a/actionview/lib/action_view/helpers/date_helper.rb +++ b/actionview/lib/action_view/helpers/date_helper.rb @@ -19,6 +19,10 @@ module ActionView # the <tt>select_month</tt> method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead # of \date[month]. module DateHelper + MINUTES_IN_YEAR = 525600 + MINUTES_IN_QUARTER_YEAR = 131400 + MINUTES_IN_THREE_QUARTERS_YEAR = 394200 + # Reports the approximate distance in time between two Time, Date or DateTime objects or integers as seconds. # Pass <tt>include_seconds: true</tt> if you want more detailed approximations when distance < 1 min, 29 secs. # Distances are reported based on the following table: @@ -120,11 +124,11 @@ module ActionView else minutes_with_offset = distance_in_minutes end - remainder = (minutes_with_offset % 525600) - distance_in_years = (minutes_with_offset.div 525600) - if remainder < 131400 + remainder = (minutes_with_offset % MINUTES_IN_YEAR) + distance_in_years = (minutes_with_offset.div MINUTES_IN_YEAR) + if remainder < MINUTES_IN_QUARTER_YEAR locale.t(:about_x_years, :count => distance_in_years) - elsif remainder < 394200 + elsif remainder < MINUTES_IN_THREE_QUARTERS_YEAR locale.t(:over_x_years, :count => distance_in_years) else locale.t(:almost_x_years, :count => distance_in_years + 1) diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb index 5235962f9f..1ff090f244 100644 --- a/actionview/lib/action_view/helpers/form_helper.rb +++ b/actionview/lib/action_view/helpers/form_helper.rb @@ -457,7 +457,7 @@ module ActionView # doesn't create the form tags themselves. This makes fields_for suitable # for specifying additional model objects in the same form. # - # Although the usage and purpose of +field_for+ is similar to +form_for+'s, + # Although the usage and purpose of +fields_for+ is similar to +form_for+'s, # its method signature is slightly different. Like +form_for+, it yields # a FormBuilder object associated with a particular model object to a block, # and within the block allows methods to be called on the builder to @@ -1268,7 +1268,7 @@ module ActionView # doesn't create the form tags themselves. This makes fields_for suitable # for specifying additional model objects in the same form. # - # Although the usage and purpose of +field_for+ is similar to +form_for+'s, + # Although the usage and purpose of +fields_for+ is similar to +form_for+'s, # its method signature is slightly different. Like +form_for+, it yields # a FormBuilder object associated with a particular model object to a block, # and within the block allows methods to be called on the builder to diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb index 80f066b3be..0bbe08166b 100644 --- a/actionview/lib/action_view/helpers/form_tag_helper.rb +++ b/actionview/lib/action_view/helpers/form_tag_helper.rb @@ -465,17 +465,23 @@ module ActionView # # <strong>Ask me!</strong> # # </button> # - # button_tag "Checkout", data: { :disable_with => "Please wait..." } + # button_tag "Checkout", data: { disable_with: "Please wait..." } # # => <button data-disable-with="Please wait..." name="button" type="submit">Checkout</button> # def button_tag(content_or_options = nil, options = nil, &block) - options = content_or_options if block_given? && content_or_options.is_a?(Hash) - options ||= {} - options = options.stringify_keys + if content_or_options.is_a? Hash + options = content_or_options + else + options ||= {} + end - options.reverse_merge! 'name' => 'button', 'type' => 'submit' + options = { 'name' => 'button', 'type' => 'submit' }.merge!(options.stringify_keys) - content_tag :button, content_or_options || 'Button', options, &block + if block_given? + content_tag :button, options, &block + else + content_tag :button, content_or_options || 'Button', options + end end # Displays an image which when clicked will submit the form. diff --git a/actionview/lib/action_view/helpers/rendering_helper.rb b/actionview/lib/action_view/helpers/rendering_helper.rb index 15b88bcda6..ebfc35a4c7 100644 --- a/actionview/lib/action_view/helpers/rendering_helper.rb +++ b/actionview/lib/action_view/helpers/rendering_helper.rb @@ -17,8 +17,9 @@ module ActionView # * <tt>:html</tt> - Renders the html safe string passed in out, otherwise # performs html escape on the string first. Setting the content type as # <tt>text/html</tt>. - # * <tt>:body</tt> - Renders the text passed in, and does not set content - # type in the response. + # * <tt>:body</tt> - Renders the text passed in, and inherits the content + # type of <tt>text/html</tt> from <tt>ActionDispatch::Response</tt> + # object. # # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter # as the locals hash. diff --git a/actionview/lib/action_view/helpers/tag_helper.rb b/actionview/lib/action_view/helpers/tag_helper.rb index 3528381781..a9f3b0ffbc 100644 --- a/actionview/lib/action_view/helpers/tag_helper.rb +++ b/actionview/lib/action_view/helpers/tag_helper.rb @@ -42,7 +42,8 @@ module ActionView # For example, a key +user_id+ would render as <tt>data-user-id</tt> and # thus accessed as <tt>dataset.userId</tt>. # - # Values are encoded to JSON, with the exception of strings and symbols. + # Values are encoded to JSON, with the exception of strings, symbols and + # BigDecimals. # This may come in handy when using jQuery's HTML5-aware <tt>.data()</tt> # from 1.4.3. # @@ -56,6 +57,9 @@ module ActionView # tag("input", type: 'text', disabled: true) # # => <input type="text" disabled="disabled" /> # + # tag("input", type: 'text', class: ["strong", "highlight"]) + # # => <input class="strong highlight" type="text" /> + # # tag("img", src: "open & shut.png") # # => <img src="open & shut.png" /> # @@ -75,7 +79,7 @@ module ActionView # Set escape to false to disable attribute value escaping. # # ==== Options - # The +options+ hash is used with attributes with no value like (<tt>disabled</tt> and + # The +options+ hash can be used with attributes with no value like (<tt>disabled</tt> and # <tt>readonly</tt>), which you can give a value of true in the +options+ hash. You can use # symbols or strings for the attribute names. # @@ -84,6 +88,8 @@ module ActionView # # => <p>Hello world!</p> # content_tag(:div, content_tag(:p, "Hello world!"), class: "strong") # # => <div class="strong"><p>Hello world!</p></div> + # content_tag(:div, "Hello world!", class: ["strong", "highlight"]) + # # => <div class="strong highlight">Hello world!</div> # content_tag("select", options, multiple: true) # # => <select multiple="multiple">...options...</select> # diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index f96587c816..017302d40f 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -102,11 +102,6 @@ module ActionView # Assign the rendered format to lookup context. def _process_format(format, options = {}) #:nodoc: super - - if options[:body] - self.no_content_type = true - end - lookup_context.formats = [format.to_sym] lookup_context.rendered_format = lookup_context.formats.first end diff --git a/actionview/lib/action_view/version.rb b/actionview/lib/action_view/version.rb index b3ff415775..f55d3fdaef 100644 --- a/actionview/lib/action_view/version.rb +++ b/actionview/lib/action_view/version.rb @@ -1,11 +1,8 @@ +require_relative 'gem_version' + module ActionView - # Returns the version of the currently loaded ActionView as a Gem::Version + # Returns the version of the currently loaded ActionView as a <tt>Gem::Version</tt> def self.version - Gem::Version.new "4.2.0.alpha" - end - - module VERSION #:nodoc: - MAJOR, MINOR, TINY, PRE = ActionView.version.segments - STRING = ActionView.version.to_s + gem_version end end diff --git a/actionview/test/fixtures/digestor/messages/new.html+iphone.erb b/actionview/test/fixtures/digestor/messages/new.html+iphone.erb new file mode 100644 index 0000000000..791e1d36b4 --- /dev/null +++ b/actionview/test/fixtures/digestor/messages/new.html+iphone.erb @@ -0,0 +1,15 @@ +<%# Template Dependency: messages/message %> + +<%= render "header" %> +<%= render "comments/comments" %> + +<%= render "messages/actions/move" %> + +<%= render @message.history.events %> + +<%# render "something_missing" %> +<%# render "something_missing_1" %> + +<% + # Template Dependency: messages/form +%>
\ No newline at end of file diff --git a/actionview/test/template/digestor_test.rb b/actionview/test/template/digestor_test.rb index 779a7fb53c..2406a64310 100644 --- a/actionview/test/template/digestor_test.rb +++ b/actionview/test/template/digestor_test.rb @@ -26,7 +26,11 @@ class FixtureFinder end def find(logical_name, keys, partial, options) - FixtureTemplate.new("digestor/#{partial ? logical_name.gsub(%r|/([^/]+)$|, '/_\1') : logical_name}.#{options[:formats].first}.erb") + partial_name = partial ? logical_name.gsub(%r|/([^/]+)$|, '/_\1') : logical_name + format = options[:formats].first.to_s + format += "+#{options[:variants].first}" if options[:variants].any? + + FixtureTemplate.new("digestor/#{partial_name}.#{format}.erb") end end @@ -194,6 +198,13 @@ class TemplateDigestorTest < ActionView::TestCase end end + def test_variants + assert_digest_difference("messages/new", false, variant: :iphone) do + change_template("messages/new", :iphone) + change_template("messages/_header", :iphone) + end + end + def test_dependencies_via_options_results_in_different_digest digest_plain = digest("comments/_comment") digest_fridge = digest("comments/_comment", dependencies: ["fridge"]) @@ -242,6 +253,11 @@ class TemplateDigestorTest < ActionView::TestCase ActionView::Resolver.caching = resolver_before end + def test_arguments_deprecation + assert_deprecated(/should be provided as a hash/) { ActionView::Digestor.digest('messages/show', :html, finder) } + assert_deprecated(/should be provided as a hash/) { ActionView::Digestor.new('messages/show', :html, finder) } + end + private def assert_logged(message) old_logger = ActionView::Base.logger @@ -258,26 +274,29 @@ class TemplateDigestorTest < ActionView::TestCase end end - def assert_digest_difference(template_name, persistent = false) - previous_digest = digest(template_name) + def assert_digest_difference(template_name, persistent = false, options = {}) + previous_digest = digest(template_name, options) ActionView::Digestor.cache.clear unless persistent yield - assert previous_digest != digest(template_name), "digest didn't change" + assert previous_digest != digest(template_name, options), "digest didn't change" ActionView::Digestor.cache.clear end - def digest(template_name, options={}) - ActionView::Digestor.digest(template_name, :html, finder, options) + def digest(template_name, options = {}) + options = options.dup + ActionView::Digestor.digest({ name: template_name, format: :html, finder: finder }.merge(options)) end def finder @finder ||= FixtureFinder.new end - def change_template(template_name) - File.open("digestor/#{template_name}.html.erb", "w") do |f| + def change_template(template_name, variant = nil) + variant = "+#{variant}" if variant.present? + + File.open("digestor/#{template_name}.html#{variant}.erb", "w") do |f| f.write "\nTHIS WAS CHANGED!" end end diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb index 0d5831dc6f..cf824e2733 100644 --- a/actionview/test/template/form_tag_helper_test.rb +++ b/actionview/test/template/form_tag_helper_test.rb @@ -476,6 +476,11 @@ class FormTagHelperTest < ActionView::TestCase assert_dom_equal('<button name="temptation" type="button"><strong>Do not press me</strong></button>', output) end + def test_button_tag_defaults_with_block_and_options + output = button_tag(:name => 'temptation', :value => 'within') { content_tag(:strong, 'Do not press me') } + assert_dom_equal('<button name="temptation" value="within" type="submit" ><strong>Do not press me</strong></button>', output) + end + def test_button_tag_with_confirmation assert_dom_equal( %(<button name="button" type="submit" data-confirm="Are you sure?">Save</button>), |