diff options
Diffstat (limited to 'actionpack')
34 files changed, 313 insertions, 192 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 9d320ddb8d..9888be07a9 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -30,6 +30,8 @@ *Rails 3.1.0 (unreleased)* +* The submit form helper does not generate an id "object_name_id" anymore. [fbrusatti] + * Make sure respond_with with :js tries to render a template in all cases [JosĂ© Valim] * json_escape will now return a SafeBuffer string if it receives SafeBuffer string [tenderlove] diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 88d892eb16..620fdc4a72 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -21,10 +21,11 @@ Gem::Specification.new do |s| s.add_dependency('rack-cache', '~> 1.0.2') s.add_dependency('builder', '~> 3.0.0') s.add_dependency('i18n', '~> 0.6') - s.add_dependency('rack', '~> 1.3.1') + s.add_dependency('rack', '~> 1.3.2') s.add_dependency('rack-test', '~> 0.6.0') s.add_dependency('rack-mount', '~> 0.8.1') - s.add_dependency('sprockets', '= 2.0.0.beta.10') - s.add_dependency('tzinfo', '~> 0.3.29') + s.add_dependency('sprockets', '~> 2.0.0.beta.12') s.add_dependency('erubis', '~> 2.7.0') + + s.add_development_dependency('tzinfo', '~> 0.3.29') end diff --git a/actionpack/lib/abstract_controller/asset_paths.rb b/actionpack/lib/abstract_controller/asset_paths.rb index ad14cd6d87..b104d34fb5 100644 --- a/actionpack/lib/abstract_controller/asset_paths.rb +++ b/actionpack/lib/abstract_controller/asset_paths.rb @@ -3,7 +3,7 @@ module AbstractController extend ActiveSupport::Concern included do - config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir, :use_sprockets + config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir end end end diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index d6f75bded0..10aa34c76b 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -139,7 +139,7 @@ module AbstractController # # end # - # This will assign "weblog_standard" as the WeblogController's layout for all actions except for the +rss+ action, which will + # This will assign "weblog_standard" as the WeblogController's layout for all actions except for the +rss+ action, which will # be rendered directly, without wrapping a layout around the rendered view. # # Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so @@ -167,6 +167,7 @@ module AbstractController included do class_attribute :_layout_conditions + remove_possible_method :_layout_conditions delegate :_layout_conditions, :to => :'self.class' self._layout_conditions = {} _write_layout_method diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index d14c5f940b..ce56d8bc71 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -212,16 +212,16 @@ module ActionController # also include them at the bottom. AbstractController::Callbacks, + # Append rescue at the bottom to wrap as much as possible. + Rescue, + # Add instrumentations hooks at the bottom, to ensure they instrument # all the methods properly. Instrumentation, # Params wrapper should come before instrumentation so they are # properly showed in logs - ParamsWrapper, - - # The same with rescue, append it at the end to wrap as much as possible. - Rescue + ParamsWrapper ] MODULES.each do |mod| diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 258a40aea6..4d016271ea 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -79,7 +79,7 @@ module ActionController #:nodoc: end end - # This is the method that defines the application behaviour when a request is found to be unverified. + # This is the method that defines the application behavior when a request is found to be unverified. # By default, \Rails resets the session when it finds an unverified request. def handle_unverified_request reset_session diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 980c658ab7..5c48a60469 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -98,7 +98,8 @@ module ActionDispatch BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ def valid_accept_header - xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS) + (xhr? && (accept || content_mime_type)) || + (accept && accept !~ BROWSER_LIKE_ACCEPTS) end def use_accept_header diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 65895590bf..003bc1dc2c 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -119,6 +119,8 @@ module ActionDispatch path elsif path.include?(":format") || path.end_with?('/') path + elsif @options[:format] == true + "#{path}.:format" else "#{path}(.:format)" end @@ -190,13 +192,12 @@ module ActionDispatch end def blocks - block = @scope[:blocks] || [] - - if @options[:constraints].present? && !@options[:constraints].is_a?(Hash) - block << @options[:constraints] + constraints = @options[:constraints] + if constraints.present? && !constraints.is_a?(Hash) + [constraints] + else + @scope[:blocks] || [] end - - block end def constraints @@ -659,13 +660,13 @@ module ActionDispatch # # This generates the following routes: # - # admin_posts GET /admin/posts(.:format) {:action=>"index", :controller=>"admin/posts"} - # admin_posts POST /admin/posts(.:format) {:action=>"create", :controller=>"admin/posts"} - # new_admin_post GET /admin/posts/new(.:format) {:action=>"new", :controller=>"admin/posts"} - # edit_admin_post GET /admin/posts/:id/edit(.:format) {:action=>"edit", :controller=>"admin/posts"} - # admin_post GET /admin/posts/:id(.:format) {:action=>"show", :controller=>"admin/posts"} - # admin_post PUT /admin/posts/:id(.:format) {:action=>"update", :controller=>"admin/posts"} - # admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"} + # admin_posts GET /admin/posts(.:format) admin/posts#index + # admin_posts POST /admin/posts(.:format) admin/posts#create + # new_admin_post GET /admin/posts/new(.:format) admin/posts#new + # edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit + # admin_post GET /admin/posts/:id(.:format) admin/posts#show + # admin_post PUT /admin/posts/:id(.:format) admin/posts#update + # admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy # # === Options # diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb index 49aef0bf72..e989a38d8b 100644 --- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb +++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb @@ -124,14 +124,7 @@ module ActionDispatch args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options end - if proxy - proxy.send(named_route, *args) - else - # we need to use url_for, because polymorphic_url can be used in context of other than - # current routes (e.g. engine's routes). As named routes from engine are not included - # calling engine's named route directly would fail. - url_for _routes.url_helpers.__send__("hash_for_#{named_route}", *args) - end + (proxy || self).send(named_route, *args) end # Returns the path component of a URL for the given record. It uses diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 509c29844a..7d01e5ddb8 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -154,7 +154,7 @@ module ActionView # "/release-#{RELEASE_NUMBER}#{asset_path}" # } # - # This example would cause the following behaviour on all servers no + # This example would cause the following behavior on all servers no # matter when they were deployed: # # image_tag("rails.png") diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb index 0f8a63901e..25cc561608 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb @@ -83,11 +83,7 @@ module ActionView # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js def javascript_path(source) - if config.use_sprockets - asset_path(source, 'js') - else - asset_paths.compute_public_path(source, 'javascripts', 'js') - end + asset_paths.compute_public_path(source, 'javascripts', 'js') end alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 6a724749f4..e850c258ce 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -8,8 +8,8 @@ module ActionView module Helpers # = Action View Date Helpers # - # The Date Helper primarily creates select/option tags for different kinds of dates and date elements. All of the - # select-type methods share a number of common options that are as follows: + # The Date Helper primarily creates select/option tags for different kinds of dates and times or date and time + # elements. All of the select-type methods share a number of common options that are as follows: # # * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday" # would give birthday[month] instead of date[month] if passed to the <tt>select_month</tt> method. @@ -18,7 +18,7 @@ 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 - # Reports the approximate distance in time between two Time or Date objects or integers as seconds. + # Reports the approximate distance in time between two Time, Date or DateTime objects or integers as seconds. # Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs. # Distances are reported based on the following table: # @@ -176,37 +176,37 @@ module ActionView # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed. # # ==== Examples - # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute. - # date_select("post", "written_on") + # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute. + # date_select("article", "written_on") # - # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute, + # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute, # # with the year in the year drop down box starting at 1995. - # date_select("post", "written_on", :start_year => 1995) + # date_select("article", "written_on", :start_year => 1995) # - # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute, + # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute, # # with the year in the year drop down box starting at 1995, numbers used for months instead of words, # # and without a day select box. - # date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true, + # date_select("article", "written_on", :start_year => 1995, :use_month_numbers => true, # :discard_day => true, :include_blank => true) # - # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute + # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute # # with the fields ordered as day, month, year rather than month, day, year. - # date_select("post", "written_on", :order => [:day, :month, :year]) + # date_select("article", "written_on", :order => [:day, :month, :year]) # # # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute # # lacking a year field. # date_select("user", "birthday", :order => [:month, :day]) # - # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute + # # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute # # which is initially set to the date 3 days from the current date - # date_select("post", "written_on", :default => 3.days.from_now) + # date_select("article", "written_on", :default => 3.days.from_now) # # # Generates a date select that when POSTed is stored in the credit_card variable, in the bill_due attribute # # that will have a default day of 20. # date_select("credit_card", "bill_due", :default => { :day => 20 }) # # # Generates a date select with custom prompts. - # date_select("post", "written_on", :prompt => { :day => 'Select day', :month => 'Select month', :year => 'Select year' }) + # date_select("article", "written_on", :prompt => { :day => 'Select day', :month => 'Select month', :year => 'Select year' }) # # The selects are prepared for multi-parameter assignment to an Active Record object. # @@ -228,20 +228,20 @@ module ActionView # If anything is passed in the html_options hash it will be applied to every select tag in the set. # # ==== Examples - # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute. - # time_select("post", "sunrise") + # # Creates a time select tag that, when POSTed, will be stored in the article variable in the sunrise attribute. + # time_select("article", "sunrise") # - # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the post variables in + # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the article variables in # # the sunrise attribute. - # time_select("post", "start_time", :include_seconds => true) + # time_select("article", "start_time", :include_seconds => true) # # # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30 and 45. # time_select 'game', 'game_time', {:minute_step => 15} # # # Creates a time select tag with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts. - # time_select("post", "written_on", :prompt => {:hour => 'Choose hour', :minute => 'Choose minute', :second => 'Choose seconds'}) - # time_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours - # time_select("post", "written_on", :prompt => true) # generic prompts for all + # time_select("article", "written_on", :prompt => {:hour => 'Choose hour', :minute => 'Choose minute', :second => 'Choose seconds'}) + # time_select("article", "written_on", :prompt => {:hour => true}) # generic prompt for hours + # time_select("article", "written_on", :prompt => true) # generic prompts for all # # # You can set :ampm option to true which will show the hours as: 12 PM, 01 AM .. 11 PM. # time_select 'game', 'game_time', {:ampm => true} @@ -261,36 +261,36 @@ module ActionView # If anything is passed in the html_options hash it will be applied to every select tag in the set. # # ==== Examples - # # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on + # # Generates a datetime select that, when POSTed, will be stored in the article variable in the written_on # # attribute. - # datetime_select("post", "written_on") + # datetime_select("article", "written_on") # # # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the - # # post variable in the written_on attribute. - # datetime_select("post", "written_on", :start_year => 1995) + # # article variable in the written_on attribute. + # datetime_select("article", "written_on", :start_year => 1995) # # # Generates a datetime select with a default value of 3 days from the current time that, when POSTed, will # # be stored in the trip variable in the departing attribute. # datetime_select("trip", "departing", :default => 3.days.from_now) # # # Generate a datetime select with hours in the AM/PM format - # datetime_select("post", "written_on", :ampm => true) + # datetime_select("article", "written_on", :ampm => true) # - # # Generates a datetime select that discards the type that, when POSTed, will be stored in the post variable + # # Generates a datetime select that discards the type that, when POSTed, will be stored in the article variable # # as the written_on attribute. - # datetime_select("post", "written_on", :discard_type => true) + # datetime_select("article", "written_on", :discard_type => true) # # # Generates a datetime select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts. - # datetime_select("post", "written_on", :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'}) - # datetime_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours - # datetime_select("post", "written_on", :prompt => true) # generic prompts for all + # datetime_select("article", "written_on", :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'}) + # datetime_select("article", "written_on", :prompt => {:hour => true}) # generic prompt for hours + # datetime_select("article", "written_on", :prompt => true) # generic prompts for all # # The selects are prepared for multi-parameter assignment to an Active Record object. def datetime_select(object_name, method, options = {}, html_options = {}) InstanceTag.new(object_name, method, self, options.delete(:object)).to_datetime_select_tag(options, html_options) end - # Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the + # Returns a set of html select-tags (one for year, month, day, hour, minute, and second) pre-selected with the # +datetime+. It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with # an array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not # supply a Symbol, it will be appended onto the <tt>:order</tt> passed in. You can also add @@ -343,15 +343,15 @@ module ActionView # Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+. # It's possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of - # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, - # it will be appended onto the <tt>:order</tt> passed in. + # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. + # If the array passed to the <tt>:order</tt> option does not contain all the three symbols, all tags will be hidden. # # If anything is passed in the html_options hash it will be applied to every select tag in the set. # # ==== Examples - # my_date = Time.today + 6.days + # my_date = Time.now + 6.days # - # # Generates a date select that defaults to the date in my_date (six days afteri today). + # # Generates a date select that defaults to the date in my_date (six days after today). # select_date(my_date) # # # Generates a date select that defaults to today (no specified date). @@ -422,7 +422,7 @@ module ActionView end # Returns a select tag with options for each of the seconds 0 through 59 with the current second selected. - # The <tt>second</tt> can also be substituted for a second number. + # The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer. # Override the field name using the <tt>:field_name</tt> option, 'second' by default. # # ==== Examples @@ -440,7 +440,7 @@ module ActionView # # # Generates a select field for seconds with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. - # select_minute(14, :prompt => 'Choose seconds') + # select_second(14, :prompt => 'Choose seconds') # def select_second(datetime, options = {}, html_options = {}) DateTimeSelector.new(datetime, options, html_options).select_second @@ -448,21 +448,21 @@ module ActionView # Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected. # Also can return a select tag with options by <tt>minute_step</tt> from 0 through 59 with the 00 minute - # selected. The <tt>minute</tt> can also be substituted for a minute number. + # selected. The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer. # Override the field name using the <tt>:field_name</tt> option, 'minute' by default. # # ==== Examples # my_time = Time.now + 6.hours # - # # Generates a select field for minutes that defaults to the minutes for the time in my_tiime. + # # Generates a select field for minutes that defaults to the minutes for the time in my_time. # select_minute(my_time) # # # Generates a select field for minutes that defaults to the number given. # select_minute(14) # # # Generates a select field for minutes that defaults to the minutes for the time in my_time - # # that is named 'stride' rather than 'second'. - # select_minute(my_time, :field_name => 'stride') + # # that is named 'moment' rather than 'minute'. + # select_minute(my_time, :field_name => 'moment') # # # Generates a select field for minutes with a custom prompt. Use <tt>:prompt => true</tt> for a # # generic prompt. @@ -473,7 +473,7 @@ module ActionView end # Returns a select tag with options for each of the hours 0 through 23 with the current hour selected. - # The <tt>hour</tt> can also be substituted for a hour number. + # The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer. # Override the field name using the <tt>:field_name</tt> option, 'hour' by default. # # ==== Examples @@ -485,8 +485,8 @@ module ActionView # # Generates a select field for hours that defaults to the number given. # select_hour(13) # - # # Generates a select field for hours that defaults to the minutes for the time in my_time - # # that is named 'stride' rather than 'second'. + # # Generates a select field for hours that defaults to the hour for the time in my_time + # # that is named 'stride' rather than 'hour'. # select_hour(my_time, :field_name => 'stride') # # # Generates a select field for hours with a custom prompt. Use <tt>:prompt => true</tt> for a @@ -501,11 +501,11 @@ module ActionView end # Returns a select tag with options for each of the days 1 through 31 with the current day selected. - # The <tt>date</tt> can also be substituted for a hour number. + # The <tt>date</tt> can also be substituted for a day number. # Override the field name using the <tt>:field_name</tt> option, 'day' by default. # # ==== Examples - # my_date = Time.today + 2.days + # my_date = Time.now + 2.days # # # Generates a select field for days that defaults to the day for the date in my_date. # select_day(my_time) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 89bd1365cd..52a640abf3 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -49,7 +49,7 @@ module ActionView # <label for="person_last_name">Last name</label>: # <input id="person_last_name" name="person[last_name]" size="30" type="text" /><br /> # - # <input id="person_submit" name="commit" type="submit" value="Create Person" /> + # <input name="commit" type="submit" value="Create Person" /> # </form> # # As you see, the HTML reflects knowledge about the resource in several spots, @@ -80,7 +80,7 @@ module ActionView # <label for="person_last_name">Last name</label>: # <input id="person_last_name" name="person[last_name]" size="30" type="text" value="Smith" /><br /> # - # <input id="person_submit" name="commit" type="submit" value="Update Person" /> + # <input name="commit" type="submit" value="Update Person" /> # </form> # # Note that the endpoint, default values, and submit button label are tailored for <tt>@person</tt>. @@ -233,7 +233,7 @@ module ActionView # <% end %> # # If your resource has associations defined, for example, you want to add comments - # to the post given that the routes are set correctly: + # to the document given that the routes are set correctly: # # <%= form_for([@document, @comment]) do |f| %> # ... @@ -259,8 +259,8 @@ module ActionView # :remote => true # # in the options hash creates a form that will allow the unobtrusive JavaScript drivers to modify its - # behaviour. The expected default behaviour is an XMLHttpRequest in the background instead of the regular - # POST arrangement, but ultimately the behaviour is the choice of the JavaScript driver implementor. + # behavior. The expected default behavior is an XMLHttpRequest in the background instead of the regular + # POST arrangement, but ultimately the behavior is the choice of the JavaScript driver implementor. # Even though it's using JavaScript to serialize the form elements, the form submission will work just like # a regular submission as viewed by the receiving side (all elements available in <tt>params</tt>). # @@ -859,7 +859,28 @@ module ActionView InstanceTag.new(object_name, method, self, options.delete(:object)).to_radio_button_tag(tag_value, options) end - # Returns a text_field of type "search". + # Returns an input of type "search" for accessing a specified attribute (identified by +method+) on an object + # assigned to the template (identified by +object_name+). Inputs of type "search" may be styled differently by + # some browsers. + # + # ==== Examples + # + # search_field(:user, :name) + # # => <input id="user_name" name="user[name]" size="30" type="search" /> + # search_field(:user, :name, :autosave => false) + # # => <input autosave="false" id="user_name" name="user[name]" size="30" type="search" /> + # search_field(:user, :name, :results => 3) + # # => <input id="user_name" name="user[name]" results="3" size="30" type="search" /> + # # Assume request.host returns "www.example.com" + # search_field(:user, :name, :autosave => true) + # # => <input autosave="com.example.www" id="user_name" name="user[name]" results="10" size="30" type="search" /> + # search_field(:user, :name, :onsearch => true) + # # => <input id="user_name" incremental="true" name="user[name]" onsearch="true" size="30" type="search" /> + # search_field(:user, :name, :autosave => false, :onsearch => true) + # # => <input autosave="false" id="user_name" incremental="true" name="user[name]" onsearch="true" size="30" type="search" /> + # search_field(:user, :name, :autosave => true, :onsearch => true) + # # => <input autosave="com.example.www" id="user_name" incremental="true" name="user[name]" onsearch="true" results="10" size="30" type="search" /> + # def search_field(object_name, method, options = {}) options = options.stringify_keys @@ -878,17 +899,29 @@ module ActionView end # Returns a text_field of type "tel". + # + # telephone_field("user", "phone") + # # => <input id="user_phone" name="user[phone]" size="30" type="tel" /> + # def telephone_field(object_name, method, options = {}) InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("tel", options) end alias phone_field telephone_field # Returns a text_field of type "url". + # + # url_field("user", "homepage") + # # => <input id="user_homepage" size="30" name="user[homepage]" type="url" /> + # def url_field(object_name, method, options = {}) InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("url", options) end # Returns a text_field of type "email". + # + # email_field("user", "address") + # # => <input id="user_address" size="30" name="user[address]" type="email" /> + # def email_field(object_name, method, options = {}) InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("email", options) end diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 72bc4510b5..822686b09d 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -30,7 +30,7 @@ module ActionView # (by passing <tt>false</tt>). # * A list of parameters to feed to the URL the form will be posted to. # * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the - # submit behaviour. By default this behaviour is an ajax submit. + # submit behavior. By default this behavior is an ajax submit. # # ==== Examples # form_tag('/posts') diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index fe0288521f..ec6c2c8db3 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -1,3 +1,5 @@ +# encoding: utf-8 + require 'active_support/core_ext/big_decimal/conversions' require 'active_support/core_ext/float/rounding' require 'active_support/core_ext/object/blank' diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index 26b6e8b599..be64dc823e 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -25,7 +25,7 @@ module ActionView # * a titleized version of the last key segment as a text. # # E.g. the value returned for a missing translation key :"blog.post.title" will be - # <span class="translation_missing" title="translation missing: blog.post.title">Title</span>. + # <span class="translation_missing" title="translation missing: en.blog.post.title">Title</span>. # This way your views will display rather reasonable strings but it will still # be easy to spot missing translations. # diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index d70ae4196b..51baca8e03 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -55,8 +55,8 @@ module ActionView # # ==== Relying on named routes # - # Passing a record (like an Active Record or Active Resource) instead of a Hash as the options parameter will - # trigger the named route for that record. The lookup will happen on the name of the class. So passing a + # Passing a record (like an Active Record or Active Resource) instead of a Hash as the options parameter will + # trigger the named route for that record. The lookup will happen on the name of the class. So passing a # Workshop object will attempt to use the +workshop_path+ route. If you have a nested route, such as # +admin_workshop_path+ you'll have to call that explicitly (it's impossible for +url_for+ to guess that route). # @@ -113,7 +113,7 @@ module ActionView end # Creates a link tag of the given +name+ using a URL created by the set of +options+. - # See the valid options in the documentation for +url_for+. It's also possible to + # See the valid options in the documentation for +url_for+. It's also possible to # pass a String instead of an options hash, which generates a link tag that uses the # value of the String as the href for the link. Using a <tt>:back</tt> Symbol instead # of an options hash will generate a link to the referrer (a JavaScript back link @@ -278,7 +278,7 @@ module ActionView # prompt with the question specified. If the user accepts, the link is # processed normally, otherwise no action is taken. # * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the - # submit behaviour. By default this behaviour is an ajax submit. + # submit behavior. By default this behavior is an ajax submit. # * <tt>:form_class</tt> - This controls the class of the form within which the submit button will # be placed # diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index a351fbc04f..c0ac332c4e 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -12,8 +12,7 @@ module ActionView # # <%= render :partial => "account" %> # - # This would render "advertiser/_account.html.erb" and pass the instance variable @account in as a local variable - # +account+ to the template for display. + # This would render "advertiser/_account.html.erb". # # In another template for Advertiser#buy, we could have: # @@ -28,32 +27,24 @@ module ActionView # # == The :as and :object options # - # By default <tt>ActionView::Partials::PartialRenderer</tt> has its object in a local variable with the same - # name as the template. So, given + # By default <tt>ActionView::Partials::PartialRenderer</tt> doesn't have any local variables. + # The <tt>:object</tt> option can be used to pass an object to the partial. For instance: # - # <%= render :partial => "contract" %> + # <%= render :partial => "account", :object => @buyer %> # - # within contract we'll get <tt>@contract</tt> in the local variable +contract+, as if we had written + # would provide the +@buyer+ object to the partial, available under the local variable +account+ and is + # equivalent to: # - # <%= render :partial => "contract", :locals => { :contract => @contract } %> + # <%= render :partial => "account", :locals => { :account => @buyer } %> # # With the <tt>:as</tt> option we can specify a different name for said local variable. For example, if we - # wanted it to be +agreement+ instead of +contract+ we'd do: - # - # <%= render :partial => "contract", :as => 'agreement' %> - # - # The <tt>:object</tt> option can be used to directly specify which object is rendered into the partial; - # useful when the template's object is elsewhere, in a different ivar or in a local variable for instance. + # wanted it to be +user+ instead of +account+ we'd do: # - # Revisiting a previous example we could have written this code: + # <%= render :partial => "account", :object => @buyer, :as => 'user' %> # - # <%= render :partial => "account", :object => @buyer %> - # - # <% @advertisements.each do |ad| %> - # <%= render :partial => "ad", :object => ad %> - # <% end %> + # This is equivalent to # - # The <tt>:object</tt> and <tt>:as</tt> options can be used together. + # <%= render :partial => "account", :locals => { :user => @buyer } %> # # == Rendering a collection of partials # @@ -300,6 +291,11 @@ module ActionView else paths.map! { |path| retrieve_variable(path).unshift(path) } end + if String === partial && @variable.to_s !~ /^[a-z_][a-zA-Z_0-9]*$/ + raise ArgumentError.new("The partial name (#{partial}) is not a valid Ruby identifier; " + + "make sure your partial name starts with a letter or underscore, " + + "and is followed by any combinations of letters, numbers, or underscores.") + end self end @@ -366,11 +362,25 @@ module ActionView def partial_path(object = @object) @partial_names[object.class.name] ||= begin object = object.to_model if object.respond_to?(:to_model) - object.class.model_name.partial_path.dup.tap do |partial| path = @lookup_context.prefixes.first - partial.insert(0, "#{File.dirname(path)}/") if partial.include?(?/) && path.include?(?/) + merge_path_into_partial(path, partial) + end + end + end + + def merge_path_into_partial(path, partial) + if path.include?(?/) && partial.include?(?/) + overlap = [] + path_array = File.dirname(path).split('/') + partial_array = partial.split('/')[0..-3] # skip model dir & partial + + path_array.each_with_index do |dir, index| + overlap << dir if dir == partial_array[index] end + + partial.gsub!(/^#{overlap.join('/')}\//,'') + partial.insert(0, "#{File.dirname(path)}/") end end diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 2b9427ace5..5f7fe81bd5 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -161,7 +161,7 @@ module ActionView # Returns the file mtime from the filesystem. def mtime(p) - File.stat(p).mtime + File.mtime(p) end # Extract handler and formats from path. If a format cannot be a found neither diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 0236350576..50278cffcd 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -1,26 +1,24 @@ namespace :assets do + # Ensures the RAILS_GROUPS environment variable is set + task :ensure_env do + ENV["RAILS_GROUPS"] ||= "assets" + end + desc "Compile all the assets named in config.assets.precompile" - task :precompile do - if ENV["RAILS_GROUPS"].to_s.empty? - ENV["RAILS_GROUPS"] = "assets" - Kernel.exec $0, *ARGV - else - Rake::Task["environment"].invoke - Sprockets::Helpers::RailsHelper + task :precompile => :ensure_env do + Rake::Task["environment"].invoke + Sprockets::Helpers::RailsHelper - assets = Rails.application.config.assets.precompile - Rails.application.assets.precompile(*assets) - end + assets = Rails.application.config.assets.precompile + # Always perform caching so that asset_path appends the timestamps to file references. + Rails.application.config.action_controller.perform_caching = true + Rails.application.assets.precompile(*assets) end desc "Remove compiled assets" task :clean => :environment do assets = Rails.application.config.assets public_asset_path = Rails.public_path + assets.prefix - file_list = FileList.new("#{public_asset_path}/**/*") - file_list.each do |file| - rm_rf file - rm_rf "#{file}.gz" - end + rm_rf public_asset_path, :secure => true end end diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index a95e7c0649..ec3d36d5ad 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -72,6 +72,8 @@ module Sprockets def debug_assets? params[:debug_assets] == '1' || params[:debug_assets] == 'true' + rescue NoMethodError + false end # Override to specify an alternative prefix for asset path generation. diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index 4906ad9a9c..83799d2b4d 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -11,13 +11,6 @@ module Sprockets load "sprockets/assets.rake" end - # Configure ActionController to use sprockets. - initializer "sprockets.set_configs", :after => "action_controller.set_configs" do |app| - ActiveSupport.on_load(:action_controller) do - self.use_sprockets = app.config.assets.enabled - end - end - # We need to configure this after initialization to ensure we collect # paths from all engines. This hook is invoked exactly before routes # are compiled, and so that other Railties have an opportunity to @@ -61,10 +54,10 @@ module Sprockets env.paths.concat assets.paths end - env.logger = Rails.logger + env.logger = ::Rails.logger if env.respond_to?(:cache) && assets.cache_store != false - env.cache = ActiveSupport::Cache.lookup_store(assets.cache_store) || Rails.cache + env.cache = ActiveSupport::Cache.lookup_store(assets.cache_store) || ::Rails.cache end if assets.compress diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb index 80c4fa2ee5..ccdfcb0b2c 100644 --- a/actionpack/test/controller/log_subscriber_test.rb +++ b/actionpack/test/controller/log_subscriber_test.rb @@ -6,6 +6,13 @@ module Another class LogSubscribersController < ActionController::Base wrap_parameters :person, :include => :name, :format => :json + class SpecialException < Exception + end + + rescue_from SpecialException do + head :status => 406 + end + def show render :nothing => true end @@ -39,6 +46,10 @@ module Another raise Exception end + def with_rescued_exception + raise SpecialException + end + end end @@ -195,6 +206,14 @@ class ACLogSubscriberTest < ActionController::TestCase assert_match(/Completed 500/, logs.last) end + def test_process_action_with_rescued_exception_includes_http_status_code + get :with_rescued_exception + wait + + assert_equal 2, logs.size + assert_match(/Completed 406/, logs.last) + end + def logs @logs ||= @logger.logged(:info) end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index be59da9105..ce4b407c7d 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -14,6 +14,14 @@ module Fun end end +module Quiz + class QuestionsController < ActionController::Base + def new + render :partial => Quiz::Question.new("Namespaced Partial") + end + end +end + class TestController < ActionController::Base protect_from_forgery @@ -1251,6 +1259,12 @@ class RenderTest < ActionController::TestCase assert_template('fun/games/_form') end + def test_namespaced_object_partial + @controller = Quiz::QuestionsController.new + get :new + assert_equal "Namespaced Partial", @response.body + end + def test_partial_collection get :partial_collection assert_equal "Hello: davidHello: mary", @response.body diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb index b6c08ffc33..81f0efb76e 100644 --- a/actionpack/test/dispatch/mapper_test.rb +++ b/actionpack/test/dispatch/mapper_test.rb @@ -83,6 +83,13 @@ module ActionDispatch assert_equal '/*path', fakeset.conditions.first[:path_info] assert_nil fakeset.requirements.first[:path] end + + def test_map_wildcard_with_format_true + fakeset = FakeSet.new + mapper = Mapper.new fakeset + mapper.match '/*path', :to => 'pages#show', :format => true + assert_equal '/*path.:format', fakeset.conditions.first[:path_info] + end end end end diff --git a/actionpack/test/dispatch/prefix_generation_test.rb b/actionpack/test/dispatch/prefix_generation_test.rb index b28a058250..93eccaecbd 100644 --- a/actionpack/test/dispatch/prefix_generation_test.rb +++ b/actionpack/test/dispatch/prefix_generation_test.rb @@ -50,7 +50,9 @@ module TestGenerationPrefix scope "/:omg", :omg => "awesome" do mount BlogEngine => "/blog", :as => "blog_engine" end + match "/posts/:id", :to => "outside_engine_generating#post", :as => :post match "/generate", :to => "outside_engine_generating#index" + match "/polymorphic_path_for_app", :to => "outside_engine_generating#polymorphic_path_for_app" match "/polymorphic_path_for_engine", :to => "outside_engine_generating#polymorphic_path_for_engine" match "/polymorphic_with_url_for", :to => "outside_engine_generating#polymorphic_with_url_for" match "/conflicting_url", :to => "outside_engine_generating#conflicting" @@ -101,6 +103,7 @@ module TestGenerationPrefix class ::OutsideEngineGeneratingController < ActionController::Base include BlogEngine.routes.mounted_helpers + include RailsApplication.routes.url_helpers def index render :text => blog_engine.post_path(:id => 1) @@ -110,6 +113,10 @@ module TestGenerationPrefix render :text => blog_engine.polymorphic_path(Post.new) end + def polymorphic_path_for_app + render :text => polymorphic_path(Post.new) + end + def polymorphic_with_url_for render :text => blog_engine.url_for(Post.new) end @@ -201,6 +208,11 @@ module TestGenerationPrefix assert_equal "/awesome/blog/posts/1", last_response.body end + test "polymorphic_path_for_app" do + get "/polymorphic_path_for_app" + assert_equal "/posts/1", last_response.body + end + test "[APP] generating engine's url with url_for(@post)" do get "/polymorphic_with_url_for" assert_equal "http://example.org/awesome/blog/posts/1", last_response.body diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 25b1b4f745..060bcfb5ec 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -468,6 +468,12 @@ class RequestTest < ActiveSupport::TestCase assert request.formats.empty? end + test "formats with xhr request" do + request = stub_request 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + request.expects(:parameters).at_least_once.returns({}) + assert_equal [Mime::JS], request.formats + end + test "ignore_accept_header" do ActionDispatch::Request.ignore_accept_header = true diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index ba7506721f..1938348375 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -504,6 +504,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest match '/countries/:country/(*other)', :to => redirect{ |params, req| params[:other] ? "/countries/all/#{params[:other]}" : '/countries/all' } match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/ + + scope '/italians' do + match '/writers', :to => 'italians#writers', :constraints => ::TestRoutingMapper::IpRestrictor + match '/sculptors', :to => 'italians#sculptors' + match '/painters/:painter', :to => 'italians#painters', :constraints => {:painter => /michelangelo/} + end end end @@ -2229,6 +2235,20 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest verify_redirect 'http://www.example.com/countries/all/cities' end + def test_constraints_block_not_carried_to_following_routes + get '/italians/writers' + assert_equal 'Not Found', @response.body + + get '/italians/sculptors' + assert_equal 'italians#sculptors', @response.body + + get '/italians/painters/botticelli' + assert_equal 'Not Found', @response.body + + get '/italians/painters/michelangelo' + assert_equal 'italians#painters', @response.body + end + def test_custom_resource_actions_defined_using_string get '/customers/inactive' assert_equal 'customers#inactive', @response.body diff --git a/actionpack/test/fixtures/test/_200.html.erb b/actionpack/test/fixtures/test/_200.html.erb new file mode 100644 index 0000000000..c9f45675dc --- /dev/null +++ b/actionpack/test/fixtures/test/_200.html.erb @@ -0,0 +1 @@ +<h1>Invalid partial</h1> diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index d5bd7256f7..d93433deac 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -443,7 +443,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_image_tag_windows_behaviour old_asset_id, ENV["RAILS_ASSET_ID"] = ENV["RAILS_ASSET_ID"], "1" - # This simulates the behaviour of File#exist? on windows when testing a file ending in "." + # This simulates the behavior of File#exist? on windows when testing a file ending in "." # If the file "rails.png" exists, windows will return true when asked if "rails.png." exists (notice trailing ".") # OS X, linux etc will return false in this case. File.stubs(:exist?).with('template/../fixtures/public/images/rails.png.').returns(true) @@ -481,7 +481,7 @@ class AssetTagHelperTest < ActionView::TestCase end def test_timebased_asset_id - expected_time = File.stat(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).mtime.to_i.to_s + expected_time = File.mtime(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).to_i.to_s assert_equal %(<img alt="Rails" src="/images/rails.png?#{expected_time}" />), image_tag("rails.png") end @@ -512,7 +512,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_timebased_asset_id_with_relative_url_root @controller.config.relative_url_root = "/collaboration/hieraki" - expected_time = File.stat(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).mtime.to_i.to_s + expected_time = File.mtime(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).to_i.to_s assert_equal %(<img alt="Rails" src="#{@controller.config.relative_url_root}/images/rails.png?#{expected_time}" />), image_tag("rails.png") end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 4187a0ac78..68b2ed45d1 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -98,6 +98,15 @@ module RenderTestCases assert_equal "only partial", @view.render("test/partial_only", :counter_counter => 5) end + def test_render_partial_with_invalid_name + @view.render(:partial => "test/200") + flunk "Render did not raise ArgumentError" + rescue ArgumentError => e + assert_equal "The partial name (test/200) is not a valid Ruby identifier; " + + "make sure your partial name starts with a letter or underscore, " + + "and is followed by any combinations of letters, numbers, or underscores.", e.message + end + def test_render_partial_with_errors @view.render(:partial => "test/raise") flunk "Render did not raise Template::Error" diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index f11d1bba15..b9161b62c5 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -4,33 +4,29 @@ require 'sprockets/helpers/rails_helper' require 'mocha' class SprocketsHelperTest < ActionView::TestCase - tests Sprockets::Helpers::RailsHelper + include Sprockets::Helpers::RailsHelper attr_accessor :assets + class MockRequest + def protocol() 'http://' end + def ssl?() false end + def host_with_port() 'localhost' end + end + def setup super - @controller = BasicController.new - @controller.stubs(:params).returns({}) - - @request = Class.new do - def protocol() 'http://' end - def ssl?() false end - def host_with_port() 'localhost' end - end.new - - @controller.request = @request + @controller = BasicController.new + @controller.request = MockRequest.new @assets = Sprockets::Environment.new - @assets.paths << FIXTURES.join("sprockets/app/javascripts") - @assets.paths << FIXTURES.join("sprockets/app/stylesheets") - @assets.paths << FIXTURES.join("sprockets/app/images") + @assets.append_path(FIXTURES.join("sprockets/app/javascripts")) + @assets.append_path(FIXTURES.join("sprockets/app/stylesheets")) + @assets.append_path(FIXTURES.join("sprockets/app/images")) - application = Object.new + application = Struct.new(:config, :assets).new(config, @assets) Rails.stubs(:application).returns(application) - application.stubs(:config).returns(config) - application.stubs(:assets).returns(@assets) @config = config @config.action_controller ||= ActiveSupport::InheritableOptions.new @config.perform_caching = true @@ -41,7 +37,7 @@ class SprocketsHelperTest < ActionView::TestCase end test "asset_path" do - assert_equal "/assets/logo-9c0a079bdd7701d7e729bd956823d153.png", + assert_match %r{/assets/logo-[0-9a-f]+.png}, asset_path("logo.png") end @@ -54,7 +50,7 @@ class SprocketsHelperTest < ActionView::TestCase assert_equal "/dir/audio", asset_path("/dir/audio") end - + test "asset_path with absolute urls" do assert_equal "http://www.example.com/video/play", asset_path("http://www.example.com/video/play") @@ -74,7 +70,7 @@ class SprocketsHelperTest < ActionView::TestCase assert_match %r{http://assets-\d.example.com/assets/logo-[0-9a-f]+.png}, asset_path("logo.png") end - + test "With a proc asset host that returns no protocol the url should be protocol relative" do @controller.config.asset_host = Proc.new do |asset| "assets-999.example.com" @@ -116,7 +112,7 @@ class SprocketsHelperTest < ActionView::TestCase @config.action_controller.default_asset_host_protocol = :request @config.action_controller.perform_caching = true - assert_equal "/assets/logo-9c0a079bdd7701d7e729bd956823d153.png", + assert_match %r{/assets/logo-[0-9a-f]+.png}, asset_path("logo.png") end @@ -127,12 +123,12 @@ class SprocketsHelperTest < ActionView::TestCase end test "javascript path" do - assert_equal "/assets/application-d41d8cd98f00b204e9800998ecf8427e.js", + assert_match %r{/assets/application-[0-9a-f]+.js}, asset_path(:application, "js") - assert_equal "/assets/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js", + assert_match %r{/assets/xmlhr-[0-9a-f]+.js}, asset_path("xmlhr", "js") - assert_equal "/assets/dir/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js", + assert_match %r{/assets/dir/xmlhr-[0-9a-f]+.js}, asset_path("dir/xmlhr.js", "js") assert_equal "/dir/xmlhr.js", @@ -145,28 +141,28 @@ class SprocketsHelperTest < ActionView::TestCase end test "javascript include tag" do - assert_equal '<script src="/assets/application-d41d8cd98f00b204e9800998ecf8427e.js" type="text/javascript"></script>', + assert_match %r{<script src="/assets/application-[0-9a-f]+.js" type="text/javascript"></script>}, javascript_include_tag(:application) - assert_equal '<script src="/assets/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js" type="text/javascript"></script>', + assert_match %r{<script src="/assets/xmlhr-[0-9a-f]+.js" type="text/javascript"></script>}, javascript_include_tag("xmlhr") - assert_equal '<script src="/assets/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js" type="text/javascript"></script>', + assert_match %r{<script src="/assets/xmlhr-[0-9a-f]+.js" type="text/javascript"></script>}, javascript_include_tag("xmlhr.js") assert_equal '<script src="http://www.example.com/xmlhr" type="text/javascript"></script>', javascript_include_tag("http://www.example.com/xmlhr") - assert_equal "<script src=\"/assets/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js?body=1\" type=\"text/javascript\"></script>\n<script src=\"/assets/application-d41d8cd98f00b204e9800998ecf8427e.js?body=1\" type=\"text/javascript\"></script>", + assert_match %r{<script src="/assets/xmlhr-[0-9a-f]+.js\?body=1" type="text/javascript"></script>\n<script src="/assets/application-[0-9a-f]+.js\?body=1" type="text/javascript"></script>}, javascript_include_tag(:application, :debug => true) - assert_equal "<script src=\"/assets/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js\" type=\"text/javascript\"></script>\n<script src=\"/assets/extra-d41d8cd98f00b204e9800998ecf8427e.js\" type=\"text/javascript\"></script>", + assert_match %r{<script src=\"/assets/xmlhr-[0-9a-f]+.js\" type=\"text/javascript\"></script>\n<script src=\"/assets/extra-[0-9a-f]+.js\" type=\"text/javascript\"></script>}, javascript_include_tag("xmlhr", "extra") end test "stylesheet path" do - assert_equal "/assets/application-68b329da9893e34099c7d8ad5cb9c940.css", asset_path(:application, "css") + assert_match %r{/assets/application-[0-9a-f]+.css}, asset_path(:application, "css") - assert_equal "/assets/style-d41d8cd98f00b204e9800998ecf8427e.css", asset_path("style", "css") - assert_equal "/assets/dir/style-d41d8cd98f00b204e9800998ecf8427e.css", asset_path("dir/style.css", "css") + assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", "css") + assert_match %r{/assets/dir/style-[0-9a-f]+.css}, asset_path("dir/style.css", "css") assert_equal "/dir/style.css", asset_path("/dir/style.css", "css") assert_equal "http://www.example.com/css/style", @@ -176,37 +172,37 @@ class SprocketsHelperTest < ActionView::TestCase end test "stylesheet link tag" do - assert_equal '<link href="/assets/application-68b329da9893e34099c7d8ad5cb9c940.css" media="screen" rel="stylesheet" type="text/css" />', + assert_match %r{<link href="/assets/application-[0-9a-f]+.css" media="screen" rel="stylesheet" type="text/css" />}, stylesheet_link_tag(:application) - assert_equal '<link href="/assets/style-d41d8cd98f00b204e9800998ecf8427e.css" media="screen" rel="stylesheet" type="text/css" />', + assert_match %r{<link href="/assets/style-[0-9a-f]+.css" media="screen" rel="stylesheet" type="text/css" />}, stylesheet_link_tag("style") - assert_equal '<link href="/assets/style-d41d8cd98f00b204e9800998ecf8427e.css" media="screen" rel="stylesheet" type="text/css" />', + assert_match %r{<link href="/assets/style-[0-9a-f]+.css" media="screen" rel="stylesheet" type="text/css" />}, stylesheet_link_tag("style.css") assert_equal '<link href="http://www.example.com/style.css" media="screen" rel="stylesheet" type="text/css" />', stylesheet_link_tag("http://www.example.com/style.css") - assert_equal '<link href="/assets/style-d41d8cd98f00b204e9800998ecf8427e.css" media="all" rel="stylesheet" type="text/css" />', + assert_match %r{<link href="/assets/style-[0-9a-f]+.css" media="all" rel="stylesheet" type="text/css" />}, stylesheet_link_tag("style", :media => "all") - assert_equal '<link href="/assets/style-d41d8cd98f00b204e9800998ecf8427e.css" media="print" rel="stylesheet" type="text/css" />', + assert_match %r{<link href="/assets/style-[0-9a-f]+.css" media="print" rel="stylesheet" type="text/css" />}, stylesheet_link_tag("style", :media => "print") - assert_equal "<link href=\"/assets/style-d41d8cd98f00b204e9800998ecf8427e.css?body=1\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n<link href=\"/assets/application-68b329da9893e34099c7d8ad5cb9c940.css?body=1\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />", + assert_match %r{<link href="/assets/style-[0-9a-f]+.css\?body=1" media="screen" rel="stylesheet" type="text/css" />\n<link href="/assets/application-[0-9a-f]+.css\?body=1" media="screen" rel="stylesheet" type="text/css" />}, stylesheet_link_tag(:application, :debug => true) - assert_equal "<link href=\"/assets/style-d41d8cd98f00b204e9800998ecf8427e.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n<link href=\"/assets/extra-d41d8cd98f00b204e9800998ecf8427e.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />", + assert_match %r{<link href="/assets/style-[0-9a-f]+.css" media="screen" rel="stylesheet" type="text/css" />\n<link href="/assets/extra-[0-9a-f]+.css" media="screen" rel="stylesheet" type="text/css" />}, stylesheet_link_tag("style", "extra") end test "alternate asset prefix" do stubs(:asset_prefix).returns("/themes/test") - assert_equal "/themes/test/style-d41d8cd98f00b204e9800998ecf8427e.css", asset_path("style", "css") + assert_match %r{/themes/test/style-[0-9a-f]+.css}, asset_path("style", "css") end test "alternate asset environment" do assets = Sprockets::Environment.new - assets.paths << FIXTURES.join("sprockets/alternate/stylesheets") + assets.append_path(FIXTURES.join("sprockets/alternate/stylesheets")) stubs(:asset_environment).returns(assets) - assert_equal "/assets/style-df0b97ad35a8e1f7f61097461f77c19a.css", asset_path("style", "css") + assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", "css") end end diff --git a/actionpack/test/template/test_test.rb b/actionpack/test/template/test_test.rb index 3d0bbba435..bf789cd8b7 100644 --- a/actionpack/test/template/test_test.rb +++ b/actionpack/test/template/test_test.rb @@ -39,7 +39,7 @@ class PeopleHelperTest < ActionView::TestCase with_test_route_set do person = mock(:name => "David") person.class.extend ActiveModel::Naming - _routes.url_helpers.expects(:hash_for_mocha_mock_path).with(person).returns("/people/1") + expects(:mocha_mock_path).with(person).returns("/people/1") assert_equal '<a href="/people/1">David</a>', link_to_person(person) end end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index a70c02a429..78245c1f95 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -386,13 +386,11 @@ class UrlHelperTest < ActiveSupport::TestCase def test_mail_to_with_javascript snippet = mail_to("me@domain.com", "My email", :encode => "javascript") assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%5c%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%5c%22%3e%4d%79%20%65%6d%61%69%6c%3c%5c%2f%61%3e%27%29%3b'))</script>", snippet - assert snippet.html_safe? end def test_mail_to_with_javascript_unicode snippet = mail_to("unicode@example.com", "Ășnicode", :encode => "javascript") assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%5c%22%6d%61%69%6c%74%6f%3a%75%6e%69%63%6f%64%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%5c%22%3e%c3%ba%6e%69%63%6f%64%65%3c%5c%2f%61%3e%27%29%3b'))</script>", snippet - assert snippet.html_safe end def test_mail_with_options @@ -421,6 +419,12 @@ class UrlHelperTest < ActiveSupport::TestCase assert_dom_equal "<script type=\"text/javascript\">eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%5c%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%5c%22%3e%6d%65%28%61%74%29%64%6f%6d%61%69%6e%28%64%6f%74%29%63%6f%6d%3c%5c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", nil, :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)") end + def test_mail_to_returns_html_safe_string + assert mail_to("david@loudthinking.com").html_safe? + assert mail_to("me@domain.com", "My email", :encode => "javascript").html_safe? + assert mail_to("me@domain.com", "My email", :encode => "hex").html_safe? + end + # TODO: button_to looks at this ... why? def protect_against_forgery? false |