diff options
author | rick <rick@spacemonkey.local> | 2008-05-10 17:46:55 -0700 |
---|---|---|
committer | rick <rick@spacemonkey.local> | 2008-05-10 17:46:55 -0700 |
commit | d09a8446d5606a5a0b5c024224b09a1318e9cf4d (patch) | |
tree | 199ef3554f731c980ea5726e67e34af4ea057c2e /actionpack | |
parent | c8451aeeea200043d8a3e6eae9c49def3a154ddb (diff) | |
parent | a7ea06b4ebe252e258f83e7de945b4baa30ec3bc (diff) | |
download | rails-d09a8446d5606a5a0b5c024224b09a1318e9cf4d.tar.gz rails-d09a8446d5606a5a0b5c024224b09a1318e9cf4d.tar.bz2 rails-d09a8446d5606a5a0b5c024224b09a1318e9cf4d.zip |
fix merge conflict with actionpack changelog
Diffstat (limited to 'actionpack')
25 files changed, 493 insertions, 202 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 87f570d55c..852e783f40 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,6 +1,9 @@ *SVN* * Change the request forgery protection to go by Content-Type instead of request.format so that you can't bypass it by POSTing to "#{request.uri}.xml" [rick] +* InstanceTag#default_time_from_options with hash args uses Time.current as default; respects hash settings when time falls in system local spring DST gap [Geoff Buesing] + +* select_date defaults to Time.zone.today when config.time_zone is set [Geoff Buesing] * Fixed that TextHelper#text_field would corrypt when raw HTML was used as the value (mchenryc, Kevin Glowacz) [#80] diff --git a/actionpack/lib/action_controller/assertions/selector_assertions.rb b/actionpack/lib/action_controller/assertions/selector_assertions.rb index 272b8f6841..9ef093acfc 100644 --- a/actionpack/lib/action_controller/assertions/selector_assertions.rb +++ b/actionpack/lib/action_controller/assertions/selector_assertions.rb @@ -21,11 +21,11 @@ module ActionController # from the response HTML or elements selected by the enclosing assertion. # # In addition to HTML responses, you can make the following assertions: - # * #assert_select_rjs -- Assertions on HTML content of RJS update and + # * +assert_select_rjs+ - Assertions on HTML content of RJS update and # insertion operations. - # * #assert_select_encoded -- Assertions on HTML encoded inside XML, + # * +assert_select_encoded+ - Assertions on HTML encoded inside XML, # for example for dealing with feed item descriptions. - # * #assert_select_email -- Assertions on the HTML body of an e-mail. + # * +assert_select_email+ - Assertions on the HTML body of an e-mail. # # Also see HTML::Selector to learn how to use selectors. module SelectorAssertions @@ -136,27 +136,27 @@ module ActionController # === Equality Tests # # The equality test may be one of the following: - # * <tt>true</tt> -- Assertion is true if at least one element selected. - # * <tt>false</tt> -- Assertion is true if no element selected. - # * <tt>String/Regexp</tt> -- Assertion is true if the text value of at least + # * <tt>true</tt> - Assertion is true if at least one element selected. + # * <tt>false</tt> - Assertion is true if no element selected. + # * <tt>String/Regexp</tt> - Assertion is true if the text value of at least # one element matches the string or regular expression. - # * <tt>Integer</tt> -- Assertion is true if exactly that number of + # * <tt>Integer</tt> - Assertion is true if exactly that number of # elements are selected. - # * <tt>Range</tt> -- Assertion is true if the number of selected + # * <tt>Range</tt> - Assertion is true if the number of selected # elements fit the range. # If no equality test specified, the assertion is true if at least one # element selected. # # To perform more than one equality tests, use a hash with the following keys: - # * <tt>:text</tt> -- Narrow the selection to elements that have this text + # * <tt>:text</tt> - Narrow the selection to elements that have this text # value (string or regexp). - # * <tt>:html</tt> -- Narrow the selection to elements that have this HTML + # * <tt>:html</tt> - Narrow the selection to elements that have this HTML # content (string or regexp). - # * <tt>:count</tt> -- Assertion is true if the number of selected elements + # * <tt>:count</tt> - Assertion is true if the number of selected elements # is equal to this value. - # * <tt>:minimum</tt> -- Assertion is true if the number of selected + # * <tt>:minimum</tt> - Assertion is true if the number of selected # elements is at least this value. - # * <tt>:maximum</tt> -- Assertion is true if the number of selected + # * <tt>:maximum</tt> - Assertion is true if the number of selected # elements is at most this value. # # If the method is called with a block, once all equality tests are diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index c6d28b492a..e1bf005f39 100755 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -159,28 +159,34 @@ module ActionController #:nodoc: # # Hello #{session[:person]} # - # For removing objects from the session, you can either assign a single key to nil, like <tt>session[:person] = nil</tt>, or you can - # remove the entire session with reset_session. + # For removing objects from the session, you can either assign a single key to +nil+: # - # Sessions are stored in a browser cookie that's cryptographically signed, but unencrypted, by default. This prevents - # the user from tampering with the session but also allows him to see its contents. + # # removes :person from session + # session[:person] = nil # - # Do not put secret information in session! + # or you can remove the entire session with +reset_session+. + # + # Sessions are stored by default in a browser cookie that's cryptographically signed, but unencrypted. + # This prevents the user from tampering with the session but also allows him to see its contents. + # + # Do not put secret information in cookie-based sessions! # # Other options for session storage are: # - # ActiveRecordStore: sessions are stored in your database, which works better than PStore with multiple app servers and, - # unlike CookieStore, hides your session contents from the user. To use ActiveRecordStore, set + # * ActiveRecordStore - Sessions are stored in your database, which works better than PStore with multiple app servers and, + # unlike CookieStore, hides your session contents from the user. To use ActiveRecordStore, set # - # config.action_controller.session_store = :active_record_store + # config.action_controller.session_store = :active_record_store # - # in your <tt>environment.rb</tt> and run <tt>rake db:sessions:create</tt>. + # in your <tt>config/environment.rb</tt> and run <tt>rake db:sessions:create</tt>. # - # MemCacheStore: sessions are stored as entries in your memcached cache. Set the session store type in <tt>environment.rb</tt>: + # * MemCacheStore - Sessions are stored as entries in your memcached cache. + # Set the session store type in <tt>config/environment.rb</tt>: # - # config.action_controller.session_store = :mem_cache_store + # config.action_controller.session_store = :mem_cache_store # - # This assumes that memcached has been installed and configured properly. See the MemCacheStore docs for more information. + # This assumes that memcached has been installed and configured properly. + # See the MemCacheStore docs for more information. # # == Responses # @@ -535,20 +541,20 @@ module ActionController #:nodoc: # # <tt>url_for</tt> is used to: # - # All keys given to url_for are forwarded to the Route module, save for the following: - # * <tt>:anchor</tt> -- specifies the anchor name to be appended to the path. For example, + # All keys given to +url_for+ are forwarded to the Route module, save for the following: + # * <tt>:anchor</tt> - Specifies the anchor name to be appended to the path. For example, # <tt>url_for :controller => 'posts', :action => 'show', :id => 10, :anchor => 'comments'</tt> # will produce "/posts/show/10#comments". - # * <tt>:only_path</tt> -- if true, returns the relative URL (omitting the protocol, host name, and port) (<tt>false</tt> by default) - # * <tt>:trailing_slash</tt> -- if true, adds a trailing slash, as in "/archive/2005/". Note that this + # * <tt>:only_path</tt> - If true, returns the relative URL (omitting the protocol, host name, and port) (<tt>false</tt> by default). + # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2005/". Note that this # is currently not recommended since it breaks caching. - # * <tt>:host</tt> -- overrides the default (current) host if provided. - # * <tt>:protocol</tt> -- overrides the default (current) protocol if provided. - # * <tt>:port</tt> -- optionally specify the port to connect to. - # * <tt>:user</tt> -- Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present). - # * <tt>:password</tt> -- Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present). - # * <tt>:skip_relative_url_root</tt> -- if true, the url is not constructed using the relative_url_root of the request so the path - # will include the web server relative installation directory. + # * <tt>:host</tt> - Overrides the default (current) host if provided. + # * <tt>:protocol</tt> - Overrides the default (current) protocol if provided. + # * <tt>:port</tt> - Optionally specify the port to connect to. + # * <tt>:user</tt> - Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present). + # * <tt>:password</tt> - Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present). + # * <tt>:skip_relative_url_root</tt> - If true, the url is not constructed using the +relative_url_root+ + # of the request so the path will include the web server relative installation directory. # # The URL is generated from the remaining keys in the hash. A URL contains two key parts: the <base> and a query string. # Routes composes a query string as the key/value pairs not included in the <base>. diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index 08cbd13876..c4063dfb4b 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -20,7 +20,8 @@ module ActionController #:nodoc: # # == Caching stores # - # All the caching stores from ActiveSupport::Cache is available to be used as backends for Action Controller caching. + # All the caching stores from ActiveSupport::Cache is available to be used as backends for Action Controller caching. This setting only + # affects action and fragment caching as page caching is always written to disk. # # Configuration examples (MemoryStore is the default): # diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb index 7aa6ce154b..a70ed72f03 100644 --- a/actionpack/lib/action_controller/caching/pages.rb +++ b/actionpack/lib/action_controller/caching/pages.rb @@ -4,23 +4,24 @@ require 'uri' module ActionController #:nodoc: module Caching # Page caching is an approach to caching where the entire action output of is stored as a HTML file that the web server - # can serve without going through the Action Pack. This can be as much as 100 times faster than going through the process of dynamically - # generating the content. Unfortunately, this incredible speed-up is only available to stateless pages where all visitors - # are treated the same. Content management systems -- including weblogs and wikis -- have many pages that are a great fit - # for this approach, but account-based systems where people log in and manipulate their own data are often less likely candidates. + # can serve without going through Action Pack. This is the fastest way to cache your content as opposed to going dynamically + # through the process of generating the content. Unfortunately, this incredible speed-up is only available to stateless pages + # where all visitors are treated the same. Content management systems -- including weblogs and wikis -- have many pages that are + # a great fit for this approach, but account-based systems where people log in and manipulate their own data are often less + # likely candidates. # - # Specifying which actions to cache is done through the <tt>caches</tt> class method: + # Specifying which actions to cache is done through the <tt>caches_page</tt> class method: # # class WeblogController < ActionController::Base # caches_page :show, :new # end # - # This will generate cache files such as weblog/show/5 and weblog/new, which match the URLs used to trigger the dynamic - # generation. This is how the web server is able pick up a cache file when it exists and otherwise let the request pass on to - # the Action Pack to generate it. + # This will generate cache files such as <tt>weblog/show/5.html</tt> and <tt>weblog/new.html</tt>, + # which match the URLs used to trigger the dynamic generation. This is how the web server is able + # pick up a cache file when it exists and otherwise let the request pass on to Action Pack to generate it. # # Expiration of the cache is handled by deleting the cached file, which results in a lazy regeneration approach where the cache - # is not restored before another hit is made against it. The API for doing so mimics the options from url_for and friends: + # is not restored before another hit is made against it. The API for doing so mimics the options from +url_for+ and friends: # # class WeblogController < ActionController::Base # def update @@ -35,13 +36,17 @@ module ActionController #:nodoc: # # == Setting the cache directory # - # The cache directory should be the document root for the web server and is set using Base.page_cache_directory = "/document/root". - # For Rails, this directory has already been set to Rails.public_path (which is usually set to RAILS_ROOT + "/public"). + # The cache directory should be the document root for the web server and is set using <tt>Base.page_cache_directory = "/document/root"</tt>. + # For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>RAILS_ROOT + "/public"</tt>). Changing + # this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your + # web server to look in the new location for cached files. # # == Setting the cache extension # - # By default, the cache extension is .html, which makes it easy for the cached files to be picked up by the web server. If you want - # something else, like .php or .shtml, just set Base.page_cache_extension. + # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>. In these cases, the page caching mechanism will add one in + # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>. + # If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an + # extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps. module Pages def self.included(base) #:nodoc: base.extend(ClassMethods) diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb index aa0e05dbd7..e2b7716aa2 100644 --- a/actionpack/lib/action_controller/polymorphic_routes.rb +++ b/actionpack/lib/action_controller/polymorphic_routes.rb @@ -47,25 +47,27 @@ module ActionController # Constructs a call to a named RESTful route for the given record and returns the # resulting URL string. For example: # - # polymorphic_url(post) - # # calls post_url(post) #=> "http://example.com/posts/1" + # # calls post_url(post) + # polymorphic_url(post) # => "http://example.com/posts/1" # # ==== Options - # * <tt>:action</tt> -- specifies the action prefix for the named route: - # <tt>:new</tt>, <tt>:edit</tt> or <tt>:formatted</tt>. Default is no prefix. - # * <tt>:routing_type</tt> -- <tt>:path</tt> or <tt>:url</tt> (default <tt>:url</tt>). + # + # * <tt>:action</tt> - Specifies the action prefix for the named route: + # <tt>:new</tt>, <tt>:edit</tt>, or <tt>:formatted</tt>. Default is no prefix. + # * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>. + # Default is <tt>:url</tt>. # # ==== Examples # # # an Article record - # polymorphic_url(record) #-> article_url(record) + # polymorphic_url(record) # same as article_url(record) # # # a Comment record - # polymorphic_url(record) #-> comment_url(record) + # polymorphic_url(record) # same as comment_url(record) # # # it recognizes new records and maps to the collection # record = Comment.new - # polymorphic_url(record) #-> comments_url() + # polymorphic_url(record) # same as comments_url() # def polymorphic_url(record_or_hash_or_array, options = {}) if record_or_hash_or_array.kind_of?(Array) diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb index 22dbc8bbc5..643ff7e5f4 100644 --- a/actionpack/lib/action_controller/record_identifier.rb +++ b/actionpack/lib/action_controller/record_identifier.rb @@ -33,11 +33,17 @@ module ActionController # Returns plural/singular for a record or class. Example: # - # partial_path(post) # => "posts/post" - # partial_path(Person) # => "people/person" - def partial_path(record_or_class) + # partial_path(post) # => "posts/post" + # partial_path(Person) # => "people/person" + # partial_path(Person, "admin/games") # => "admin/people/person" + def partial_path(record_or_class, controller_path = nil) klass = class_from_record_or_class(record_or_class) - "#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + + if controller_path && controller_path.include?("/") + "#{File.dirname(controller_path)}/#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + else + "#{klass.name.tableize}/#{klass.name.demodulize.underscore}" + end end # The DOM class convention is to use the singular form of an object or class. Examples: diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/request_forgery_protection.rb index b52a2d4ff1..946a0ed152 100644 --- a/actionpack/lib/action_controller/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/request_forgery_protection.rb @@ -69,10 +69,10 @@ module ActionController #:nodoc: # # Valid Options: # - # * <tt>:only/:except</tt> - passed to the <tt>before_filter</tt> call. Set which actions are verified. + # * <tt>:only/:except</tt> - Passed to the <tt>before_filter</tt> call. Set which actions are verified. # * <tt>:secret</tt> - Custom salt used to generate the <tt>form_authenticity_token</tt>. # Leave this off if you are using the cookie session store. - # * <tt>:digest</tt> - Message digest used for hashing. Defaults to 'SHA1' + # * <tt>:digest</tt> - Message digest used for hashing. Defaults to 'SHA1'. def protect_from_forgery(options = {}) self.request_forgery_protection_token ||= :authenticity_token before_filter :verify_authenticity_token, :only => options.delete(:only), :except => options.delete(:except) diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index 0f0fa27d74..26f75780c1 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -236,27 +236,27 @@ module ActionController # which takes into account whether <tt>@message</tt> is a new record or not and generates the # path and method accordingly. # - # The #resources method accepts the following options to customize the resulting routes: - # * <tt>:collection</tt> - add named routes for other actions that operate on the collection. + # The +resources+ method accepts the following options to customize the resulting routes: + # * <tt>:collection</tt> - Add named routes for other actions that operate on the collection. # Takes a hash of <tt>#{action} => #{method}</tt>, where method is <tt>:get</tt>/<tt>:post</tt>/<tt>:put</tt>/<tt>:delete</tt> - # or <tt>:any</tt> if the method does not matter. These routes map to a URL like /messages/rss, with a route of rss_messages_url. - # * <tt>:member</tt> - same as <tt>:collection</tt>, but for actions that operate on a specific member. - # * <tt>:new</tt> - same as <tt>:collection</tt>, but for actions that operate on the new resource action. - # * <tt>:controller</tt> - specify the controller name for the routes. - # * <tt>:singular</tt> - specify the singular name used in the member routes. - # * <tt>:requirements</tt> - set custom routing parameter requirements. - # * <tt>:conditions</tt> - specify custom routing recognition conditions. Resources sets the <tt>:method</tt> value for the method-specific routes. - # * <tt>:as</tt> - specify a different resource name to use in the URL path. For example: + # or <tt>:any</tt> if the method does not matter. These routes map to a URL like /messages/rss, with a route of +rss_messages_url+. + # * <tt>:member</tt> - Same as <tt>:collection</tt>, but for actions that operate on a specific member. + # * <tt>:new</tt> - Same as <tt>:collection</tt>, but for actions that operate on the new resource action. + # * <tt>:controller</tt> - Specify the controller name for the routes. + # * <tt>:singular</tt> - Specify the singular name used in the member routes. + # * <tt>:requirements</tt> - Set custom routing parameter requirements. + # * <tt>:conditions</tt> - Specify custom routing recognition conditions. Resources sets the <tt>:method</tt> value for the method-specific routes. + # * <tt>:as</tt> - Specify a different resource name to use in the URL path. For example: # # products_path == '/productos' # map.resources :products, :as => 'productos' do |product| # # product_reviews_path(product) == '/productos/1234/comentarios' # product.resources :product_reviews, :as => 'comentarios' # end # - # * <tt>:has_one</tt> - specify nested resources, this is a shorthand for mapping singleton resources beneath the current. - # * <tt>:has_many</tt> - same has <tt>:has_one</tt>, but for plural resources. + # * <tt>:has_one</tt> - Specify nested resources, this is a shorthand for mapping singleton resources beneath the current. + # * <tt>:has_many</tt> - Same has <tt>:has_one</tt>, but for plural resources. # - # You may directly specify the routing association with has_one and has_many like: + # You may directly specify the routing association with +has_one+ and +has_many+ like: # # map.resources :notes, :has_one => :author, :has_many => [:comments, :attachments] # @@ -268,14 +268,14 @@ module ActionController # notes.resources :attachments # end # - # * <tt>:path_names</tt> - specify different names for the 'new' and 'edit' actions. For example: + # * <tt>:path_names</tt> - Specify different names for the 'new' and 'edit' actions. For example: # # new_products_path == '/productos/nuevo' # map.resources :products, :as => 'productos', :path_names => { :new => 'nuevo', :edit => 'editar' } # # You can also set default action names from an environment, like this: # config.action_controller.resources_path_names = { :new => 'nuevo', :edit => 'editar' } # - # * <tt>:path_prefix</tt> - set a prefix to the routes with required route variables. + # * <tt>:path_prefix</tt> - Set a prefix to the routes with required route variables. # # Weblog comments usually belong to a post, so you might use resources like: # @@ -296,7 +296,7 @@ module ActionController # article_comments_url(:article_id => @article) # article_comment_url(:article_id => @article, :id => @comment) # - # * <tt>:name_prefix</tt> - define a prefix for all generated routes, usually ending in an underscore. + # * <tt>:name_prefix</tt> - Define a prefix for all generated routes, usually ending in an underscore. # Use this if you have named routes that may clash. # # map.resources :tags, :path_prefix => '/books/:book_id', :name_prefix => 'book_' @@ -343,7 +343,7 @@ module ActionController # # --> GET /categories/7/messages/1 # # has named route "category_message" # - # The #resources method sets HTTP method restrictions on the routes it generates. For example, making an + # The +resources+ method sets HTTP method restrictions on the routes it generates. For example, making an # HTTP POST on <tt>new_message_url</tt> will raise a RoutingError exception. The default route in # <tt>config/routes.rb</tt> overrides this and allows invalid HTTP methods for resource routes. def resources(*entities, &block) @@ -524,11 +524,9 @@ module ActionController resource.member_methods.each do |method, actions| actions.each do |action| action_options = action_options_for(action, resource, method) - action_path = action - if resource.options[:path_names] - action_path = resource.options[:path_names][action] - action_path ||= Base.resources_path_names[action] || action - end + + action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash) + action_path ||= Base.resources_path_names[action] || action map.named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}", action_options) map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}.:format",action_options) diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb index 0bffe21431..6aa266513d 100644 --- a/actionpack/lib/action_controller/routing.rb +++ b/actionpack/lib/action_controller/routing.rb @@ -15,7 +15,7 @@ module ActionController # The routing module provides URL rewriting in native Ruby. It's a way to # redirect incoming requests to controllers and actions. This replaces # mod_rewrite rules. Best of all, Rails' Routing works with any web server. - # Routes are defined in routes.rb in your RAILS_ROOT/config directory. + # Routes are defined in <tt>config/routes.rb</tt>. # # Consider the following route, installed by Rails when you generate your # application: @@ -53,7 +53,7 @@ module ActionController # == Route priority # # Not all routes are created equally. Routes have priority defined by the - # order of appearance of the routes in the routes.rb file. The priority goes + # order of appearance of the routes in the <tt>config/routes.rb</tt> file. The priority goes # from top to bottom. The last route in that file is at the lowest priority # and will be applied last. If no route matches, 404 is returned. # @@ -118,7 +118,7 @@ module ActionController # root_url # => 'http://www.example.com/' # root_path # => '' # - # You can also specify an already-defined named route in your map.root call: + # You can also specify an already-defined named route in your <tt>map.root</tt> call: # # # In routes.rb # map.new_session :controller => 'sessions', :action => 'new' @@ -217,7 +217,7 @@ module ActionController # ActionController::Routing::Routes.reload # # This will clear all named routes and reload routes.rb if the file has been modified from - # last load. To absolutely force reloading, use +reload!+. + # last load. To absolutely force reloading, use <tt>reload!</tt>. # # == Testing Routes # @@ -277,6 +277,9 @@ module ActionController end class << self + # Expects an array of controller names as the first argument. + # Executes the passed block with only the named controllers named available. + # This method is used in internal Rails testing. def with_controllers(names) prior_controllers = @possible_controllers use_controllers! names @@ -285,6 +288,10 @@ module ActionController use_controllers! prior_controllers end + # Returns an array of paths, cleaned of double-slashes and relative path references. + # * "\\\" and "//" become "\\" or "/". + # * "/foo/bar/../config" becomes "/foo/config". + # The returned array is sorted by length, descending. def normalize_paths(paths) # do the hokey-pokey of path normalization... paths = paths.collect do |path| @@ -303,6 +310,7 @@ module ActionController paths = paths.uniq.sort_by { |path| - path.length } end + # Returns the array of controller names currently available to ActionController::Routing. def possible_controllers unless @possible_controllers @possible_controllers = [] @@ -327,10 +335,28 @@ module ActionController @possible_controllers end + # Replaces the internal list of controllers available to ActionController::Routing with the passed argument. + # ActionController::Routing.use_controllers!([ "posts", "comments", "admin/comments" ]) def use_controllers!(controller_names) @possible_controllers = controller_names end + # Returns a controller path for a new +controller+ based on a +previous+ controller path. + # Handles 4 scenarios: + # + # * stay in the previous controller: + # controller_relative_to( nil, "groups/discussion" ) # => "groups/discussion" + # + # * stay in the previous namespace: + # controller_relative_to( "posts", "groups/discussion" ) # => "groups/posts" + # + # * forced move to the root namespace: + # controller_relative_to( "/posts", "groups/discussion" ) # => "posts" + # + # * previous namespace is root: + # controller_relative_to( "posts", "anything_with_no_slashes" ) # =>"posts" + # + def controller_relative_to(controller, previous) if controller.nil? then previous elsif controller[0] == ?/ then controller[1..-1] @@ -344,6 +370,7 @@ module ActionController Routes = RouteSet.new ::Inflector.module_eval do + # Ensures that routes are reloaded when Rails inflections are updated. def inflections_with_route_reloading(&block) returning(inflections_without_route_reloading(&block)) { ActionController::Routing::Routes.reload! if block_given? diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb index 24ea8c7f2d..b142d18b47 100644 --- a/actionpack/lib/action_controller/routing/segments.rb +++ b/actionpack/lib/action_controller/routing/segments.rb @@ -244,11 +244,12 @@ module ActionController end class PathSegment < DynamicSegment #:nodoc: - RESERVED_PCHAR = "#{Segment::RESERVED_PCHAR}/" - UNSAFE_PCHAR = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}]", false, 'N').freeze - def interpolation_chunk(value_code = "#{local_name}") - "\#{URI.escape(#{value_code}.to_s, ActionController::Routing::PathSegment::UNSAFE_PCHAR)}" + "\#{#{value_code}}" + end + + def extract_value + "#{local_name} = hash[:#{key}] && hash[:#{key}].collect { |path_component| URI.escape(path_component, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}" end def default diff --git a/actionpack/lib/action_controller/session/active_record_store.rb b/actionpack/lib/action_controller/session/active_record_store.rb index 379fcd62b6..1e8eb57acb 100644 --- a/actionpack/lib/action_controller/session/active_record_store.rb +++ b/actionpack/lib/action_controller/session/active_record_store.rb @@ -13,7 +13,7 @@ class CGI # A session store backed by an Active Record class. A default class is - # provided, but any object duck-typing to an Active Record +Session+ class + # provided, but any object duck-typing to an Active Record Session class # with text +session_id+ and +data+ attributes is sufficient. # # The default assumes a +sessions+ tables with columns: @@ -26,13 +26,13 @@ class CGI # ActionController::SessionOverflowError will be raised. # # You may configure the table name, primary key, and data column. - # For example, at the end of config/environment.rb: + # For example, at the end of <tt>config/environment.rb</tt>: # CGI::Session::ActiveRecordStore::Session.table_name = 'legacy_session_table' # CGI::Session::ActiveRecordStore::Session.primary_key = 'session_id' # CGI::Session::ActiveRecordStore::Session.data_column_name = 'legacy_session_data' - # Note that setting the primary key to the session_id frees you from - # having a separate id column if you don't want it. However, you must - # set session.model.id = session.session_id by hand! A before_filter + # Note that setting the primary key to the +session_id+ frees you from + # having a separate +id+ column if you don't want it. However, you must + # set <tt>session.model.id = session.session_id</tt> by hand! A before filter # on ApplicationController is a good place. # # Since the default class is a simple Active Record, you get timestamps @@ -42,7 +42,7 @@ class CGI # You may provide your own session class implementation, whether a # feature-packed Active Record or a bare-metal high-performance SQL # store, by setting - # +CGI::Session::ActiveRecordStore.session_class = MySessionClass+ + # CGI::Session::ActiveRecordStore.session_class = MySessionClass # You must implement these methods: # self.find_by_session_id(session_id) # initialize(hash_of_session_id_and_data) @@ -154,8 +154,13 @@ class CGI # The database connection, table name, and session id and data columns # are configurable class attributes. Marshaling and unmarshaling # are implemented as class methods that you may override. By default, - # marshaling data is +ActiveSupport::Base64.encode64(Marshal.dump(data))+ and - # unmarshaling data is +Marshal.load(ActiveSupport::Base64.decode64(data))+. + # marshaling data is + # + # ActiveSupport::Base64.encode64(Marshal.dump(data)) + # + # and unmarshaling data is + # + # Marshal.load(ActiveSupport::Base64.decode64(data)) # # This marshaling behavior is intended to store the widest range of # binary session data in a +text+ column. For higher performance, diff --git a/actionpack/lib/action_controller/url_rewriter.rb b/actionpack/lib/action_controller/url_rewriter.rb index b143806818..3a38f23396 100644 --- a/actionpack/lib/action_controller/url_rewriter.rb +++ b/actionpack/lib/action_controller/url_rewriter.rb @@ -29,16 +29,16 @@ module ActionController # Generate a url based on the options provided, default_url_options and the # routes defined in routes.rb. The following options are supported: # - # * <tt>:only_path</tt> If true, the relative url is returned. Defaults to +false+. - # * <tt>:protocol</tt> The protocol to connect to. Defaults to 'http'. - # * <tt>:host</tt> Specifies the host the link should be targetted at. + # * <tt>:only_path</tt> - If true, the relative url is returned. Defaults to +false+. + # * <tt>:protocol</tt> - The protocol to connect to. Defaults to 'http'. + # * <tt>:host</tt> - Specifies the host the link should be targetted at. # If <tt>:only_path</tt> is false, this option must be # provided either explicitly, or via +default_url_options+. - # * <tt>:port</tt> Optionally specify the port to connect to. - # * <tt>:anchor</tt> An anchor name to be appended to the path. - # * <tt>:skip_relative_url_root</tt> If true, the url is not constructed using the + # * <tt>:port</tt> - Optionally specify the port to connect to. + # * <tt>:anchor</tt> - An anchor name to be appended to the path. + # * <tt>:skip_relative_url_root</tt> - If true, the url is not constructed using the # +relative_url_root+ set in ActionController::AbstractRequest.relative_url_root. - # * <tt>:trailing_slash</tt> If true, adds a trailing slash, as in "/archive/2009/" + # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/" # # Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to # +url_for+ is forwarded to the Routes module. diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index a6da81de07..4840b2526d 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -5,9 +5,9 @@ module ActionView #:nodoc: class MissingTemplate < ActionViewError #:nodoc: end - # Action View templates can be written in three ways. If the template file has a +.erb+ (or +.rhtml+) extension then it uses a mixture of ERb - # (included in Ruby) and HTML. If the template file has a +.builder+ (or +.rxml+) extension then Jim Weirich's Builder::XmlMarkup library is used. - # If the template file has a +.rjs+ extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator. + # Action View templates can be written in three ways. If the template file has a <tt>.erb</tt> (or <tt>.rhtml</tt>) extension then it uses a mixture of ERb + # (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> (or <tt>.rxml</tt>) extension then Jim Weirich's Builder::XmlMarkup library is used. + # If the template file has a <tt>.rjs</tt> extension then it will use ActionView::Helpers::PrototypeHelper::JavaScriptGenerator. # # = ERb # @@ -24,7 +24,7 @@ module ActionView #:nodoc: # # Hi, Mr. <% puts "Frodo" %> # - # If you absolutely must write from within a function, you can use the TextHelper#concat + # If you absolutely must write from within a function, you can use the TextHelper#concat. # # <%- and -%> suppress leading and trailing whitespace, including the trailing newline, and can be used interchangeably with <% and %>. # @@ -46,7 +46,7 @@ module ActionView #:nodoc: # <% @page_title = "A Wonderful Hello" %> # <%= render "shared/header" %> # - # Now the header can pick up on the @page_title variable and use it for outputting a title tag: + # Now the header can pick up on the <tt>@page_title</tt> variable and use it for outputting a title tag: # # <title><%= @page_title %></title> # @@ -56,7 +56,7 @@ module ActionView #:nodoc: # # <%= render "shared/header", { :headline => "Welcome", :person => person } %> # - # These can now be accessed in shared/header with: + # These can now be accessed in <tt>shared/header</tt> with: # # Headline: <%= headline %> # First name: <%= person.first_name %> @@ -77,13 +77,13 @@ module ActionView #:nodoc: # # == Builder # - # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An +XmlMarkup+ object - # named +xml+ is automatically made available to templates with a +.builder+ extension. + # Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An XmlMarkup object + # named +xml+ is automatically made available to templates with a <tt>.builder</tt> extension. # # Here are some basic examples: # # xml.em("emphasized") # => <em>emphasized</em> - # xml.em { xml.b("emph & bold") } # => <em><b>emph & bold</b></em> + # xml.em { xml.b("emph & bold") } # => <em><b>emph & bold</b></em> # xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a> # xml.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\> # # NOTE: order of attributes is not specified. @@ -130,18 +130,18 @@ module ActionView #:nodoc: # # == JavaScriptGenerator # - # JavaScriptGenerator templates end in +.rjs+. Unlike conventional templates which are used to + # JavaScriptGenerator templates end in <tt>.rjs</tt>. Unlike conventional templates which are used to # render the results of an action, these templates generate instructions on how to modify an already rendered page. This makes it easy to # modify multiple elements on your page in one declarative Ajax response. Actions with these templates are called in the background with Ajax # and make updates to the page where the request originated from. # # An instance of the JavaScriptGenerator object named +page+ is automatically made available to your template, which is implicitly wrapped in an ActionView::Helpers::PrototypeHelper#update_page block. # - # When an .rjs action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example: + # When an <tt>.rjs</tt> action is called with +link_to_remote+, the generated JavaScript is automatically evaluated. Example: # # link_to_remote :url => {:action => 'delete'} # - # The subsequently rendered +delete.rjs+ might look like: + # The subsequently rendered <tt>delete.rjs</tt> might look like: # # page.replace_html 'sidebar', :partial => 'sidebar' # page.remove "person-#{@person.id}" @@ -185,7 +185,7 @@ module ActionView #:nodoc: attr_internal :request delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers, - :flash, :logger, :to => :controller + :flash, :logger, :action_name, :to => :controller module CompiledTemplates #:nodoc: # holds compiled template code diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index cbd390421a..8a9c8044ae 100755 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -283,7 +283,7 @@ module ActionView # # prefixed with 'payday' rather than 'date' # select_datetime(my_date_time, :prefix => 'payday') # - def select_date(date = Date.today, options = {}, html_options = {}) + def select_date(date = Date.current, options = {}, html_options = {}) options[:order] ||= [] [:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) } @@ -683,12 +683,13 @@ module ActionView default[:min] ||= default[:minute] default[:sec] ||= default[:second] + time = Time.current + [:year, :month, :day, :hour, :min, :sec].each do |key| - default[key] ||= Time.now.send(key) + default[key] ||= time.send(key) end - Time.mktime(default[:year], default[:month], default[:day], - default[:hour], default[:min], default[:sec]) + Time.utc(default[:year], default[:month], default[:day], default[:hour], default[:min], default[:sec]) end end end diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index f37b428b80..922a0662fe 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -316,12 +316,12 @@ module ActionView # Creates a submit button with the text <tt>value</tt> as the caption. # # ==== Options - # * <tt>:confirm => 'question?'</tt> -- This will add a JavaScript confirm + # * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm # prompt with the question specified. If the user accepts, the form is # processed normally, otherwise no action is taken. - # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # * <tt>:disabled</tt> - If true, the user will not be able to use this input. # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version - # of the submit button when the form is submitted. + # of the submit button when the form is submitted. # * Any other key creates standard HTML options for the tag. # # ==== Examples diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 908728c0e6..1b12aa8058 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -631,6 +631,27 @@ module ActionView # render(:update) { |page| page.update_time } # end # + # Calls to JavaScriptGenerator not matching a helper method below + # generate a proxy to the JavaScript Class named by the method called. + # + # Examples: + # + # # Generates: + # # Foo.init(); + # update_page do |page| + # page.foo.init + # end + # + # # Generates: + # # Event.observe('one', 'click', function () { + # # $('two').show(); + # # }); + # update_page do |page| + # page.event.observe('one', 'click') do |p| + # p[:two].show + # end + # end + # # You can also use PrototypeHelper#update_page_tag instead of # PrototypeHelper#update_page to wrap the generated JavaScript in a # <script> tag. @@ -855,12 +876,21 @@ module ActionView # # Examples: # - # # Generates: Element.replace(my_element, "My content to replace with.") - # page.call 'Element.replace', 'my_element', "My content to replace with." - # - # # Generates: alert('My message!') - # page.call 'alert', 'My message!' - # + # # Generates: Element.replace(my_element, "My content to replace with.") + # page.call 'Element.replace', 'my_element', "My content to replace with." + # + # # Generates: alert('My message!') + # page.call 'alert', 'My message!' + # + # # Generates: + # # my_method(function() { + # # $("one").show(); + # # $("two").hide(); + # # }); + # page.call(:my_method) do |p| + # p[:one].show + # p[:two].hide + # end def call(function, *arguments, &block) record "#{function}(#{arguments_for_call(arguments, block)})" end diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 6d27494213..375ebfcdc5 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -19,15 +19,15 @@ module ActionView # need an unescaped url, pass <tt>:escape => false</tt> in the +options+. # # ==== Options - # * <tt>:anchor</tt> -- specifies the anchor name to be appended to the path. - # * <tt>:only_path</tt> -- if true, returns the relative URL (omitting the protocol, host name, and port) (<tt>true</tt> by default unless <tt>:host</tt> is specified) - # * <tt>:trailing_slash</tt> -- if true, adds a trailing slash, as in "/archive/2005/". Note that this + # * <tt>:anchor</tt> - Specifies the anchor name to be appended to the path. + # * <tt>:only_path</tt> - If true, returns the relative URL (omitting the protocol, host name, and port) (<tt>true</tt> by default unless <tt>:host</tt> is specified). + # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2005/". Note that this # is currently not recommended since it breaks caching. - # * <tt>:host</tt> -- overrides the default (current) host if provided - # * <tt>:protocol</tt> -- overrides the default (current) protocol if provided - # * <tt>:user</tt> -- Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present) - # * <tt>:password</tt> -- Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present) - # * <tt>:escape</tt> -- Determines whether the returned URL will be HTML escaped or not (<tt>true</tt> by default) + # * <tt>:host</tt> - Overrides the default (current) host if provided. + # * <tt>:protocol</tt> - Overrides the default (current) protocol if provided. + # * <tt>:user</tt> - Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present). + # * <tt>:password</tt> - Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present). + # * <tt>:escape</tt> - Determines whether the returned URL will be HTML escaped or not (<tt>true</tt> by default). # # ==== Relying on named routes # @@ -91,14 +91,14 @@ module ActionView # a name, the link itself will become the name. # # ==== Options - # * <tt>:confirm => 'question?'</tt> -- This will add a JavaScript confirm + # * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm # prompt with the question specified. If the user accepts, the link is # processed normally, otherwise no action is taken. - # * <tt>:popup => true || array of window options</tt> -- This will force the + # * <tt>:popup => true || array of window options</tt> - This will force the # link to open in a popup window. By passing true, a default browser window # will be opened with the URL. You can also specify an array of options # that are passed-thru to JavaScripts window.open method. - # * <tt>:method => symbol of HTTP verb</tt> -- This modifier will dynamically + # * <tt>:method => symbol of HTTP verb</tt> - This modifier will dynamically # create an HTML form and immediately submit the form for processing using # the HTTP verb specified. Useful for having links perform a POST operation # in dangerous actions like deleting a record (which search bots can follow @@ -178,9 +178,9 @@ module ActionView # The +options+ hash accepts the same options at url_for. # # There are a few special +html_options+: - # * <tt>:method</tt> -- specifies the anchor name to be appended to the path. - # * <tt>:disabled</tt> -- specifies the anchor name to be appended to the path. - # * <tt>:confirm</tt> -- This will add a JavaScript confirm + # * <tt>:method</tt> - Specifies the anchor name to be appended to the path. + # * <tt>:disabled</tt> - Specifies the anchor name to be appended to the path. + # * <tt>:confirm</tt> - This will add a JavaScript confirm # prompt with the question specified. If the user accepts, the link is # processed normally, otherwise no action is taken. # diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb index a708ecb3fb..6b294be6bd 100644 --- a/actionpack/lib/action_view/partials.rb +++ b/actionpack/lib/action_view/partials.rb @@ -119,7 +119,7 @@ module ActionView "" end else - render_partial(ActionController::RecordIdentifier.partial_path(partial_path), partial_path, local_assigns) + render_partial(ActionController::RecordIdentifier.partial_path(partial_path, controller.class.controller_path), partial_path, local_assigns) end end @@ -147,7 +147,7 @@ module ActionView templates = Hash.new i = 0 collection.map do |element| - partial_path = ActionController::RecordIdentifier.partial_path(element) + partial_path = ActionController::RecordIdentifier.partial_path(element, controller.class.controller_path) template = templates[partial_path] ||= ActionView::PartialTemplate.new(self, partial_path, nil, local_assigns) template.counter = i i += 1 diff --git a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb index 32b26206c3..ed10e72953 100644 --- a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb +++ b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb @@ -1,49 +1,49 @@ require 'active_record_unit' -class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase - fixtures :developers, :projects, :developers_projects, :topics, :replies, :companies, :mascots +class RenderPartialWithRecordIdentificationController < ActionController::Base + def render_with_has_many_and_belongs_to_association + @developer = Developer.find(1) + render :partial => @developer.projects + end - class RenderPartialWithRecordIdentificationController < ActionController::Base - def render_with_has_many_and_belongs_to_association - @developer = Developer.find(1) - render :partial => @developer.projects - end - - def render_with_has_many_association - @topic = Topic.find(1) - render :partial => @topic.replies - end - - def render_with_named_scope - render :partial => Reply.base - end - - def render_with_has_many_through_association - @developer = Developer.find(:first) - render :partial => @developer.topics - end - - def render_with_has_one_association - @company = Company.find(1) - render :partial => @company.mascot - end - - def render_with_belongs_to_association - @reply = Reply.find(1) - render :partial => @reply.topic - end - - def render_with_record - @developer = Developer.find(:first) - render :partial => @developer - end - - def render_with_record_collection - @developers = Developer.find(:all) - render :partial => @developers - end + def render_with_has_many_association + @topic = Topic.find(1) + render :partial => @topic.replies + end + + def render_with_named_scope + render :partial => Reply.base + end + + def render_with_has_many_through_association + @developer = Developer.find(:first) + render :partial => @developer.topics + end + + def render_with_has_one_association + @company = Company.find(1) + render :partial => @company.mascot + end + + def render_with_belongs_to_association + @reply = Reply.find(1) + render :partial => @reply.topic end - RenderPartialWithRecordIdentificationController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] + + def render_with_record + @developer = Developer.find(:first) + render :partial => @developer + end + + def render_with_record_collection + @developers = Developer.find(:all) + render :partial => @developers + end +end +RenderPartialWithRecordIdentificationController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] + +class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase + fixtures :developers, :projects, :developers_projects, :topics, :replies, :companies, :mascots def setup @controller = RenderPartialWithRecordIdentificationController.new @@ -84,3 +84,108 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase assert_equal mascot.name, @response.body end end + +class RenderPartialWithRecordIdentificationController < ActionController::Base + def render_with_has_many_and_belongs_to_association + @developer = Developer.find(1) + render :partial => @developer.projects + end + + def render_with_has_many_association + @topic = Topic.find(1) + render :partial => @topic.replies + end + + def render_with_has_many_through_association + @developer = Developer.find(:first) + render :partial => @developer.topics + end + + def render_with_belongs_to_association + @reply = Reply.find(1) + render :partial => @reply.topic + end + + def render_with_record + @developer = Developer.find(:first) + render :partial => @developer + end + + def render_with_record_collection + @developers = Developer.find(:all) + render :partial => @developers + end +end +RenderPartialWithRecordIdentificationController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] + +class Game < Struct.new(:name, :id) + def to_param + id.to_s + end +end + +module Fun + class NestedController < ActionController::Base + def render_with_record_in_nested_controller + render :partial => Game.new("Pong") + end + + def render_with_record_collection_in_nested_controller + render :partial => [ Game.new("Pong"), Game.new("Tank") ] + end + end + NestedController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] + + module Serious + class NestedDeeperController < ActionController::Base + def render_with_record_in_deeper_nested_controller + render :partial => Game.new("Chess") + end + + def render_with_record_collection_in_deeper_nested_controller + render :partial => [ Game.new("Chess"), Game.new("Sudoku"), Game.new("Solitaire") ] + end + end + NestedDeeperController.view_paths = [ File.dirname(__FILE__) + "/../fixtures/" ] + end +end + +class RenderPartialWithRecordIdentificationAndNestedControllersTest < ActiveRecordTestCase + def setup + @controller = Fun::NestedController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + super + end + + def test_render_with_record_in_nested_controller + get :render_with_record_in_nested_controller + assert_template 'fun/games/_game' + end + + def test_render_with_record_collection_in_nested_controller + get :render_with_record_collection_in_nested_controller + assert_template 'fun/games/_game' + end + +end + +class RenderPartialWithRecordIdentificationAndNestedDeeperControllersTest < ActiveRecordTestCase + def setup + @controller = Fun::Serious::NestedDeeperController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + super + end + + def test_render_with_record_in_deeper_nested_controller + get :render_with_record_in_deeper_nested_controller + assert_template 'fun/serious/games/_game' + end + + def test_render_with_record_collection_in_deeper_nested_controller + get :render_with_record_collection_in_deeper_nested_controller + assert_template 'fun/serious/games/_game' + end + +end
\ No newline at end of file diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb index 8e39057f55..6e2c6d90c6 100644 --- a/actionpack/test/controller/new_render_test.rb +++ b/actionpack/test/controller/new_render_test.rb @@ -246,6 +246,10 @@ class NewRenderTestController < ActionController::Base def accessing_logger_in_template render :inline => "<%= logger.class %>" end + + def accessing_action_name_in_template + render :inline => "<%= action_name %>" + end def accessing_params_in_template_with_layout render :layout => nil, :inline => "Hello: <%= params[:name] %>" @@ -545,6 +549,11 @@ class NewRenderTest < Test::Unit::TestCase get :accessing_logger_in_template assert_equal "Logger", @response.body end + + def test_access_to_action_name_in_view + get :accessing_action_name_in_template + assert_equal "accessing_action_name_in_template", @response.body + end def test_render_xml get :render_xml_hello diff --git a/actionpack/test/controller/record_identifier_test.rb b/actionpack/test/controller/record_identifier_test.rb index def8613215..12c1eaea69 100644 --- a/actionpack/test/controller/record_identifier_test.rb +++ b/actionpack/test/controller/record_identifier_test.rb @@ -57,6 +57,18 @@ class RecordIdentifierTest < Test::Unit::TestCase assert_equal expected, partial_path(Comment) end + def test_partial_path_with_namespaced_controller_path + expected = "admin/#{@plural}/#{@singular}" + assert_equal expected, partial_path(@record, "admin/posts") + assert_equal expected, partial_path(@klass, "admin/posts") + end + + def test_partial_path_with_not_namespaced_controller_path + expected = "#{@plural}/#{@singular}" + assert_equal expected, partial_path(@record, "posts") + assert_equal expected, partial_path(@klass, "posts") + end + def test_dom_class assert_equal @singular, dom_class(@record) end @@ -100,4 +112,28 @@ class NestedRecordIdentifierTest < RecordIdentifierTest assert_equal expected, partial_path(@record) assert_equal expected, partial_path(Comment::Nested) end + + def test_partial_path_with_namespaced_controller_path + expected = "admin/comment/nesteds/nested" + assert_equal expected, partial_path(@record, "admin/posts") + assert_equal expected, partial_path(@klass, "admin/posts") + end + + def test_partial_path_with_deeper_namespaced_controller_path + expected = "deeper/admin/comment/nesteds/nested" + assert_equal expected, partial_path(@record, "deeper/admin/posts") + assert_equal expected, partial_path(@klass, "deeper/admin/posts") + end + + def test_partial_path_with_even_deeper_namespaced_controller_path + expected = "even/more/deeper/admin/comment/nesteds/nested" + assert_equal expected, partial_path(@record, "even/more/deeper/admin/posts") + assert_equal expected, partial_path(@klass, "even/more/deeper/admin/posts") + end + + def test_partial_path_with_not_namespaced_controller_path + expected = "comment/nesteds/nested" + assert_equal expected, partial_path(@record, "posts") + assert_equal expected, partial_path(@klass, "posts") + end end diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index b138cee29f..0d089d0f23 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -226,6 +226,28 @@ class ResourcesTest < Test::Unit::TestCase end end + def test_member_when_changed_default_restful_actions_and_path_names_not_specified + default_path_names = ActionController::Base.resources_path_names + ActionController::Base.resources_path_names = {:new => 'nuevo', :edit => 'editar'} + + with_restful_routing :messages do + new_options = { :action => 'new', :controller => 'messages' } + new_path = "/messages/nuevo" + edit_options = { :action => 'edit', :id => '1', :controller => 'messages' } + edit_path = "/messages/1/editar" + + assert_restful_routes_for :messages do |options| + assert_recognizes(options.merge(new_options), :path => new_path, :method => :get) + end + + assert_restful_routes_for :messages do |options| + assert_recognizes(options.merge(edit_options), :path => edit_path, :method => :get) + end + end + ensure + ActionController::Base.resources_path_names = default_path_names + end + def test_with_two_member_actions_with_same_method [:put, :post].each do |method| with_restful_routing :messages, :member => { :mark => method, :unmark => method } do @@ -691,11 +713,11 @@ class ResourcesTest < Test::Unit::TestCase options[:options] ||= {} options[:options][:controller] = options[:controller] || controller_name.to_s - new_action = "new" - edit_action = "edit" + new_action = ActionController::Base.resources_path_names[:new] || "new" + edit_action = ActionController::Base.resources_path_names[:edit] || "edit" if options[:path_names] - new_action = options[:path_names][:new] || "new" - edit_action = options[:path_names][:edit] || "edit" + new_action = options[:path_names][:new] if options[:path_names][:new] + edit_action = options[:path_names][:edit] if options[:path_names][:edit] end collection_path = "/#{options[:path_prefix]}#{options[:as] || controller_name}" diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 640afd58f8..b28f7bcdff 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -25,7 +25,7 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase ActionController::Routing.use_controllers! ['controller'] @set = ActionController::Routing::RouteSet.new @set.draw do |map| - map.connect ':controller/:action/:variable' + map.connect ':controller/:action/:variable/*additional' end safe, unsafe = %w(: @ & = + $ , ;), %w(^ / ? # [ ]) @@ -36,17 +36,19 @@ class UriReservedCharactersRoutingTest < Test::Unit::TestCase end def test_route_generation_escapes_unsafe_path_characters - assert_equal "/contr#{@segment}oller/act#{@escaped}ion/var#{@escaped}iable", + assert_equal "/contr#{@segment}oller/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2", @set.generate(:controller => "contr#{@segment}oller", :action => "act#{@segment}ion", - :variable => "var#{@segment}iable") + :variable => "var#{@segment}iable", + :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"]) end def test_route_recognition_unescapes_path_components options = { :controller => "controller", :action => "act#{@segment}ion", - :variable => "var#{@segment}iable" } - assert_equal options, @set.recognize_path("/controller/act#{@escaped}ion/var#{@escaped}iable") + :variable => "var#{@segment}iable", + :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"] } + assert_equal options, @set.recognize_path("/controller/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2") end end diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index 2373600bfe..ae83c7bf47 100755 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -950,6 +950,15 @@ class DateHelperTest < ActionView::TestCase expects(:select_minute).with(time, anything, anything).returns('') select_time end + + def test_select_date_uses_date_current_as_default + date = stub(:year => 2004, :month => 6, :day => 15) + Date.expects(:current).returns date + expects(:select_year).with(date, anything, anything).returns('') + expects(:select_month).with(date, anything, anything).returns('') + expects(:select_day).with(date, anything, anything).returns('') + select_date + end end def test_date_select @@ -1699,4 +1708,27 @@ class DateHelperTest < ActionView::TestCase assert_dom_equal expected, datetime_select("post", "updated_at", {}, :class => 'selector') end + uses_mocha 'TestInstanceTagDefaultTimeFromOptions' do + def test_instance_tag_default_time_from_options_uses_time_current_as_default_when_hash_passed_as_arg + dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3) + Time.expects(:current).returns Time.now + dummy_instance_tag.send!(:default_time_from_options, :hour => 2) + end + + def test_instance_tag_default_time_from_options_respects_hash_arg_settings_when_time_falls_in_system_local_dst_spring_gap + with_env_tz('US/Central') do + dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3) + Time.stubs(:now).returns Time.local(2006, 4, 2, 1) + assert_equal 2, dummy_instance_tag.send!(:default_time_from_options, :hour => 2).hour + end + end + end + + protected + def with_env_tz(new_tz = 'US/Eastern') + old_tz, ENV['TZ'] = ENV['TZ'], new_tz + yield + ensure + old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') + end end |