Commit b9846d60741788e84c889077d9b3b4786ba31042
1 parent
0088a8d8
Exists in
master
and in
28 other branches
ActionItem135: upgrading to rails 1.2.6; all tests pass
git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@1103 3f533792-8f58-4932-b0fe-aaf55b0a4547
Showing
127 changed files
with
2801 additions
and
565 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 127 files displayed.
vendor/rails/actionmailer/CHANGELOG
| 1 | +*1.3.6* (October 12th, 2007) | |
| 2 | + | |
| 3 | +* Depend on Action Pack 1.13.6 | |
| 4 | + | |
| 5 | +*1.3.5* (October 12th, 2007) | |
| 6 | + | |
| 7 | +* Depend on Action Pack 1.13.5 | |
| 8 | + | |
| 9 | + | |
| 10 | +*1.3.4* (October 4th, 2007) | |
| 11 | + | |
| 12 | +* Depend on Action Pack 1.13.4 | |
| 13 | + | |
| 14 | + | |
| 1 | 15 | *1.3.3* (March 12th, 2007) |
| 2 | 16 | |
| 3 | 17 | * Depend on Action Pack 1.13.3 | ... | ... |
vendor/rails/actionmailer/Rakefile
| ... | ... | @@ -54,7 +54,7 @@ spec = Gem::Specification.new do |s| |
| 54 | 54 | s.rubyforge_project = "actionmailer" |
| 55 | 55 | s.homepage = "http://www.rubyonrails.org" |
| 56 | 56 | |
| 57 | - s.add_dependency('actionpack', '= 1.13.3' + PKG_BUILD) | |
| 57 | + s.add_dependency('actionpack', '= 1.13.6' + PKG_BUILD) | |
| 58 | 58 | |
| 59 | 59 | s.has_rdoc = true |
| 60 | 60 | s.requirements << 'none' | ... | ... |
vendor/rails/actionmailer/lib/action_mailer/version.rb
vendor/rails/actionpack/CHANGELOG
| 1 | +*1.13.6* (November 24th, 2007) | |
| 2 | + | |
| 3 | +* Correct Broken Fix for session_fixation attacks | |
| 4 | + | |
| 5 | +* Ensure that cookies handle array values correctly. Closes #9937 [queso] | |
| 6 | + | |
| 7 | +*1.13.5* (October 12th, 2007) | |
| 8 | + | |
| 9 | +* Backport: allow array and hash query parameters. Array route parameters are converted/to/a/path as before. #6765, #7047, #7462 [bgipsy, Jeremy McAnally, Dan Kubb, brendan, Diego Algorta Casamayou] | |
| 10 | + | |
| 11 | +* Fix in place editor's setter action with non-string fields. #7418 [Andreas] | |
| 12 | + | |
| 13 | + | |
| 14 | +*1.13.4* (October 4th, 2007) | |
| 15 | + | |
| 16 | +* Only accept session ids from cookies, prevents session fixation attacks. [bradediger] | |
| 17 | + | |
| 18 | +* Change the resource seperator from ; to / change the generated routes to use the new-style named routes. e.g. new_group_user_path(@group) instead of group_new_user_path(@group). [pixeltrix] | |
| 19 | + | |
| 20 | +* Integration tests: introduce methods for other HTTP methods. #6353 [caboose] | |
| 21 | + | |
| 22 | +* Improve performance of action caching. Closes #8231 [skaes] | |
| 23 | + | |
| 24 | +* Fix errors with around_filters which do not yield, restore 1.1 behaviour with after filters. Closes #8891 [skaes] | |
| 25 | + | |
| 26 | + After filters will *no longer* be run if an around_filter fails to yield, users relying on | |
| 27 | + this behaviour are advised to put the code in question after a yield statement in an around filter. | |
| 28 | + | |
| 29 | +* Allow you to delete cookies with options. Closes #3685 [josh, Chris Wanstrath] | |
| 30 | + | |
| 31 | +* Deprecate pagination. Install the classic_pagination plugin for forward compatibility, or move to the superior will_paginate plugin. #8157 [Mislav Marohnic] | |
| 32 | + | |
| 33 | +* Fix filtered parameter logging with nil parameter values. #8422 [choonkeat] | |
| 34 | + | |
| 35 | +* Integration tests: alias xhr to xml_http_request and add a request_method argument instead of always using POST. #7124 [Nik Wakelin, Francois Beausoleil, Wizard] | |
| 36 | + | |
| 37 | +* Document caches_action. #5419 [Jarkko Laine] | |
| 38 | + | |
| 39 | +* observe_form always sends the serialized form. #5271 [manfred, normelton@gmail.com] | |
| 40 | + | |
| 41 | +* Update UrlWriter to accept :anchor parameter. Closes #6771. [octopod] | |
| 42 | + | |
| 43 | +* Replace the current block/continuation filter chain handling by an implementation based on a simple loop. Closes #8226 [Stefan Kaes] | |
| 44 | + | |
| 45 | +* Return the string representation from an Xml Builder when rendering a partial. #5044 [tpope] | |
| 46 | + | |
| 47 | +* Cleaned up, corrected, and mildly expanded ActionPack documentation. Closes #7190 [jeremymcanally] | |
| 48 | + | |
| 49 | +* Small collection of ActionController documentation cleanups. Closes #7319 [jeremymcanally] | |
| 50 | + | |
| 51 | +* Performance: patch cgi/session/pstore to require digest/md5 once rather than per #initialize. #7583 [Stefan Kaes] | |
| 52 | + | |
| 53 | +* Deprecation: verification with :redirect_to => :named_route shouldn't be deprecated. #7525 [Justin French] | |
| 54 | + | |
| 55 | + | |
| 1 | 56 | *1.13.3* (March 12th, 2007) |
| 2 | 57 | |
| 3 | -* Apply [5709] to stable. | |
| 58 | +* Fix a bug in Routing where a parameter taken from the path of the current request could not be used as a query parameter for the next. #6752 [Nicholas Seckar] | |
| 4 | 59 | |
| 5 | 60 | * session_enabled? works with session :off. #6680 [Catfish] |
| 6 | 61 | |
| ... | ... | @@ -440,7 +495,7 @@ |
| 440 | 495 | |
| 441 | 496 | * Avoid naming collision among compiled view methods. [Jeremy Kemper] |
| 442 | 497 | |
| 443 | -* Fix CGI extensions when they expect string but get nil in Windows. Closes #5276 [mislav@nippur.irb.hr] | |
| 498 | +* Fix CGI extensions when they expect string but get nil in Windows. Closes #5276 [Mislav Marohnic] | |
| 444 | 499 | |
| 445 | 500 | * Determine the correct template_root for deeply nested components. #2841 [s.brink@web.de] |
| 446 | 501 | ... | ... |
vendor/rails/actionpack/Rakefile
| ... | ... | @@ -75,7 +75,7 @@ spec = Gem::Specification.new do |s| |
| 75 | 75 | s.has_rdoc = true |
| 76 | 76 | s.requirements << 'none' |
| 77 | 77 | |
| 78 | - s.add_dependency('activesupport', '= 1.4.2' + PKG_BUILD) | |
| 78 | + s.add_dependency('activesupport', '= 1.4.4' + PKG_BUILD) | |
| 79 | 79 | |
| 80 | 80 | s.require_path = 'lib' |
| 81 | 81 | s.autorequire = 'action_controller' | ... | ... |
vendor/rails/actionpack/examples/address_book_controller.cgi
vendor/rails/actionpack/examples/address_book_controller.fcgi
vendor/rails/actionpack/examples/address_book_controller.rbx
vendor/rails/actionpack/examples/benchmark_with_ar.fcgi
vendor/rails/actionpack/examples/blog_controller.cgi
vendor/rails/actionpack/examples/debate_controller.cgi
vendor/rails/actionpack/lib/action_controller/assertions/dom_assertions.rb
| 1 | 1 | module ActionController |
| 2 | 2 | module Assertions |
| 3 | 3 | module DomAssertions |
| 4 | - # test 2 html strings to be equivalent, i.e. identical up to reordering of attributes | |
| 4 | + # Test two HTML strings for equivalency (e.g., identical up to reordering of attributes) | |
| 5 | 5 | def assert_dom_equal(expected, actual, message="") |
| 6 | 6 | clean_backtrace do |
| 7 | 7 | expected_dom = HTML::Document.new(expected).root |
| ... | ... | @@ -11,7 +11,7 @@ module ActionController |
| 11 | 11 | end |
| 12 | 12 | end |
| 13 | 13 | |
| 14 | - # negated form of +assert_dom_equivalent+ | |
| 14 | + # The negated form of +assert_dom_equivalent+. | |
| 15 | 15 | def assert_dom_not_equal(expected, actual, message="") |
| 16 | 16 | clean_backtrace do |
| 17 | 17 | expected_dom = HTML::Document.new(expected).root | ... | ... |
vendor/rails/actionpack/lib/action_controller/assertions/model_assertions.rb
| 1 | 1 | module ActionController |
| 2 | 2 | module Assertions |
| 3 | 3 | module ModelAssertions |
| 4 | - # ensures that the passed record is valid by active record standards. returns the error messages if not | |
| 4 | + # Ensures that the passed record is valid by ActiveRecord standards and returns any error messages if it is not. | |
| 5 | 5 | def assert_valid(record) |
| 6 | 6 | clean_backtrace do |
| 7 | 7 | assert record.valid?, record.errors.full_messages.join("\n") | ... | ... |
vendor/rails/actionpack/lib/action_controller/assertions/response_assertions.rb
| ... | ... | @@ -69,6 +69,7 @@ module ActionController |
| 69 | 69 | end |
| 70 | 70 | |
| 71 | 71 | if value.respond_to?(:[]) && value['controller'] |
| 72 | + value['controller'] = value['controller'].to_s | |
| 72 | 73 | if key == :actual && value['controller'].first != '/' && !value['controller'].include?('/') |
| 73 | 74 | new_controller_path = ActionController::Routing.controller_relative_to(value['controller'], @controller.class.controller_path) |
| 74 | 75 | value['controller'] = new_controller_path if value['controller'] != new_controller_path && ActionController::Routing.possible_controllers.include?(new_controller_path) |
| ... | ... | @@ -120,6 +121,7 @@ module ActionController |
| 120 | 121 | end |
| 121 | 122 | |
| 122 | 123 | private |
| 124 | + # Recognizes the route for a given path. | |
| 123 | 125 | def recognized_request_for(path, request_method = nil) |
| 124 | 126 | path = "/#{path}" unless path.first == '/' |
| 125 | 127 | |
| ... | ... | @@ -132,6 +134,7 @@ module ActionController |
| 132 | 134 | request |
| 133 | 135 | end |
| 134 | 136 | |
| 137 | + # Proxy to to_param if the object will respond to it. | |
| 135 | 138 | def parameterize(value) |
| 136 | 139 | value.respond_to?(:to_param) ? value.to_param : value |
| 137 | 140 | end | ... | ... |
vendor/rails/actionpack/lib/action_controller/assertions/routing_assertions.rb
vendor/rails/actionpack/lib/action_controller/assertions/selector_assertions.rb
| ... | ... | @@ -561,6 +561,8 @@ module ActionController |
| 561 | 561 | # RJS encodes double quotes and line breaks. |
| 562 | 562 | unescaped= rjs_string.gsub('\"', '"') |
| 563 | 563 | unescaped.gsub!('\n', "\n") |
| 564 | + unescaped.gsub!('\076', '>') | |
| 565 | + unescaped.gsub!('\074', '<') | |
| 564 | 566 | # RJS encodes non-ascii characters. |
| 565 | 567 | unescaped.gsub!(RJS_PATTERN_UNICODE_ESCAPED_CHAR) {|u| [$1.hex].pack('U*')} |
| 566 | 568 | unescaped | ... | ... |
vendor/rails/actionpack/lib/action_controller/base.rb
| ... | ... | @@ -292,6 +292,10 @@ module ActionController #:nodoc: |
| 292 | 292 | # Turn on +ignore_missing_templates+ if you want to unit test actions without making the associated templates. |
| 293 | 293 | cattr_accessor :ignore_missing_templates |
| 294 | 294 | |
| 295 | + # Controls the resource action separator | |
| 296 | + @@resource_action_separator = "/" | |
| 297 | + cattr_accessor :resource_action_separator | |
| 298 | + | |
| 295 | 299 | # Holds the request object that's primarily used to get environment variables through access like |
| 296 | 300 | # <tt>request.env["REQUEST_URI"]</tt>. |
| 297 | 301 | attr_internal :request |
| ... | ... | @@ -393,7 +397,8 @@ module ActionController #:nodoc: |
| 393 | 397 | elsif value.is_a?(Hash) |
| 394 | 398 | filtered_parameters[key] = filter_parameters(value) |
| 395 | 399 | elsif block_given? |
| 396 | - key, value = key.dup, value.dup | |
| 400 | + key = key.dup | |
| 401 | + value = value.dup if value | |
| 397 | 402 | yield key, value |
| 398 | 403 | filtered_parameters[key] = value |
| 399 | 404 | else |
| ... | ... | @@ -538,6 +543,7 @@ module ActionController #:nodoc: |
| 538 | 543 | self.class.controller_path |
| 539 | 544 | end |
| 540 | 545 | |
| 546 | + # Test whether the session is enabled for this request. | |
| 541 | 547 | def session_enabled? |
| 542 | 548 | request.session_options && request.session_options[:disabled] != false |
| 543 | 549 | end | ... | ... |
vendor/rails/actionpack/lib/action_controller/caching.rb
| 1 | 1 | require 'fileutils' |
| 2 | 2 | require 'uri' |
| 3 | +require 'set' | |
| 3 | 4 | |
| 4 | 5 | module ActionController #:nodoc: |
| 5 | 6 | # Caching is a cheap way of speeding up slow applications by keeping the result of calculations, renderings, and database calls |
| ... | ... | @@ -163,13 +164,24 @@ module ActionController #:nodoc: |
| 163 | 164 | module Actions |
| 164 | 165 | def self.included(base) #:nodoc: |
| 165 | 166 | base.extend(ClassMethods) |
| 166 | - base.send(:attr_accessor, :rendered_action_cache) | |
| 167 | + base.class_eval do | |
| 168 | + attr_accessor :rendered_action_cache, :action_cache_path | |
| 169 | + alias_method_chain :protected_instance_variables, :action_caching | |
| 170 | + end | |
| 167 | 171 | end |
| 168 | 172 | |
| 169 | - module ClassMethods #:nodoc: | |
| 173 | + def protected_instance_variables_with_action_caching | |
| 174 | + protected_instance_variables_without_action_caching + %w(@action_cache_path) | |
| 175 | + end | |
| 176 | + | |
| 177 | + module ClassMethods | |
| 178 | + # Declares that +actions+ should be cached. | |
| 179 | + # See ActionController::Caching::Actions for details. | |
| 170 | 180 | def caches_action(*actions) |
| 171 | 181 | return unless perform_caching |
| 172 | - around_filter(ActionCacheFilter.new(*actions)) | |
| 182 | + action_cache_filter = ActionCacheFilter.new(*actions) | |
| 183 | + before_filter action_cache_filter | |
| 184 | + after_filter action_cache_filter | |
| 173 | 185 | end |
| 174 | 186 | end |
| 175 | 187 | |
| ... | ... | @@ -185,70 +197,59 @@ module ActionController #:nodoc: |
| 185 | 197 | end |
| 186 | 198 | |
| 187 | 199 | class ActionCacheFilter #:nodoc: |
| 188 | - def initialize(*actions, &block) | |
| 189 | - @actions = actions | |
| 200 | + def initialize(*actions) | |
| 201 | + @actions = Set.new actions | |
| 190 | 202 | end |
| 191 | 203 | |
| 192 | 204 | def before(controller) |
| 193 | - return unless @actions.include?(controller.action_name.intern) | |
| 194 | - action_cache_path = ActionCachePath.new(controller) | |
| 195 | - if cache = controller.read_fragment(action_cache_path.path) | |
| 205 | + return unless @actions.include?(controller.action_name.to_sym) | |
| 206 | + cache_path = ActionCachePath.new(controller, {}) | |
| 207 | + if cache = controller.read_fragment(cache_path.path) | |
| 196 | 208 | controller.rendered_action_cache = true |
| 197 | - set_content_type!(action_cache_path) | |
| 209 | + set_content_type!(controller, cache_path.extension) | |
| 198 | 210 | controller.send(:render_text, cache) |
| 199 | 211 | false |
| 212 | + else | |
| 213 | + controller.action_cache_path = cache_path | |
| 200 | 214 | end |
| 201 | 215 | end |
| 202 | 216 | |
| 203 | 217 | def after(controller) |
| 204 | - return if !@actions.include?(controller.action_name.intern) || controller.rendered_action_cache | |
| 205 | - controller.write_fragment(ActionCachePath.path_for(controller), controller.response.body) | |
| 218 | + return if !@actions.include?(controller.action_name.to_sym) || controller.rendered_action_cache | |
| 219 | + controller.write_fragment(controller.action_cache_path.path, controller.response.body) | |
| 206 | 220 | end |
| 207 | 221 | |
| 208 | 222 | private |
| 209 | - | |
| 210 | - def set_content_type!(action_cache_path) | |
| 211 | - if extention = action_cache_path.extension | |
| 212 | - content_type = Mime::EXTENSION_LOOKUP[extention] | |
| 213 | - action_cache_path.controller.response.content_type = content_type.to_s | |
| 214 | - end | |
| 223 | + def set_content_type!(controller, extension) | |
| 224 | + controller.response.content_type = Mime::EXTENSION_LOOKUP[extension].to_s if extension | |
| 215 | 225 | end |
| 216 | 226 | |
| 217 | 227 | end |
| 218 | 228 | |
| 219 | 229 | class ActionCachePath |
| 220 | - attr_reader :controller, :options | |
| 230 | + attr_reader :path, :extension | |
| 221 | 231 | |
| 222 | 232 | class << self |
| 223 | - def path_for(*args, &block) | |
| 224 | - new(*args).path | |
| 233 | + def path_for(controller, options) | |
| 234 | + new(controller, options).path | |
| 225 | 235 | end |
| 226 | 236 | end |
| 227 | 237 | |
| 228 | 238 | def initialize(controller, options = {}) |
| 229 | - @controller = controller | |
| 230 | - @options = options | |
| 231 | - end | |
| 232 | - | |
| 233 | - def path | |
| 234 | - return @path if @path | |
| 235 | - @path = controller.url_for(options).split('://').last | |
| 236 | - normalize! | |
| 237 | - add_extension! | |
| 238 | - URI.unescape(@path) | |
| 239 | - end | |
| 240 | - | |
| 241 | - def extension | |
| 242 | - @extension ||= extract_extension(controller.request.path) | |
| 239 | + @extension = extract_extension(controller.request.path) | |
| 240 | + path = controller.url_for(options).split('://').last | |
| 241 | + normalize!(path) | |
| 242 | + add_extension!(path, @extension) | |
| 243 | + @path = URI.unescape(path) | |
| 243 | 244 | end |
| 244 | 245 | |
| 245 | 246 | private |
| 246 | - def normalize! | |
| 247 | - @path << 'index' if @path.last == '/' | |
| 247 | + def normalize!(path) | |
| 248 | + path << 'index' if path[-1] == ?/ | |
| 248 | 249 | end |
| 249 | 250 | |
| 250 | - def add_extension! | |
| 251 | - @path << ".#{extension}" if extension | |
| 251 | + def add_extension!(path, extension) | |
| 252 | + path << ".#{extension}" if extension | |
| 252 | 253 | end |
| 253 | 254 | |
| 254 | 255 | def extract_extension(file_path) | ... | ... |
vendor/rails/actionpack/lib/action_controller/cgi_ext/pstore_performance_fix.rb
0 → 100644
| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | +# CGI::Session::PStore.initialize requires 'digest/md5' on every call. | |
| 2 | +# This makes sense when spawning processes per request, but is | |
| 3 | +# unnecessarily expensive when serving requests from a long-lived | |
| 4 | +# process. | |
| 5 | +require 'cgi/session' | |
| 6 | +require 'cgi/session/pstore' | |
| 7 | +require 'digest/md5' | |
| 8 | + | |
| 9 | +class CGI::Session::PStore #:nodoc: | |
| 10 | + def initialize(session, option={}) | |
| 11 | + dir = option['tmpdir'] || Dir::tmpdir | |
| 12 | + prefix = option['prefix'] || '' | |
| 13 | + id = session.session_id | |
| 14 | + md5 = Digest::MD5.hexdigest(id)[0,16] | |
| 15 | + path = dir+"/"+prefix+md5 | |
| 16 | + path.untaint | |
| 17 | + if File::exist?(path) | |
| 18 | + @hash = nil | |
| 19 | + else | |
| 20 | + unless session.new_session | |
| 21 | + raise CGI::Session::NoSession, "uninitialized session" | |
| 22 | + end | |
| 23 | + @hash = {} | |
| 24 | + end | |
| 25 | + @p = ::PStore.new(path) | |
| 26 | + @p.transaction do |p| | |
| 27 | + File.chmod(0600, p.path) | |
| 28 | + end | |
| 29 | + end | |
| 30 | +end | ... | ... |
vendor/rails/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb
vendor/rails/actionpack/lib/action_controller/cgi_process.rb
| ... | ... | @@ -2,6 +2,7 @@ require 'action_controller/cgi_ext/cgi_ext' |
| 2 | 2 | require 'action_controller/cgi_ext/cookie_performance_fix' |
| 3 | 3 | require 'action_controller/cgi_ext/raw_post_data_fix' |
| 4 | 4 | require 'action_controller/cgi_ext/session_performance_fix' |
| 5 | +require 'action_controller/cgi_ext/pstore_performance_fix' | |
| 5 | 6 | |
| 6 | 7 | module ActionController #:nodoc: |
| 7 | 8 | class Base |
| ... | ... | @@ -12,8 +13,8 @@ module ActionController #:nodoc: |
| 12 | 13 | # (default). Additionally, there is CGI::Session::DRbStore and CGI::Session::ActiveRecordStore. Read more about these in |
| 13 | 14 | # lib/action_controller/session. |
| 14 | 15 | # * <tt>:session_key</tt> - the parameter name used for the session id. Defaults to '_session_id'. |
| 15 | - # * <tt>:session_id</tt> - the session id to use. If not provided, then it is retrieved from the +session_key+ parameter | |
| 16 | - # of the request, or automatically generated for a new session. | |
| 16 | + # * <tt>:session_id</tt> - the session id to use. If not provided, then it is retrieved from the +session_key+ cookie, or | |
| 17 | + # automatically generated for a new session. | |
| 17 | 18 | # * <tt>:new_session</tt> - if true, force creation of a new session. If not set, a new session is only created if none currently |
| 18 | 19 | # exists. If false, a new session is never created, and if none currently exists and the +session_id+ option is not set, |
| 19 | 20 | # an ArgumentError is raised. |
| ... | ... | @@ -23,6 +24,8 @@ module ActionController #:nodoc: |
| 23 | 24 | # server. |
| 24 | 25 | # * <tt>:session_secure</tt> - if +true+, this session will only work over HTTPS. |
| 25 | 26 | # * <tt>:session_path</tt> - the path for which this session applies. Defaults to the directory of the CGI script. |
| 27 | + # * <tt>:cookie_only</tt> - if +true+ (the default), session IDs will only be accepted from cookies and not from | |
| 28 | + # the query string or POST parameters. This protects against session fixation attacks. | |
| 26 | 29 | def self.process_cgi(cgi = CGI.new, session_options = {}) |
| 27 | 30 | new.process_cgi(cgi, session_options) |
| 28 | 31 | end |
| ... | ... | @@ -34,11 +37,14 @@ module ActionController #:nodoc: |
| 34 | 37 | |
| 35 | 38 | class CgiRequest < AbstractRequest #:nodoc: |
| 36 | 39 | attr_accessor :cgi, :session_options |
| 40 | + class SessionFixationAttempt < StandardError; end #:nodoc: | |
| 37 | 41 | |
| 38 | 42 | DEFAULT_SESSION_OPTIONS = { |
| 39 | 43 | :database_manager => CGI::Session::PStore, |
| 40 | 44 | :prefix => "ruby_sess.", |
| 41 | - :session_path => "/" | |
| 45 | + :session_path => "/", | |
| 46 | + :session_key => "_session_id", | |
| 47 | + :cookie_only => true | |
| 42 | 48 | } unless const_defined?(:DEFAULT_SESSION_OPTIONS) |
| 43 | 49 | |
| 44 | 50 | def initialize(cgi, session_options = {}) |
| ... | ... | @@ -48,6 +54,10 @@ module ActionController #:nodoc: |
| 48 | 54 | super() |
| 49 | 55 | end |
| 50 | 56 | |
| 57 | + def cookie_only? | |
| 58 | + session_options_with_string_keys['cookie_only'] | |
| 59 | + end | |
| 60 | + | |
| 51 | 61 | def query_string |
| 52 | 62 | if (qs = @cgi.query_string) && !qs.empty? |
| 53 | 63 | qs |
| ... | ... | @@ -108,6 +118,9 @@ module ActionController #:nodoc: |
| 108 | 118 | @session = Hash.new |
| 109 | 119 | else |
| 110 | 120 | stale_session_check! do |
| 121 | + if cookie_only? && request_parameters[session_options_with_string_keys['session_key']] | |
| 122 | + raise SessionFixationAttempt | |
| 123 | + end | |
| 111 | 124 | case value = session_options_with_string_keys['new_session'] |
| 112 | 125 | when true |
| 113 | 126 | @session = new_session | ... | ... |
vendor/rails/actionpack/lib/action_controller/cookies.rb
| ... | ... | @@ -47,7 +47,10 @@ module ActionController #:nodoc: |
| 47 | 47 | # Returns the value of the cookie by +name+ -- or nil if no such cookie exists. You set new cookies using either the cookie method |
| 48 | 48 | # or cookies[]= (for simple name/value cookies without options). |
| 49 | 49 | def [](name) |
| 50 | - @cookies[name.to_s].value.first if @cookies[name.to_s] && @cookies[name.to_s].respond_to?(:value) | |
| 50 | + cookie = @cookies[name.to_s] | |
| 51 | + if cookie && cookie.respond_to?(:value) | |
| 52 | + cookie.size > 1 ? cookie.value : cookie.value.to_s | |
| 53 | + end | |
| 51 | 54 | end |
| 52 | 55 | |
| 53 | 56 | def []=(name, options) |
| ... | ... | @@ -62,9 +65,11 @@ module ActionController #:nodoc: |
| 62 | 65 | end |
| 63 | 66 | |
| 64 | 67 | # Removes the cookie on the client machine by setting the value to an empty string |
| 65 | - # and setting its expiration date into the past | |
| 66 | - def delete(name) | |
| 67 | - set_cookie("name" => name.to_s, "value" => "", "expires" => Time.at(0)) | |
| 68 | + # and setting its expiration date into the past. Like []=, you can pass in an options | |
| 69 | + # hash to delete cookies with extra data such as a +path+. | |
| 70 | + def delete(name, options = {}) | |
| 71 | + options.stringify_keys! | |
| 72 | + set_cookie(options.merge("name" => name.to_s, "value" => "", "expires" => Time.at(0))) | |
| 68 | 73 | end |
| 69 | 74 | |
| 70 | 75 | private | ... | ... |
vendor/rails/actionpack/lib/action_controller/filters.rb
| ... | ... | @@ -214,9 +214,10 @@ module ActionController #:nodoc: |
| 214 | 214 | # == Filter Chain Halting |
| 215 | 215 | # |
| 216 | 216 | # <tt>before_filter</tt> and <tt>around_filter</tt> may halt the request |
| 217 | - # before controller action is run. This is useful, for example, to deny | |
| 217 | + # before a controller action is run. This is useful, for example, to deny | |
| 218 | 218 | # access to unauthenticated users or to redirect from http to https. |
| 219 | 219 | # Simply return false from the filter or call render or redirect. |
| 220 | + # After filters will not be executed if the filter chain is halted. | |
| 220 | 221 | # |
| 221 | 222 | # Around filters halt the request unless the action block is called. |
| 222 | 223 | # Given these filters |
| ... | ... | @@ -238,12 +239,12 @@ module ActionController #:nodoc: |
| 238 | 239 | # . . / |
| 239 | 240 | # . #around (code after yield) |
| 240 | 241 | # . / |
| 241 | - # #after (actual filter code is run) | |
| 242 | + # #after (actual filter code is run, unless the around filter does not yield) | |
| 242 | 243 | # |
| 243 | - # If #around returns before yielding, only #after will be run. The #before | |
| 244 | - # filter and controller action will not be run. If #before returns false, | |
| 245 | - # the second half of #around and all of #after will still run but the | |
| 246 | - # action will not. | |
| 244 | + # If #around returns before yielding, #after will still not be run. The #before | |
| 245 | + # filter and controller action will not be run. If #before returns false, | |
| 246 | + # the second half of #around and will still run but #after and the | |
| 247 | + # action will not. If #around does not yield, #after will not be run. | |
| 247 | 248 | module ClassMethods |
| 248 | 249 | # The passed <tt>filters</tt> will be appended to the filter_chain and |
| 249 | 250 | # will execute before the action on this controller is performed. |
| ... | ... | @@ -263,13 +264,13 @@ module ActionController #:nodoc: |
| 263 | 264 | # The passed <tt>filters</tt> will be appended to the array of filters |
| 264 | 265 | # that run _after_ actions on this controller are performed. |
| 265 | 266 | def append_after_filter(*filters, &block) |
| 266 | - prepend_filter_to_chain(filters, :after, &block) | |
| 267 | + append_filter_to_chain(filters, :after, &block) | |
| 267 | 268 | end |
| 268 | 269 | |
| 269 | 270 | # The passed <tt>filters</tt> will be prepended to the array of filters |
| 270 | 271 | # that run _after_ actions on this controller are performed. |
| 271 | 272 | def prepend_after_filter(*filters, &block) |
| 272 | - append_filter_to_chain(filters, :after, &block) | |
| 273 | + prepend_filter_to_chain(filters, :after, &block) | |
| 273 | 274 | end |
| 274 | 275 | |
| 275 | 276 | # Shorthand for append_after_filter since it's the most common. |
| ... | ... | @@ -362,12 +363,12 @@ module ActionController #:nodoc: |
| 362 | 363 | |
| 363 | 364 | # Returns a mapping between filters and the actions that may run them. |
| 364 | 365 | def included_actions #:nodoc: |
| 365 | - read_inheritable_attribute("included_actions") || {} | |
| 366 | + @included_actions ||= read_inheritable_attribute("included_actions") || {} | |
| 366 | 367 | end |
| 367 | 368 | |
| 368 | 369 | # Returns a mapping between filters and actions that may not run them. |
| 369 | 370 | def excluded_actions #:nodoc: |
| 370 | - read_inheritable_attribute("excluded_actions") || {} | |
| 371 | + @excluded_actions ||= read_inheritable_attribute("excluded_actions") || {} | |
| 371 | 372 | end |
| 372 | 373 | |
| 373 | 374 | # Find a filter in the filter_chain where the filter method matches the _filter_ param |
| ... | ... | @@ -381,10 +382,11 @@ module ActionController #:nodoc: |
| 381 | 382 | |
| 382 | 383 | # Returns true if the filter is excluded from the given action |
| 383 | 384 | def filter_excluded_from_action?(filter,action) #:nodoc: |
| 384 | - if (ia = included_actions[filter]) && !ia.empty? | |
| 385 | + case | |
| 386 | + when ia = included_actions[filter] | |
| 385 | 387 | !ia.include?(action) |
| 386 | - else | |
| 387 | - (excluded_actions[filter] || []).include?(action) | |
| 388 | + when ea = excluded_actions[filter] | |
| 389 | + ea.include?(action) | |
| 388 | 390 | end |
| 389 | 391 | end |
| 390 | 392 | |
| ... | ... | @@ -397,20 +399,28 @@ module ActionController #:nodoc: |
| 397 | 399 | @filter = filter |
| 398 | 400 | end |
| 399 | 401 | |
| 402 | + def type | |
| 403 | + :around | |
| 404 | + end | |
| 405 | + | |
| 400 | 406 | def before? |
| 401 | - false | |
| 407 | + type == :before | |
| 402 | 408 | end |
| 403 | 409 | |
| 404 | 410 | def after? |
| 405 | - false | |
| 411 | + type == :after | |
| 406 | 412 | end |
| 407 | 413 | |
| 408 | 414 | def around? |
| 409 | - true | |
| 415 | + type == :around | |
| 416 | + end | |
| 417 | + | |
| 418 | + def run(controller) | |
| 419 | + raise ActionControllerError, 'No filter type: Nothing to do here.' | |
| 410 | 420 | end |
| 411 | 421 | |
| 412 | 422 | def call(controller, &block) |
| 413 | - raise(ActionControllerError, 'No filter type: Nothing to do here.') | |
| 423 | + run(controller) | |
| 414 | 424 | end |
| 415 | 425 | end |
| 416 | 426 | |
| ... | ... | @@ -420,35 +430,38 @@ module ActionController #:nodoc: |
| 420 | 430 | def filter |
| 421 | 431 | @filter.filter |
| 422 | 432 | end |
| 423 | - | |
| 424 | - def around? | |
| 425 | - false | |
| 426 | - end | |
| 427 | 433 | end |
| 428 | 434 | |
| 429 | 435 | class BeforeFilterProxy < FilterProxy #:nodoc: |
| 430 | - def before? | |
| 431 | - true | |
| 436 | + def type | |
| 437 | + :before | |
| 432 | 438 | end |
| 433 | 439 | |
| 434 | - def call(controller, &block) | |
| 435 | - if false == @filter.call(controller) # must only stop if equal to false. only filters returning false are halted. | |
| 436 | - controller.halt_filter_chain(@filter, :returned_false) | |
| 437 | - else | |
| 438 | - yield | |
| 440 | + def run(controller) | |
| 441 | + # only filters returning false are halted. | |
| 442 | + if false == @filter.call(controller) | |
| 443 | + controller.send :halt_filter_chain, @filter, :returned_false | |
| 439 | 444 | end |
| 440 | 445 | end |
| 446 | + | |
| 447 | + def call(controller) | |
| 448 | + yield unless run(controller) | |
| 449 | + end | |
| 441 | 450 | end |
| 442 | 451 | |
| 443 | 452 | class AfterFilterProxy < FilterProxy #:nodoc: |
| 444 | - def after? | |
| 445 | - true | |
| 453 | + def type | |
| 454 | + :after | |
| 446 | 455 | end |
| 447 | 456 | |
| 448 | - def call(controller, &block) | |
| 449 | - yield | |
| 457 | + def run(controller) | |
| 450 | 458 | @filter.call(controller) |
| 451 | 459 | end |
| 460 | + | |
| 461 | + def call(controller) | |
| 462 | + yield | |
| 463 | + run(controller) | |
| 464 | + end | |
| 452 | 465 | end |
| 453 | 466 | |
| 454 | 467 | class SymbolFilter < Filter #:nodoc: |
| ... | ... | @@ -485,29 +498,72 @@ module ActionController #:nodoc: |
| 485 | 498 | end |
| 486 | 499 | end |
| 487 | 500 | |
| 501 | + class ClassBeforeFilter < Filter #:nodoc: | |
| 502 | + def call(controller, &block) | |
| 503 | + @filter.before(controller) | |
| 504 | + end | |
| 505 | + end | |
| 506 | + | |
| 507 | + class ClassAfterFilter < Filter #:nodoc: | |
| 508 | + def call(controller, &block) | |
| 509 | + @filter.after(controller) | |
| 510 | + end | |
| 511 | + end | |
| 512 | + | |
| 488 | 513 | protected |
| 489 | - def append_filter_to_chain(filters, position = :around, &block) | |
| 490 | - write_inheritable_array('filter_chain', create_filters(filters, position, &block) ) | |
| 514 | + def append_filter_to_chain(filters, filter_type = :around, &block) | |
| 515 | + pos = find_filter_append_position(filters, filter_type) | |
| 516 | + update_filter_chain(filters, filter_type, pos, &block) | |
| 491 | 517 | end |
| 492 | 518 | |
| 493 | - def prepend_filter_to_chain(filters, position = :around, &block) | |
| 494 | - write_inheritable_attribute('filter_chain', create_filters(filters, position, &block) + filter_chain) | |
| 519 | + def prepend_filter_to_chain(filters, filter_type = :around, &block) | |
| 520 | + pos = find_filter_prepend_position(filters, filter_type) | |
| 521 | + update_filter_chain(filters, filter_type, pos, &block) | |
| 495 | 522 | end |
| 496 | 523 | |
| 497 | - def create_filters(filters, position, &block) #:nodoc: | |
| 524 | + def update_filter_chain(filters, filter_type, pos, &block) | |
| 525 | + new_filters = create_filters(filters, filter_type, &block) | |
| 526 | + new_chain = filter_chain.insert(pos, new_filters).flatten | |
| 527 | + write_inheritable_attribute('filter_chain', new_chain) | |
| 528 | + end | |
| 529 | + | |
| 530 | + def find_filter_append_position(filters, filter_type) | |
| 531 | + # appending an after filter puts it at the end of the call chain | |
| 532 | + # before and around filters go before the first after filter in the chain | |
| 533 | + unless filter_type == :after | |
| 534 | + filter_chain.each_with_index do |f,i| | |
| 535 | + return i if f.after? | |
| 536 | + end | |
| 537 | + end | |
| 538 | + return -1 | |
| 539 | + end | |
| 540 | + | |
| 541 | + def find_filter_prepend_position(filters, filter_type) | |
| 542 | + # prepending a before or around filter puts it at the front of the call chain | |
| 543 | + # after filters go before the first after filter in the chain | |
| 544 | + if filter_type == :after | |
| 545 | + filter_chain.each_with_index do |f,i| | |
| 546 | + return i if f.after? | |
| 547 | + end | |
| 548 | + return -1 | |
| 549 | + end | |
| 550 | + return 0 | |
| 551 | + end | |
| 552 | + | |
| 553 | + def create_filters(filters, filter_type, &block) #:nodoc: | |
| 498 | 554 | filters, conditions = extract_conditions(filters, &block) |
| 499 | - filters.map! { |filter| find_or_create_filter(filter,position) } | |
| 555 | + filters.map! { |filter| find_or_create_filter(filter, filter_type) } | |
| 500 | 556 | update_conditions(filters, conditions) |
| 501 | 557 | filters |
| 502 | 558 | end |
| 503 | 559 | |
| 504 | - def find_or_create_filter(filter,position) | |
| 505 | - if found_filter = find_filter(filter) { |f| f.send("#{position}?") } | |
| 560 | + def find_or_create_filter(filter, filter_type) | |
| 561 | + if found_filter = find_filter(filter) { |f| f.type == filter_type } | |
| 506 | 562 | found_filter |
| 507 | 563 | else |
| 508 | - f = class_for_filter(filter).new(filter) | |
| 564 | + f = class_for_filter(filter, filter_type).new(filter) | |
| 509 | 565 | # apply proxy to filter if necessary |
| 510 | - case position | |
| 566 | + case filter_type | |
| 511 | 567 | when :before |
| 512 | 568 | BeforeFilterProxy.new(f) |
| 513 | 569 | when :after |
| ... | ... | @@ -520,7 +576,7 @@ module ActionController #:nodoc: |
| 520 | 576 | |
| 521 | 577 | # The determination of the filter type was once done at run time. |
| 522 | 578 | # This method is here to extract as much logic from the filter run time as possible |
| 523 | - def class_for_filter(filter) #:nodoc: | |
| 579 | + def class_for_filter(filter, filter_type) #:nodoc: | |
| 524 | 580 | case |
| 525 | 581 | when filter.is_a?(Symbol) |
| 526 | 582 | SymbolFilter |
| ... | ... | @@ -534,8 +590,12 @@ module ActionController #:nodoc: |
| 534 | 590 | end |
| 535 | 591 | when filter.respond_to?(:filter) |
| 536 | 592 | ClassFilter |
| 593 | + when filter.respond_to?(:before) && filter_type == :before | |
| 594 | + ClassBeforeFilter | |
| 595 | + when filter.respond_to?(:after) && filter_type == :after | |
| 596 | + ClassAfterFilter | |
| 537 | 597 | else |
| 538 | - raise(ActionControllerError, 'A filters must be a Symbol, Proc, Method, or object responding to filter.') | |
| 598 | + raise(ActionControllerError, 'A filter must be a Symbol, Proc, Method, or object responding to filter, after or before.') | |
| 539 | 599 | end |
| 540 | 600 | end |
| 541 | 601 | |
| ... | ... | @@ -550,8 +610,8 @@ module ActionController #:nodoc: |
| 550 | 610 | return if conditions.empty? |
| 551 | 611 | if conditions[:only] |
| 552 | 612 | write_inheritable_hash('included_actions', condition_hash(filters, conditions[:only])) |
| 553 | - else | |
| 554 | - write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except])) if conditions[:except] | |
| 613 | + elsif conditions[:except] | |
| 614 | + write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except])) | |
| 555 | 615 | end |
| 556 | 616 | end |
| 557 | 617 | |
| ... | ... | @@ -576,9 +636,9 @@ module ActionController #:nodoc: |
| 576 | 636 | |
| 577 | 637 | def remove_actions_from_included_actions!(filters,*actions) |
| 578 | 638 | actions = actions.flatten.map(&:to_s) |
| 579 | - updated_hash = filters.inject(included_actions) do |hash,filter| | |
| 639 | + updated_hash = filters.inject(read_inheritable_attribute('included_actions')||{}) do |hash,filter| | |
| 580 | 640 | ia = (hash[filter] || []) - actions |
| 581 | - ia.blank? ? hash.delete(filter) : hash[filter] = ia | |
| 641 | + ia.empty? ? hash.delete(filter) : hash[filter] = ia | |
| 582 | 642 | hash |
| 583 | 643 | end |
| 584 | 644 | write_inheritable_attribute('included_actions', updated_hash) |
| ... | ... | @@ -595,7 +655,9 @@ module ActionController #:nodoc: |
| 595 | 655 | def proxy_before_and_after_filter(filter) #:nodoc: |
| 596 | 656 | return filter unless filter_responds_to_before_and_after(filter) |
| 597 | 657 | Proc.new do |controller, action| |
| 598 | - unless filter.before(controller) == false | |
| 658 | + if filter.before(controller) == false | |
| 659 | + controller.send :halt_filter_chain, filter, :returned_false | |
| 660 | + else | |
| 599 | 661 | begin |
| 600 | 662 | action.call |
| 601 | 663 | ensure |
| ... | ... | @@ -615,53 +677,90 @@ module ActionController #:nodoc: |
| 615 | 677 | end |
| 616 | 678 | end |
| 617 | 679 | |
| 618 | - def perform_action_with_filters | |
| 619 | - call_filter(self.class.filter_chain, 0) | |
| 620 | - end | |
| 680 | + protected | |
| 621 | 681 | |
| 622 | 682 | def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc: |
| 623 | 683 | @before_filter_chain_aborted = false |
| 624 | 684 | process_without_filters(request, response, method, *arguments) |
| 625 | 685 | end |
| 626 | 686 | |
| 627 | - def filter_chain | |
| 628 | - self.class.filter_chain | |
| 687 | + def perform_action_with_filters | |
| 688 | + call_filters(self.class.filter_chain, 0, 0) | |
| 629 | 689 | end |
| 630 | 690 | |
| 631 | - def call_filter(chain, index) | |
| 632 | - return (performed? || perform_action_without_filters) if index >= chain.size | |
| 633 | - filter = chain[index] | |
| 634 | - return call_filter(chain, index.next) if self.class.filter_excluded_from_action?(filter,action_name) | |
| 691 | + private | |
| 635 | 692 | |
| 636 | - halted = false | |
| 637 | - filter.call(self) do | |
| 638 | - halted = call_filter(chain, index.next) | |
| 693 | + def call_filters(chain, index, nesting) | |
| 694 | + index = run_before_filters(chain, index, nesting) | |
| 695 | + aborted = @before_filter_chain_aborted | |
| 696 | + perform_action_without_filters unless performed? || aborted | |
| 697 | + return index if nesting != 0 || aborted | |
| 698 | + run_after_filters(chain, index) | |
| 699 | + end | |
| 700 | + | |
| 701 | + def skip_excluded_filters(chain, index) | |
| 702 | + while (filter = chain[index]) && self.class.filter_excluded_from_action?(filter, action_name) | |
| 703 | + index = index.next | |
| 639 | 704 | end |
| 640 | - halt_filter_chain(filter.filter, :no_yield) if halted == false unless @before_filter_chain_aborted | |
| 641 | - halted | |
| 705 | + [filter, index] | |
| 642 | 706 | end |
| 643 | 707 | |
| 644 | - def halt_filter_chain(filter, reason) | |
| 645 | - if logger | |
| 646 | - case reason | |
| 647 | - when :no_yield | |
| 648 | - logger.info "Filter chain halted as [#{filter.inspect}] did not yield." | |
| 649 | - when :returned_false | |
| 650 | - logger.info "Filter chain halted as [#{filter.inspect}] returned false." | |
| 708 | + def run_before_filters(chain, index, nesting) | |
| 709 | + while chain[index] | |
| 710 | + filter, index = skip_excluded_filters(chain, index) | |
| 711 | + break unless filter # end of call chain reached | |
| 712 | + case filter.type | |
| 713 | + when :before | |
| 714 | + filter.run(self) # invoke before filter | |
| 715 | + index = index.next | |
| 716 | + break if @before_filter_chain_aborted | |
| 717 | + when :around | |
| 718 | + yielded = false | |
| 719 | + filter.call(self) do | |
| 720 | + yielded = true | |
| 721 | + # all remaining before and around filters will be run in this call | |
| 722 | + index = call_filters(chain, index.next, nesting.next) | |
| 723 | + end | |
| 724 | + halt_filter_chain(filter, :did_not_yield) unless yielded | |
| 725 | + break | |
| 726 | + else | |
| 727 | + break # no before or around filters left | |
| 651 | 728 | end |
| 652 | 729 | end |
| 653 | - @before_filter_chain_aborted = true | |
| 654 | - return false | |
| 730 | + index | |
| 655 | 731 | end |
| 656 | 732 | |
| 657 | - private | |
| 658 | - def process_cleanup_with_filters | |
| 659 | - if @before_filter_chain_aborted | |
| 660 | - close_session | |
| 733 | + def run_after_filters(chain, index) | |
| 734 | + seen_after_filter = false | |
| 735 | + while chain[index] | |
| 736 | + filter, index = skip_excluded_filters(chain, index) | |
| 737 | + break unless filter # end of call chain reached | |
| 738 | + case filter.type | |
| 739 | + when :after | |
| 740 | + seen_after_filter = true | |
| 741 | + filter.run(self) # invoke after filter | |
| 661 | 742 | else |
| 662 | - process_cleanup_without_filters | |
| 743 | + # implementation error or someone has mucked with the filter chain | |
| 744 | + raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter | |
| 663 | 745 | end |
| 746 | + index = index.next | |
| 747 | + end | |
| 748 | + index.next | |
| 749 | + end | |
| 750 | + | |
| 751 | + def halt_filter_chain(filter, reason) | |
| 752 | + @before_filter_chain_aborted = true | |
| 753 | + logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger | |
| 754 | + false | |
| 755 | + end | |
| 756 | + | |
| 757 | + def process_cleanup_with_filters | |
| 758 | + if @before_filter_chain_aborted | |
| 759 | + close_session | |
| 760 | + else | |
| 761 | + process_cleanup_without_filters | |
| 664 | 762 | end |
| 763 | + end | |
| 665 | 764 | end |
| 666 | 765 | end |
| 667 | 766 | end | ... | ... |
vendor/rails/actionpack/lib/action_controller/integration.rb
| ... | ... | @@ -67,7 +67,7 @@ module ActionController |
| 67 | 67 | @https = false |
| 68 | 68 | @cookies = {} |
| 69 | 69 | @controller = @request = @response = nil |
| 70 | - | |
| 70 | + | |
| 71 | 71 | self.host = "www.example.com" |
| 72 | 72 | self.remote_addr = "127.0.0.1" |
| 73 | 73 | self.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" |
| ... | ... | @@ -89,7 +89,7 @@ module ActionController |
| 89 | 89 | # session.https! |
| 90 | 90 | # session.https!(false) |
| 91 | 91 | def https!(flag=true) |
| 92 | - @https = flag | |
| 92 | + @https = flag | |
| 93 | 93 | end |
| 94 | 94 | |
| 95 | 95 | # Return +true+ if the session is mimicing a secure HTTPS request. |
| ... | ... | @@ -143,10 +143,10 @@ module ActionController |
| 143 | 143 | # Performs a GET request with the given parameters. The parameters may |
| 144 | 144 | # be +nil+, a Hash, or a string that is appropriately encoded |
| 145 | 145 | # (application/x-www-form-urlencoded or multipart/form-data). The headers |
| 146 | - # should be a hash. The keys will automatically be upcased, with the | |
| 146 | + # should be a hash. The keys will automatically be upcased, with the | |
| 147 | 147 | # prefix 'HTTP_' added if needed. |
| 148 | 148 | # |
| 149 | - # You can also perform POST, PUT, DELETE, and HEAD requests with #post, | |
| 149 | + # You can also perform POST, PUT, DELETE, and HEAD requests with #post, | |
| 150 | 150 | # #put, #delete, and #head. |
| 151 | 151 | def get(path, parameters=nil, headers=nil) |
| 152 | 152 | process :get, path, parameters, headers |
| ... | ... | @@ -161,31 +161,41 @@ module ActionController |
| 161 | 161 | def put(path, parameters=nil, headers=nil) |
| 162 | 162 | process :put, path, parameters, headers |
| 163 | 163 | end |
| 164 | - | |
| 164 | + | |
| 165 | 165 | # Performs a DELETE request with the given parameters. See get() for more details. |
| 166 | 166 | def delete(path, parameters=nil, headers=nil) |
| 167 | 167 | process :delete, path, parameters, headers |
| 168 | 168 | end |
| 169 | - | |
| 169 | + | |
| 170 | 170 | # Performs a HEAD request with the given parameters. See get() for more details. |
| 171 | 171 | def head(path, parameters=nil, headers=nil) |
| 172 | 172 | process :head, path, parameters, headers |
| 173 | 173 | end |
| 174 | 174 | |
| 175 | - # Performs an XMLHttpRequest request with the given parameters, mimicing | |
| 176 | - # the request environment created by the Prototype library. The parameters | |
| 177 | - # may be +nil+, a Hash, or a string that is appropriately encoded | |
| 178 | - # (application/x-www-form-urlencoded or multipart/form-data). The headers | |
| 179 | - # should be a hash. The keys will automatically be upcased, with the | |
| 180 | - # prefix 'HTTP_' added if needed. | |
| 181 | - def xml_http_request(path, parameters=nil, headers=nil) | |
| 182 | - headers = (headers || {}).merge( | |
| 183 | - "X-Requested-With" => "XMLHttpRequest", | |
| 184 | - "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" | |
| 185 | - ) | |
| 175 | + # Performs an XMLHttpRequest request with the given parameters, mirroring | |
| 176 | + # a request from the Prototype library. | |
| 177 | + # | |
| 178 | + # The request_method is :get, :post, :put, :delete or :head; the | |
| 179 | + # parameters are +nil+, a hash, or a url-encoded or multipart string; | |
| 180 | + # the headers are a hash. Keys are automatically upcased and prefixed | |
| 181 | + # with 'HTTP_' if not already. | |
| 182 | + # | |
| 183 | + # This method used to omit the request_method parameter, assuming it | |
| 184 | + # was :post. This was deprecated in Rails 1.2.4. Always pass the request | |
| 185 | + # method as the first argument. | |
| 186 | + def xml_http_request(request_method, path, parameters = nil, headers = nil) | |
| 187 | + unless request_method.is_a?(Symbol) | |
| 188 | + ActiveSupport::Deprecation.warn 'xml_http_request now takes the request_method (:get, :post, etc.) as the first argument. It used to assume :post, so add the :post argument to your existing method calls to silence this warning.' | |
| 189 | + request_method, path, parameters, headers = :post, request_method, path, parameters | |
| 190 | + end | |
| 191 | + | |
| 192 | + headers ||= {} | |
| 193 | + headers['X-Requested-With'] = 'XMLHttpRequest' | |
| 194 | + headers['Accept'] = 'text/javascript, text/html, application/xml, text/xml, */*' | |
| 186 | 195 | |
| 187 | - post(path, parameters, headers) | |
| 196 | + process(request_method, path, parameters, headers) | |
| 188 | 197 | end |
| 198 | + alias xhr :xml_http_request | |
| 189 | 199 | |
| 190 | 200 | # Returns the URL for the given options, according to the rules specified |
| 191 | 201 | # in the application's routes. |
| ... | ... | @@ -292,7 +302,7 @@ module ActionController |
| 292 | 302 | @status = @status.to_i |
| 293 | 303 | end |
| 294 | 304 | |
| 295 | - # Encode the cookies hash in a format suitable for passing to a | |
| 305 | + # Encode the cookies hash in a format suitable for passing to a | |
| 296 | 306 | # request. |
| 297 | 307 | def encode_cookies |
| 298 | 308 | cookies.inject("") do |string, (name, value)| |
| ... | ... | @@ -450,7 +460,7 @@ module ActionController |
| 450 | 460 | # without any test methods. |
| 451 | 461 | def run(*args) #:nodoc: |
| 452 | 462 | return if @method_name == "default_test" |
| 453 | - super | |
| 463 | + super | |
| 454 | 464 | end |
| 455 | 465 | |
| 456 | 466 | # Because of how use_instantiated_fixtures and use_transactional_fixtures |
| ... | ... | @@ -490,7 +500,7 @@ module ActionController |
| 490 | 500 | @integration_session = open_session |
| 491 | 501 | end |
| 492 | 502 | |
| 493 | - %w(get post cookies assigns xml_http_request).each do |method| | |
| 503 | + %w(get post put head delete cookies assigns xml_http_request).each do |method| | |
| 494 | 504 | define_method(method) do |*args| |
| 495 | 505 | reset! unless @integration_session |
| 496 | 506 | # reset the html_document variable, but only for new get/post calls | ... | ... |
vendor/rails/actionpack/lib/action_controller/macros/in_place_editing.rb
| ... | ... | @@ -24,7 +24,7 @@ module ActionController |
| 24 | 24 | define_method("set_#{object}_#{attribute}") do |
| 25 | 25 | @item = object.to_s.camelize.constantize.find(params[:id]) |
| 26 | 26 | @item.update_attribute(attribute, params[:value]) |
| 27 | - render :text => @item.send(attribute) | |
| 27 | + render :text => @item.send(attribute).to_s | |
| 28 | 28 | end |
| 29 | 29 | end |
| 30 | 30 | end | ... | ... |
vendor/rails/actionpack/lib/action_controller/pagination.rb
| 1 | 1 | module ActionController |
| 2 | 2 | # === Action Pack pagination for Active Record collections |
| 3 | 3 | # |
| 4 | - # DEPRECATION WARNING: Pagination will be separated into its own plugin with Rails 2.0. | |
| 4 | + # DEPRECATION WARNING: Pagination will be moved to a plugin in Rails 2.0. | |
| 5 | + # Install the classic_pagination plugin for forward compatibility: | |
| 6 | + # script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination | |
| 5 | 7 | # |
| 6 | 8 | # The Pagination module aids in the process of paging large collections of |
| 7 | 9 | # Active Record objects. It offers macro-style automatic fetching of your |
| ... | ... | @@ -130,6 +132,8 @@ module ActionController |
| 130 | 132 | paginator_and_collection_for(collection_id, options) |
| 131 | 133 | end |
| 132 | 134 | |
| 135 | + deprecate :paginate => 'Pagination is moving to a plugin in Rails 2.0: script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination' | |
| 136 | + | |
| 133 | 137 | # These methods become class methods on any controller |
| 134 | 138 | module ClassMethods |
| 135 | 139 | # Creates a +before_filter+ which automatically paginates an Active |
| ... | ... | @@ -148,6 +152,8 @@ module ActionController |
| 148 | 152 | OPTIONS[self][collection_id] = options |
| 149 | 153 | end |
| 150 | 154 | end |
| 155 | + | |
| 156 | + deprecate :paginate => 'Pagination is moving to a plugin in Rails 2.0: script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination' | |
| 151 | 157 | end |
| 152 | 158 | |
| 153 | 159 | def create_paginators_and_retrieve_collections #:nodoc: | ... | ... |
vendor/rails/actionpack/lib/action_controller/resources.rb
| ... | ... | @@ -2,48 +2,68 @@ module ActionController |
| 2 | 2 | module Resources |
| 3 | 3 | class Resource #:nodoc: |
| 4 | 4 | attr_reader :collection_methods, :member_methods, :new_methods |
| 5 | - attr_reader :path_prefix, :name_prefix | |
| 5 | + attr_reader :path_prefix, :new_name_prefix | |
| 6 | 6 | attr_reader :plural, :singular |
| 7 | 7 | attr_reader :options |
| 8 | 8 | |
| 9 | 9 | def initialize(entities, options) |
| 10 | 10 | @plural = entities |
| 11 | 11 | @singular = options[:singular] || plural.to_s.singularize |
| 12 | - | |
| 12 | + | |
| 13 | 13 | @options = options |
| 14 | 14 | |
| 15 | 15 | arrange_actions |
| 16 | 16 | add_default_actions |
| 17 | 17 | set_prefixes |
| 18 | 18 | end |
| 19 | - | |
| 19 | + | |
| 20 | 20 | def controller |
| 21 | 21 | @controller ||= (options[:controller] || plural).to_s |
| 22 | 22 | end |
| 23 | - | |
| 23 | + | |
| 24 | 24 | def path |
| 25 | 25 | @path ||= "#{path_prefix}/#{plural}" |
| 26 | 26 | end |
| 27 | - | |
| 27 | + | |
| 28 | 28 | def new_path |
| 29 | 29 | @new_path ||= "#{path}/new" |
| 30 | 30 | end |
| 31 | - | |
| 31 | + | |
| 32 | 32 | def member_path |
| 33 | 33 | @member_path ||= "#{path}/:id" |
| 34 | 34 | end |
| 35 | - | |
| 35 | + | |
| 36 | 36 | def nesting_path_prefix |
| 37 | 37 | @nesting_path_prefix ||= "#{path}/:#{singular}_id" |
| 38 | 38 | end |
| 39 | - | |
| 39 | + | |
| 40 | + def deprecate_name_prefix? | |
| 41 | + @name_prefix.blank? && !@new_name_prefix.blank? | |
| 42 | + end | |
| 43 | + | |
| 44 | + def name_prefix | |
| 45 | + deprecate_name_prefix? ? @new_name_prefix : @name_prefix | |
| 46 | + end | |
| 47 | + | |
| 48 | + def old_name_prefix | |
| 49 | + @name_prefix | |
| 50 | + end | |
| 51 | + | |
| 52 | + def nesting_name_prefix | |
| 53 | + "#{new_name_prefix}#{singular}_" | |
| 54 | + end | |
| 55 | + | |
| 56 | + def action_separator | |
| 57 | + @action_separator ||= Base.resource_action_separator | |
| 58 | + end | |
| 59 | + | |
| 40 | 60 | protected |
| 41 | 61 | def arrange_actions |
| 42 | 62 | @collection_methods = arrange_actions_by_methods(options.delete(:collection)) |
| 43 | 63 | @member_methods = arrange_actions_by_methods(options.delete(:member)) |
| 44 | 64 | @new_methods = arrange_actions_by_methods(options.delete(:new)) |
| 45 | 65 | end |
| 46 | - | |
| 66 | + | |
| 47 | 67 | def add_default_actions |
| 48 | 68 | add_default_action(member_methods, :get, :edit) |
| 49 | 69 | add_default_action(new_methods, :get, :new) |
| ... | ... | @@ -52,6 +72,7 @@ module ActionController |
| 52 | 72 | def set_prefixes |
| 53 | 73 | @path_prefix = options.delete(:path_prefix) |
| 54 | 74 | @name_prefix = options.delete(:name_prefix) |
| 75 | + @new_name_prefix = options.delete(:new_name_prefix) | |
| 55 | 76 | end |
| 56 | 77 | |
| 57 | 78 | def arrange_actions_by_methods(actions) |
| ... | ... | @@ -60,7 +81,7 @@ module ActionController |
| 60 | 81 | flipped_hash |
| 61 | 82 | end |
| 62 | 83 | end |
| 63 | - | |
| 84 | + | |
| 64 | 85 | def add_default_action(collection, method, action) |
| 65 | 86 | (collection[method] ||= []).unshift(action) |
| 66 | 87 | end |
| ... | ... | @@ -178,11 +199,11 @@ module ActionController |
| 178 | 199 | # |
| 179 | 200 | # The comment resources work the same, but must now include a value for :article_id. |
| 180 | 201 | # |
| 181 | - # comments_url(@article) | |
| 182 | - # comment_url(@article, @comment) | |
| 202 | + # article_comments_url(@article) | |
| 203 | + # article_comment_url(@article, @comment) | |
| 183 | 204 | # |
| 184 | - # comments_url(:article_id => @article) | |
| 185 | - # comment_url(:article_id => @article, :id => @comment) | |
| 205 | + # article_comments_url(:article_id => @article) | |
| 206 | + # article_comment_url(:article_id => @article, :id => @comment) | |
| 186 | 207 | # |
| 187 | 208 | # * <tt>:name_prefix</tt> -- define a prefix for all generated routes, usually ending in an underscore. |
| 188 | 209 | # Use this if you have named routes that may clash. |
| ... | ... | @@ -192,7 +213,7 @@ module ActionController |
| 192 | 213 | # |
| 193 | 214 | # * <tt>:collection</tt> -- add named routes for other actions that operate on the collection. |
| 194 | 215 | # Takes a hash of <tt>#{action} => #{method}</tt>, where method is <tt>:get</tt>/<tt>:post</tt>/<tt>:put</tt>/<tt>:delete</tt> |
| 195 | - # 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. | |
| 216 | + # 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. | |
| 196 | 217 | # * <tt>:member</tt> -- same as :collection, but for actions that operate on a specific member. |
| 197 | 218 | # * <tt>:new</tt> -- same as :collection, but for actions that operate on the new resource action. |
| 198 | 219 | # |
| ... | ... | @@ -204,19 +225,19 @@ module ActionController |
| 204 | 225 | # # --> GET /thread/7/messages/1 |
| 205 | 226 | # |
| 206 | 227 | # map.resources :messages, :collection => { :rss => :get } |
| 207 | - # # --> GET /messages;rss (maps to the #rss action) | |
| 228 | + # # --> GET /messages/rss (maps to the #rss action) | |
| 208 | 229 | # # also adds a named route called "rss_messages" |
| 209 | 230 | # |
| 210 | 231 | # map.resources :messages, :member => { :mark => :post } |
| 211 | - # # --> POST /messages/1;mark (maps to the #mark action) | |
| 232 | + # # --> POST /messages/1/mark (maps to the #mark action) | |
| 212 | 233 | # # also adds a named route called "mark_message" |
| 213 | 234 | # |
| 214 | 235 | # map.resources :messages, :new => { :preview => :post } |
| 215 | - # # --> POST /messages/new;preview (maps to the #preview action) | |
| 236 | + # # --> POST /messages/new/preview (maps to the #preview action) | |
| 216 | 237 | # # also adds a named route called "preview_new_message" |
| 217 | 238 | # |
| 218 | 239 | # map.resources :messages, :new => { :new => :any, :preview => :post } |
| 219 | - # # --> POST /messages/new;preview (maps to the #preview action) | |
| 240 | + # # --> POST /messages/new/preview (maps to the #preview action) | |
| 220 | 241 | # # also adds a named route called "preview_new_message" |
| 221 | 242 | # # --> /messages/new can be invoked via any request method |
| 222 | 243 | # |
| ... | ... | @@ -235,9 +256,10 @@ module ActionController |
| 235 | 256 | # /account profile. |
| 236 | 257 | # |
| 237 | 258 | # See map.resources for general conventions. These are the main differences: |
| 238 | - # - a singular name is given to map.resource. The default controller name is taken from the singular name. | |
| 239 | - # - To specify a custom plural name, use the :plural option. There is no :singular option | |
| 240 | - # - No default index, new, or create routes are created for the singleton resource controller. | |
| 259 | + # - A singular name is given to map.resource. The default controller name is taken from the singular name. | |
| 260 | + # - There is no <tt>:collection</tt> option as there is only the singleton resource. | |
| 261 | + # - There is no <tt>:singular</tt> option as the singular name is passed to map.resource. | |
| 262 | + # - No default index route is created for the singleton resource controller. | |
| 241 | 263 | # - When nesting singleton resources, only the singular name is used as the path prefix (example: 'account/messages/1') |
| 242 | 264 | # |
| 243 | 265 | # Example: |
| ... | ... | @@ -300,7 +322,7 @@ module ActionController |
| 300 | 322 | map_member_actions(map, resource) |
| 301 | 323 | |
| 302 | 324 | if block_given? |
| 303 | - with_options(:path_prefix => resource.nesting_path_prefix, &block) | |
| 325 | + with_options(:path_prefix => resource.nesting_path_prefix, :new_name_prefix => resource.nesting_name_prefix, &block) | |
| 304 | 326 | end |
| 305 | 327 | end |
| 306 | 328 | end |
| ... | ... | @@ -315,7 +337,7 @@ module ActionController |
| 315 | 337 | map_member_actions(map, resource) |
| 316 | 338 | |
| 317 | 339 | if block_given? |
| 318 | - with_options(:path_prefix => resource.nesting_path_prefix, &block) | |
| 340 | + with_options(:path_prefix => resource.nesting_path_prefix, :new_name_prefix => resource.nesting_name_prefix, &block) | |
| 319 | 341 | end |
| 320 | 342 | end |
| 321 | 343 | end |
| ... | ... | @@ -324,8 +346,21 @@ module ActionController |
| 324 | 346 | resource.collection_methods.each do |method, actions| |
| 325 | 347 | actions.each do |action| |
| 326 | 348 | action_options = action_options_for(action, resource, method) |
| 327 | - map.named_route("#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path};#{action}", action_options) | |
| 328 | - map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path}.:format;#{action}", action_options) | |
| 349 | + | |
| 350 | + unless resource.old_name_prefix.blank? | |
| 351 | + map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.old_name_prefix}#{action}_#{resource.plural}") | |
| 352 | + map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "formatted_#{resource.old_name_prefix}#{action}_#{resource.plural}") | |
| 353 | + end | |
| 354 | + | |
| 355 | + if resource.deprecate_name_prefix? | |
| 356 | + map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{action}_#{resource.plural}") | |
| 357 | + map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "formatted_#{action}_#{resource.plural}") | |
| 358 | + end | |
| 359 | + | |
| 360 | + map.named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options) | |
| 361 | + map.connect("#{resource.path};#{action}", action_options) | |
| 362 | + map.connect("#{resource.path}.:format;#{action}", action_options) | |
| 363 | + map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}.:format", action_options) | |
| 329 | 364 | end |
| 330 | 365 | end |
| 331 | 366 | end |
| ... | ... | @@ -335,6 +370,11 @@ module ActionController |
| 335 | 370 | map.named_route("#{resource.name_prefix}#{resource.plural}", resource.path, index_action_options) |
| 336 | 371 | map.named_route("formatted_#{resource.name_prefix}#{resource.plural}", "#{resource.path}.:format", index_action_options) |
| 337 | 372 | |
| 373 | + if resource.deprecate_name_prefix? | |
| 374 | + map.deprecated_named_route("#{resource.name_prefix}#{resource.plural}", "#{resource.plural}") | |
| 375 | + map.deprecated_named_route("formatted_#{resource.name_prefix}#{resource.plural}", "formatted_#{resource.plural}") | |
| 376 | + end | |
| 377 | + | |
| 338 | 378 | create_action_options = action_options_for("create", resource) |
| 339 | 379 | map.connect(resource.path, create_action_options) |
| 340 | 380 | map.connect("#{resource.path}.:format", create_action_options) |
| ... | ... | @@ -351,11 +391,37 @@ module ActionController |
| 351 | 391 | actions.each do |action| |
| 352 | 392 | action_options = action_options_for(action, resource, method) |
| 353 | 393 | if action == :new |
| 354 | - map.named_route("#{resource.name_prefix}new_#{resource.singular}", resource.new_path, action_options) | |
| 355 | - map.named_route("formatted_#{resource.name_prefix}new_#{resource.singular}", "#{resource.new_path}.:format", action_options) | |
| 394 | + | |
| 395 | + unless resource.old_name_prefix.blank? | |
| 396 | + map.deprecated_named_route("new_#{resource.name_prefix}#{resource.singular}", "#{resource.old_name_prefix}new_#{resource.singular}") | |
| 397 | + map.deprecated_named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.old_name_prefix}new_#{resource.singular}") | |
| 398 | + end | |
| 399 | + | |
| 400 | + if resource.deprecate_name_prefix? | |
| 401 | + map.deprecated_named_route("new_#{resource.name_prefix}#{resource.singular}", "new_#{resource.singular}") | |
| 402 | + map.deprecated_named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "formatted_new_#{resource.singular}") | |
| 403 | + end | |
| 404 | + | |
| 405 | + map.named_route("new_#{resource.name_prefix}#{resource.singular}", resource.new_path, action_options) | |
| 406 | + map.named_route("formatted_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}.:format", action_options) | |
| 407 | + | |
| 356 | 408 | else |
| 357 | - map.named_route("#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path};#{action}", action_options) | |
| 358 | - map.named_route("formatted_#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path}.:format;#{action}", action_options) | |
| 409 | + | |
| 410 | + unless resource.old_name_prefix.blank? | |
| 411 | + map.deprecated_named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.old_name_prefix}#{action}_new_#{resource.singular}") | |
| 412 | + map.deprecated_named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.old_name_prefix}#{action}_new_#{resource.singular}") | |
| 413 | + end | |
| 414 | + | |
| 415 | + if resource.deprecate_name_prefix? | |
| 416 | + map.deprecated_named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{action}_new_#{resource.singular}") | |
| 417 | + map.deprecated_named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "formatted_#{action}_new_#{resource.singular}") | |
| 418 | + end | |
| 419 | + | |
| 420 | + map.named_route("#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}", action_options) | |
| 421 | + map.connect("#{resource.new_path};#{action}", action_options) | |
| 422 | + map.connect("#{resource.new_path}.:format;#{action}", action_options) | |
| 423 | + map.named_route("formatted_#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}.:format", action_options) | |
| 424 | + | |
| 359 | 425 | end |
| 360 | 426 | end |
| 361 | 427 | end |
| ... | ... | @@ -365,8 +431,22 @@ module ActionController |
| 365 | 431 | resource.member_methods.each do |method, actions| |
| 366 | 432 | actions.each do |action| |
| 367 | 433 | action_options = action_options_for(action, resource, method) |
| 368 | - map.named_route("#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path};#{action}", action_options) | |
| 369 | - map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path}.:format;#{action}",action_options) | |
| 434 | + | |
| 435 | + unless resource.old_name_prefix.blank? | |
| 436 | + map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.old_name_prefix}#{action}_#{resource.singular}") | |
| 437 | + map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.old_name_prefix}#{action}_#{resource.singular}") | |
| 438 | + end | |
| 439 | + | |
| 440 | + if resource.deprecate_name_prefix? | |
| 441 | + map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{action}_#{resource.singular}") | |
| 442 | + map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "formatted_#{action}_#{resource.singular}") | |
| 443 | + end | |
| 444 | + | |
| 445 | + map.named_route("#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}", action_options) | |
| 446 | + map.connect("#{resource.member_path};#{action}", action_options) | |
| 447 | + map.connect("#{resource.member_path}.:format;#{action}", action_options) | |
| 448 | + map.named_route("formatted_#{action}_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action}.:format", action_options) | |
| 449 | + | |
| 370 | 450 | end |
| 371 | 451 | end |
| 372 | 452 | |
| ... | ... | @@ -374,6 +454,11 @@ module ActionController |
| 374 | 454 | map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, show_action_options) |
| 375 | 455 | map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", show_action_options) |
| 376 | 456 | |
| 457 | + if resource.deprecate_name_prefix? | |
| 458 | + map.deprecated_named_route("#{resource.name_prefix}#{resource.singular}", "#{resource.singular}") | |
| 459 | + map.deprecated_named_route("formatted_#{resource.name_prefix}#{resource.singular}", "formatted_#{resource.singular}") | |
| 460 | + end | |
| 461 | + | |
| 377 | 462 | update_action_options = action_options_for("update", resource) |
| 378 | 463 | map.connect(resource.member_path, update_action_options) |
| 379 | 464 | map.connect("#{resource.member_path}.:format", update_action_options) | ... | ... |
vendor/rails/actionpack/lib/action_controller/routing.rb
| ... | ... | @@ -451,26 +451,17 @@ module ActionController |
| 451 | 451 | # is given (as an array), only the keys indicated will be used to build |
| 452 | 452 | # the query string. The query string will correctly build array parameter |
| 453 | 453 | # values. |
| 454 | - def build_query_string(hash, only_keys=nil) | |
| 454 | + def build_query_string(hash, only_keys = nil) | |
| 455 | 455 | elements = [] |
| 456 | - | |
| 457 | - only_keys ||= hash.keys | |
| 458 | - | |
| 459 | - only_keys.each do |key| | |
| 460 | - value = hash[key] or next | |
| 461 | - key = CGI.escape key.to_s | |
| 462 | - if value.class == Array | |
| 463 | - key << '[]' | |
| 464 | - else | |
| 465 | - value = [ value ] | |
| 466 | - end | |
| 467 | - value.each { |val| elements << "#{key}=#{CGI.escape(val.to_param.to_s)}" } | |
| 468 | - end | |
| 469 | 456 | |
| 470 | - query_string = "?#{elements.join("&")}" unless elements.empty? | |
| 471 | - query_string || "" | |
| 457 | + (only_keys || hash.keys).each do |key| | |
| 458 | + if value = hash[key] | |
| 459 | + elements << value.to_query(key) | |
| 460 | + end | |
| 461 | + end | |
| 462 | + elements.empty? ? '' : "?#{elements.sort * '&'}" | |
| 472 | 463 | end |
| 473 | - | |
| 464 | + | |
| 474 | 465 | # Write the real recognition implementation and then resend the message. |
| 475 | 466 | def recognize(path, environment={}) |
| 476 | 467 | write_recognition |
| ... | ... | @@ -668,7 +659,7 @@ module ActionController |
| 668 | 659 | end |
| 669 | 660 | |
| 670 | 661 | def extract_value |
| 671 | - "#{local_name} = hash[:#{key}] #{"|| #{default.inspect}" if default}" | |
| 662 | + "#{local_name} = hash[:#{key}] && hash[:#{key}].to_param #{"|| #{default.inspect}" if default}" | |
| 672 | 663 | end |
| 673 | 664 | def value_check |
| 674 | 665 | if default # Then we know it won't be nil |
| ... | ... | @@ -989,6 +980,10 @@ module ActionController |
| 989 | 980 | def named_route(name, path, options = {}) |
| 990 | 981 | @set.add_named_route(name, path, options) |
| 991 | 982 | end |
| 983 | + | |
| 984 | + def deprecated_named_route(name, deprecated_name, options = {}) | |
| 985 | + @set.add_deprecated_named_route(name, deprecated_name) | |
| 986 | + end | |
| 992 | 987 | |
| 993 | 988 | # Added deprecation notice for anyone who already added a named route called "root". |
| 994 | 989 | # It'll be used as a shortcut for map.connect '' in Rails 2.0. |
| ... | ... | @@ -1019,7 +1014,7 @@ module ActionController |
| 1019 | 1014 | def clear! |
| 1020 | 1015 | @routes = {} |
| 1021 | 1016 | @helpers = [] |
| 1022 | - | |
| 1017 | + | |
| 1023 | 1018 | @module ||= Module.new |
| 1024 | 1019 | @module.instance_methods.each do |selector| |
| 1025 | 1020 | @module.send :remove_method, selector |
| ... | ... | @@ -1055,6 +1050,38 @@ module ActionController |
| 1055 | 1050 | def install(destinations = [ActionController::Base, ActionView::Base]) |
| 1056 | 1051 | Array(destinations).each { |dest| dest.send :include, @module } |
| 1057 | 1052 | end |
| 1053 | + | |
| 1054 | + def define_deprecated_named_route_methods(name, deprecated_name) | |
| 1055 | + | |
| 1056 | + [:url, :path].each do |kind| | |
| 1057 | + @module.send :module_eval, <<-end_eval # We use module_eval to avoid leaks | |
| 1058 | + | |
| 1059 | + def #{url_helper_name(deprecated_name, kind)}(*args) | |
| 1060 | + | |
| 1061 | + ActiveSupport::Deprecation.warn( | |
| 1062 | + 'The named route "#{url_helper_name(deprecated_name, kind)}" uses a format that has been deprecated. ' + | |
| 1063 | + 'You should use "#{url_helper_name(name, kind)}" instead.', caller | |
| 1064 | + ) | |
| 1065 | + | |
| 1066 | + send :#{url_helper_name(name, kind)}, *args | |
| 1067 | + | |
| 1068 | + end | |
| 1069 | + | |
| 1070 | + def #{hash_access_name(deprecated_name, kind)}(*args) | |
| 1071 | + | |
| 1072 | + ActiveSupport::Deprecation.warn( | |
| 1073 | + 'The named route "#{hash_access_name(deprecated_name, kind)}" uses a format that has been deprecated. ' + | |
| 1074 | + 'You should use "#{hash_access_name(name, kind)}" instead.', caller | |
| 1075 | + ) | |
| 1076 | + | |
| 1077 | + send :#{hash_access_name(name, kind)}, *args | |
| 1078 | + | |
| 1079 | + end | |
| 1080 | + | |
| 1081 | + end_eval | |
| 1082 | + end | |
| 1083 | + | |
| 1084 | + end | |
| 1058 | 1085 | |
| 1059 | 1086 | private |
| 1060 | 1087 | def url_helper_name(name, kind = :url) |
| ... | ... | @@ -1177,6 +1204,10 @@ module ActionController |
| 1177 | 1204 | def add_named_route(name, path, options = {}) |
| 1178 | 1205 | named_routes[name] = add_route(path, options) |
| 1179 | 1206 | end |
| 1207 | + | |
| 1208 | + def add_deprecated_named_route(name, deprecated_name) | |
| 1209 | + named_routes.define_deprecated_named_route_methods(name, deprecated_name) | |
| 1210 | + end | |
| 1180 | 1211 | |
| 1181 | 1212 | def options_as_params(options) |
| 1182 | 1213 | # If an explicit :controller was given, always make :action explicit |
| ... | ... | @@ -1190,10 +1221,9 @@ module ActionController |
| 1190 | 1221 | # |
| 1191 | 1222 | # great fun, eh? |
| 1192 | 1223 | |
| 1193 | - options_as_params = options[:controller] ? { :action => "index" } : {} | |
| 1194 | - options.each do |k, value| | |
| 1195 | - options_as_params[k] = value.to_param | |
| 1196 | - end | |
| 1224 | + options_as_params = options.clone | |
| 1225 | + options_as_params[:action] ||= 'index' if options[:controller] | |
| 1226 | + options_as_params[:action] = options_as_params[:action].to_s if options_as_params[:action] | |
| 1197 | 1227 | options_as_params |
| 1198 | 1228 | end |
| 1199 | 1229 | |
| ... | ... | @@ -1224,6 +1254,9 @@ module ActionController |
| 1224 | 1254 | options = options_as_params(options) |
| 1225 | 1255 | expire_on = build_expiry(options, recall) |
| 1226 | 1256 | |
| 1257 | + if options[:controller] | |
| 1258 | + options[:controller] = options[:controller].to_s | |
| 1259 | + end | |
| 1227 | 1260 | # if the controller has changed, make sure it changes relative to the |
| 1228 | 1261 | # current controller module, if any. In other words, if we're currently |
| 1229 | 1262 | # on admin/get, and the new controller is 'set', the new controller | ... | ... |
vendor/rails/actionpack/lib/action_controller/session/drb_server.rb
vendor/rails/actionpack/lib/action_controller/test_process.rb
| ... | ... | @@ -24,6 +24,7 @@ module ActionController #:nodoc: |
| 24 | 24 | attr_accessor :cookies, :session_options |
| 25 | 25 | attr_accessor :query_parameters, :request_parameters, :path, :session, :env |
| 26 | 26 | attr_accessor :host |
| 27 | + attr_reader :request_uri_overridden | |
| 27 | 28 | |
| 28 | 29 | def initialize(query_parameters = nil, request_parameters = nil, session = nil) |
| 29 | 30 | @query_parameters = query_parameters || {} |
| ... | ... | @@ -67,12 +68,14 @@ module ActionController #:nodoc: |
| 67 | 68 | # Used to check AbstractRequest's request_uri functionality. |
| 68 | 69 | # Disables the use of @path and @request_uri so superclass can handle those. |
| 69 | 70 | def set_REQUEST_URI(value) |
| 71 | + @request_uri_overridden = true | |
| 70 | 72 | @env["REQUEST_URI"] = value |
| 71 | 73 | @request_uri = nil |
| 72 | 74 | @path = nil |
| 73 | 75 | end |
| 74 | 76 | |
| 75 | 77 | def request_uri=(uri) |
| 78 | + @env["REQUEST_URI"] = uri | |
| 76 | 79 | @request_uri = uri |
| 77 | 80 | @path = uri.split("?").first |
| 78 | 81 | end |
| ... | ... | @@ -426,12 +429,12 @@ module ActionController #:nodoc: |
| 426 | 429 | end |
| 427 | 430 | |
| 428 | 431 | def build_request_uri(action, parameters) |
| 429 | - unless @request.env['REQUEST_URI'] | |
| 432 | + unless @request.request_uri_overridden | |
| 430 | 433 | options = @controller.send(:rewrite_options, parameters) |
| 431 | 434 | options.update(:only_path => true, :action => action) |
| 432 | 435 | |
| 433 | 436 | url = ActionController::UrlRewriter.new(@request, parameters) |
| 434 | - @request.set_REQUEST_URI(url.rewrite(options)) | |
| 437 | + @request.request_uri = url.rewrite(options) | |
| 435 | 438 | end |
| 436 | 439 | end |
| 437 | 440 | ... | ... |
vendor/rails/actionpack/lib/action_controller/url_rewriter.rb
| ... | ... | @@ -52,8 +52,9 @@ module ActionController |
| 52 | 52 | # Delete the unused options to prevent their appearance in the query string |
| 53 | 53 | [:protocol, :host, :port].each { |k| options.delete k } |
| 54 | 54 | end |
| 55 | + anchor = "##{options.delete(:anchor)}" if options.key?(:anchor) | |
| 55 | 56 | url << Routing::Routes.generate(options, {}) |
| 56 | - return url | |
| 57 | + return "#{url}#{anchor}" | |
| 57 | 58 | end |
| 58 | 59 | |
| 59 | 60 | end |
| ... | ... | @@ -76,6 +77,7 @@ module ActionController |
| 76 | 77 | alias_method :to_s, :to_str |
| 77 | 78 | |
| 78 | 79 | private |
| 80 | + # Given a path and options, returns a rewritten URL string | |
| 79 | 81 | def rewrite_url(path, options) |
| 80 | 82 | rewritten_url = "" |
| 81 | 83 | unless options[:only_path] |
| ... | ... | @@ -91,6 +93,7 @@ module ActionController |
| 91 | 93 | rewritten_url |
| 92 | 94 | end |
| 93 | 95 | |
| 96 | + # Given a Hash of options, generates a route | |
| 94 | 97 | def rewrite_path(options) |
| 95 | 98 | options = options.symbolize_keys |
| 96 | 99 | options.update(options[:params].symbolize_keys) if options[:params] | ... | ... |
vendor/rails/actionpack/lib/action_controller/verification.rb
| ... | ... | @@ -95,6 +95,7 @@ module ActionController #:nodoc: |
| 95 | 95 | response.headers.update(options[:add_headers]) if options[:add_headers] |
| 96 | 96 | unless performed? |
| 97 | 97 | render(options[:render]) if options[:render] |
| 98 | + options[:redirect_to] = self.send(options[:redirect_to]) if options[:redirect_to].is_a? Symbol | |
| 98 | 99 | redirect_to(options[:redirect_to]) if options[:redirect_to] |
| 99 | 100 | end |
| 100 | 101 | return false | ... | ... |
vendor/rails/actionpack/lib/action_pack/version.rb
vendor/rails/actionpack/lib/action_view/base.rb
| ... | ... | @@ -148,7 +148,7 @@ module ActionView #:nodoc: |
| 148 | 148 | # |
| 149 | 149 | # This refreshes the sidebar, removes a person element and highlights the user list. |
| 150 | 150 | # |
| 151 | - # See the ActionView::Helpers::PrototypeHelper::JavaScriptGenerator documentation for more details. | |
| 151 | + # See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details. | |
| 152 | 152 | class Base |
| 153 | 153 | include ERB::Util |
| 154 | 154 | |
| ... | ... | @@ -160,7 +160,7 @@ module ActionView #:nodoc: |
| 160 | 160 | attr_internal *ActionController::Base::DEPRECATED_INSTANCE_VARIABLES |
| 161 | 161 | |
| 162 | 162 | # Specify trim mode for the ERB compiler. Defaults to '-'. |
| 163 | - # See ERB documentation for suitable values. | |
| 163 | + # See ERb documentation for suitable values. | |
| 164 | 164 | @@erb_trim_mode = '-' |
| 165 | 165 | cattr_accessor :erb_trim_mode |
| 166 | 166 | |
| ... | ... | @@ -191,17 +191,17 @@ module ActionView #:nodoc: |
| 191 | 191 | end |
| 192 | 192 | include CompiledTemplates |
| 193 | 193 | |
| 194 | - # maps inline templates to their method names | |
| 194 | + # Maps inline templates to their method names | |
| 195 | 195 | @@method_names = {} |
| 196 | - # map method names to their compile time | |
| 196 | + # Map method names to their compile time | |
| 197 | 197 | @@compile_time = {} |
| 198 | - # map method names to the names passed in local assigns so far | |
| 198 | + # Map method names to the names passed in local assigns so far | |
| 199 | 199 | @@template_args = {} |
| 200 | - # count the number of inline templates | |
| 200 | + # Count the number of inline templates | |
| 201 | 201 | @@inline_template_count = 0 |
| 202 | - # maps template paths without extension to their file extension returned by pick_template_extension. | |
| 203 | - # if for a given path, path.ext1 and path.ext2 exist on the file system, the order of extensions | |
| 204 | - # used by pick_template_extension determines whether ext1 or ext2 will be stored | |
| 202 | + # Maps template paths without extension to their file extension returned by pick_template_extension. | |
| 203 | + # If for a given path, path.ext1 and path.ext2 exist on the file system, the order of extensions | |
| 204 | + # used by pick_template_extension determines whether ext1 or ext2 will be stored. | |
| 205 | 205 | @@cached_template_extension = {} |
| 206 | 206 | |
| 207 | 207 | class ObjectWrapper < Struct.new(:value) #:nodoc: |
| ... | ... | @@ -305,7 +305,6 @@ module ActionView #:nodoc: |
| 305 | 305 | # Render the provided template with the given local assigns. If the template has not been rendered with the provided |
| 306 | 306 | # local assigns yet, or if the template has been updated on disk, then the template will be compiled to a method. |
| 307 | 307 | # |
| 308 | - | |
| 309 | 308 | # Either, but not both, of template and file_path may be nil. If file_path is given, the template |
| 310 | 309 | # will only be read if it has to be compiled. |
| 311 | 310 | # |
| ... | ... | @@ -371,10 +370,12 @@ module ActionView #:nodoc: |
| 371 | 370 | end |
| 372 | 371 | |
| 373 | 372 | private |
| 373 | + # Builds a string holding the full path of the template including extension | |
| 374 | 374 | def full_template_path(template_path, extension) |
| 375 | 375 | "#{@base_path}/#{template_path}.#{extension}" |
| 376 | 376 | end |
| 377 | 377 | |
| 378 | + # Asserts the existence of a template. | |
| 378 | 379 | def template_exists?(template_path, extension) |
| 379 | 380 | file_path = full_template_path(template_path, extension) |
| 380 | 381 | @@method_names.has_key?(file_path) || FileTest.exists?(file_path) |
| ... | ... | @@ -389,6 +390,7 @@ module ActionView #:nodoc: |
| 389 | 390 | @@cache_template_extensions && @@cached_template_extension[template_path] |
| 390 | 391 | end |
| 391 | 392 | |
| 393 | + # Determines the template's file extension, such as rhtml, rxml, or rjs. | |
| 392 | 394 | def find_template_extension_for(template_path) |
| 393 | 395 | if match = delegate_template_exists?(template_path) |
| 394 | 396 | match.first.to_sym |
| ... | ... | @@ -405,6 +407,7 @@ module ActionView #:nodoc: |
| 405 | 407 | File.read(template_path) |
| 406 | 408 | end |
| 407 | 409 | |
| 410 | + # Evaluate the local assigns and pushes them to the view. | |
| 408 | 411 | def evaluate_assigns |
| 409 | 412 | unless @assigns_added |
| 410 | 413 | assign_variables_from_controller |
| ... | ... | @@ -416,6 +419,7 @@ module ActionView #:nodoc: |
| 416 | 419 | handler.new(self).render(template, local_assigns) |
| 417 | 420 | end |
| 418 | 421 | |
| 422 | + # Assigns instance variables from the controller to the view. | |
| 419 | 423 | def assign_variables_from_controller |
| 420 | 424 | @assigns.each { |key, value| instance_variable_set("@#{key}", value) } |
| 421 | 425 | end |
| ... | ... | @@ -427,10 +431,10 @@ module ActionView #:nodoc: |
| 427 | 431 | ((args = @@template_args[render_symbol]) && local_assigns.all? { |k,_| args.has_key?(k) }) |
| 428 | 432 | end |
| 429 | 433 | |
| 430 | - # Check whether compilation is necessary. | |
| 431 | - # Compile if the inline template or file has not been compiled yet. | |
| 432 | - # Or if local_assigns has a new key, which isn't supported by the compiled code yet. | |
| 433 | - # Or if the file has changed on disk and checking file mods hasn't been disabled. | |
| 434 | + # Method to check whether template compilation is necessary. | |
| 435 | + # The template will be compiled if the inline template or file has not been compiled yet, | |
| 436 | + # if local_assigns has a new key, which isn't supported by the compiled code yet, | |
| 437 | + # or if the file has changed on disk and checking file mods hasn't been disabled. | |
| 434 | 438 | def compile_template?(template, file_name, local_assigns) |
| 435 | 439 | method_key = file_name || template |
| 436 | 440 | render_symbol = @@method_names[method_key] |
| ... | ... | @@ -445,14 +449,15 @@ module ActionView #:nodoc: |
| 445 | 449 | end |
| 446 | 450 | end |
| 447 | 451 | |
| 448 | - # Create source code for given template | |
| 452 | + # Method to create the source code for a given template. | |
| 449 | 453 | def create_template_source(extension, template, render_symbol, locals) |
| 450 | 454 | if template_requires_setup?(extension) |
| 451 | 455 | body = case extension.to_sym |
| 452 | 456 | when :rxml |
| 453 | 457 | "controller.response.content_type ||= 'application/xml'\n" + |
| 454 | - "xml = Builder::XmlMarkup.new(:indent => 2)\n" + | |
| 455 | - template | |
| 458 | + "xml ||= Builder::XmlMarkup.new(:indent => 2)\n" + | |
| 459 | + template + | |
| 460 | + "\nxml.target!\n" | |
| 456 | 461 | when :rjs |
| 457 | 462 | "controller.response.content_type ||= 'text/javascript'\n" + |
| 458 | 463 | "update_page do |page|\n#{template}\nend" |
| ... | ... | @@ -473,11 +478,11 @@ module ActionView #:nodoc: |
| 473 | 478 | "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend" |
| 474 | 479 | end |
| 475 | 480 | |
| 476 | - def template_requires_setup?(extension) | |
| 481 | + def template_requires_setup?(extension) #:nodoc: | |
| 477 | 482 | templates_requiring_setup.include? extension.to_s |
| 478 | 483 | end |
| 479 | 484 | |
| 480 | - def templates_requiring_setup | |
| 485 | + def templates_requiring_setup #:nodoc: | |
| 481 | 486 | %w(rxml rjs) |
| 482 | 487 | end |
| 483 | 488 | |
| ... | ... | @@ -501,6 +506,7 @@ module ActionView #:nodoc: |
| 501 | 506 | end |
| 502 | 507 | end |
| 503 | 508 | |
| 509 | + # Compile and evaluate the template's code | |
| 504 | 510 | def compile_template(extension, template, file_name, local_assigns) |
| 505 | 511 | render_symbol = assign_method_name(extension, template, file_name) |
| 506 | 512 | render_source = create_template_source(extension, template, render_symbol, local_assigns.keys) | ... | ... |
vendor/rails/actionpack/lib/action_view/compiled_templates.rb
| ... | ... | @@ -3,14 +3,14 @@ module ActionView |
| 3 | 3 | |
| 4 | 4 | # CompiledTemplates modules hold methods that have been compiled. |
| 5 | 5 | # Templates are compiled into these methods so that they do not need to be |
| 6 | - # re-read and re-parsed each request. | |
| 6 | + # read and parsed for each request. | |
| 7 | 7 | # |
| 8 | 8 | # Each template may be compiled into one or more methods. Each method accepts a given |
| 9 | 9 | # set of parameters which is used to implement local assigns passing. |
| 10 | 10 | # |
| 11 | 11 | # To use a compiled template module, create a new instance and include it into the class |
| 12 | 12 | # in which you want the template to be rendered. |
| 13 | - class CompiledTemplates < Module #:nodoc: | |
| 13 | + class CompiledTemplates < Module | |
| 14 | 14 | attr_reader :method_names |
| 15 | 15 | |
| 16 | 16 | def initialize | ... | ... |
vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb
| ... | ... | @@ -13,17 +13,18 @@ module ActionView |
| 13 | 13 | # is a great of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form. |
| 14 | 14 | # In that case, it's better to use the input method and the specialized form methods in link:classes/ActionView/Helpers/FormHelper.html |
| 15 | 15 | module ActiveRecordHelper |
| 16 | - # Returns a default input tag for the type of object returned by the method. Example | |
| 17 | - # (title is a VARCHAR column and holds "Hello World"): | |
| 16 | + # Returns a default input tag for the type of object returned by the method. For example, let's say you have a model | |
| 17 | + # that has an attribute +title+ of type VARCHAR column, and this instance holds "Hello World": | |
| 18 | 18 | # input("post", "title") => |
| 19 | 19 | # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /> |
| 20 | 20 | def input(record_name, method, options = {}) |
| 21 | 21 | InstanceTag.new(record_name, method, self).to_tag(options) |
| 22 | 22 | end |
| 23 | 23 | |
| 24 | - # Returns an entire form with input tags and everything for a specified Active Record object. Example | |
| 25 | - # (post is a new record that has a title using VARCHAR and a body using TEXT): | |
| 26 | - # form("post") => | |
| 24 | + # Returns an entire form with all needed input tags for a specified Active Record object. For example, let's say you | |
| 25 | + # have a table model <tt>Post</tt> with attributes named <tt>title</tt> of type <tt>VARCHAR</tt> and <tt>body</tt> of type <tt>TEXT</tt>: | |
| 26 | + # form("post") | |
| 27 | + # That line would yield a form like the following: | |
| 27 | 28 | # <form action='/post/create' method='post'> |
| 28 | 29 | # <p> |
| 29 | 30 | # <label for="post_title">Title</label><br /> |
| ... | ... | @@ -32,14 +33,13 @@ module ActionView |
| 32 | 33 | # <p> |
| 33 | 34 | # <label for="post_body">Body</label><br /> |
| 34 | 35 | # <textarea cols="40" id="post_body" name="post[body]" rows="20"> |
| 35 | - # Back to the hill and over it again! | |
| 36 | 36 | # </textarea> |
| 37 | 37 | # </p> |
| 38 | 38 | # <input type='submit' value='Create' /> |
| 39 | 39 | # </form> |
| 40 | 40 | # |
| 41 | 41 | # It's possible to specialize the form builder by using a different action name and by supplying another |
| 42 | - # block renderer. Example (entry is a new record that has a message attribute using VARCHAR): | |
| 42 | + # block renderer. For example, let's say you have a model <tt>Entry</tt> with an attribute <tt>message</tt> of type <tt>VARCHAR</tt>: | |
| 43 | 43 | # |
| 44 | 44 | # form("entry", :action => "sign", :input_block => |
| 45 | 45 | # Proc.new { |record, column| "#{column.human_name}: #{input(record, column.name)}<br />" }) => |
| ... | ... | @@ -74,16 +74,16 @@ module ActionView |
| 74 | 74 | content_tag('form', contents, :action => action, :method => 'post', :enctype => options[:multipart] ? 'multipart/form-data': nil) |
| 75 | 75 | end |
| 76 | 76 | |
| 77 | - # Returns a string containing the error message attached to the +method+ on the +object+, if one exists. | |
| 78 | - # This error message is wrapped in a DIV tag, which can be specialized to include both a +prepend_text+ and +append_text+ | |
| 79 | - # to properly introduce the error and a +css_class+ to style it accordingly. Examples (post has an error message | |
| 80 | - # "can't be empty" on the title attribute): | |
| 77 | + # Returns a string containing the error message attached to the +method+ on the +object+ if one exists. | |
| 78 | + # This error message is wrapped in a <tt>DIV</tt> tag, which can be extended to include a +prepend_text+ and/or +append_text+ | |
| 79 | + # (to properly explain the error), and a +css_class+ to style it accordingly. As an example, let's say you have a model | |
| 80 | + # +post+ that has an error message on the +title+ attribute: | |
| 81 | 81 | # |
| 82 | 82 | # <%= error_message_on "post", "title" %> => |
| 83 | 83 | # <div class="formError">can't be empty</div> |
| 84 | 84 | # |
| 85 | - # <%= error_message_on "post", "title", "Title simply ", " (or it won't work)", "inputError" %> => | |
| 86 | - # <div class="inputError">Title simply can't be empty (or it won't work)</div> | |
| 85 | + # <%= error_message_on "post", "title", "Title simply ", " (or it won't work).", "inputError" %> => | |
| 86 | + # <div class="inputError">Title simply can't be empty (or it won't work).</div> | |
| 87 | 87 | def error_message_on(object, method, prepend_text = "", append_text = "", css_class = "formError") |
| 88 | 88 | if (obj = instance_variable_get("@#{object}")) && (errors = obj.errors.on(method)) |
| 89 | 89 | content_tag("div", "#{prepend_text}#{errors.is_a?(Array) ? errors.first : errors}#{append_text}", :class => css_class) |
| ... | ... | @@ -92,11 +92,11 @@ module ActionView |
| 92 | 92 | end |
| 93 | 93 | end |
| 94 | 94 | |
| 95 | - # Returns a string with a div containing all of the error messages for the objects located as instance variables by the names | |
| 95 | + # Returns a string with a <tt>DIV</tt> containing all of the error messages for the objects located as instance variables by the names | |
| 96 | 96 | # given. If more than one object is specified, the errors for the objects are displayed in the order that the object names are |
| 97 | 97 | # provided. |
| 98 | 98 | # |
| 99 | - # This div can be tailored by the following options: | |
| 99 | + # This <tt>DIV</tt> can be tailored by the following options: | |
| 100 | 100 | # |
| 101 | 101 | # * <tt>header_tag</tt> - Used for the header of the error div (default: h2) |
| 102 | 102 | # * <tt>id</tt> - The id of the error div (default: errorExplanation) |
| ... | ... | @@ -105,12 +105,12 @@ module ActionView |
| 105 | 105 | # any text that you prefer. If <tt>object_name</tt> is not set, the name of |
| 106 | 106 | # the first object will be used. |
| 107 | 107 | # |
| 108 | - # Specifying one object: | |
| 108 | + # To specify the display for one object, you simply provide its name as a parameter. For example, for the +User+ model: | |
| 109 | 109 | # |
| 110 | 110 | # error_messages_for 'user' |
| 111 | 111 | # |
| 112 | - # Specifying more than one object (and using the name 'user' in the | |
| 113 | - # header as the <tt>object_name</tt> instead of 'user_common'): | |
| 112 | + # To specify more than one object, you simply list them; optionally, you can add an extra +object_name+ parameter, which | |
| 113 | + # be the name in the header. | |
| 114 | 114 | # |
| 115 | 115 | # error_messages_for 'user_common', 'user', :object_name => 'user' |
| 116 | 116 | # | ... | ... |
vendor/rails/actionpack/lib/action_view/helpers/debug_helper.rb
| ... | ... | @@ -3,6 +3,16 @@ module ActionView |
| 3 | 3 | # Provides a set of methods for making it easier to locate problems. |
| 4 | 4 | module DebugHelper |
| 5 | 5 | # Returns a <pre>-tag set with the +object+ dumped by YAML. Very readable way to inspect an object. |
| 6 | + # my_hash = {'first' => 1, 'second' => 'two', 'third' => [1,2,3]} | |
| 7 | + # debug(my_hash) | |
| 8 | + # => <pre class='debug_dump'>--- | |
| 9 | + # first: 1 | |
| 10 | + # second: two | |
| 11 | + # third: | |
| 12 | + # - 1 | |
| 13 | + # - 2 | |
| 14 | + # - 3 | |
| 15 | + # </pre> | |
| 6 | 16 | def debug(object) |
| 7 | 17 | begin |
| 8 | 18 | Marshal::dump(object) | ... | ... |
vendor/rails/actionpack/lib/action_view/helpers/deprecated_helper.rb
| ... | ... | @@ -2,6 +2,9 @@ module ActionView |
| 2 | 2 | module Helpers |
| 3 | 3 | module PrototypeHelper |
| 4 | 4 | |
| 5 | + # Method to execute an element update using Prototype. | |
| 6 | + # DEPRECATION WARNING: This helper has been depercated; use RJS instead. | |
| 7 | + # See ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods for more information. | |
| 5 | 8 | def update_element_function(element_id, options = {}, &block) |
| 6 | 9 | content = escape_javascript(options[:content] || '') |
| 7 | 10 | content = escape_javascript(capture(&block)) if block | ... | ... |
vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb
| ... | ... | @@ -250,8 +250,10 @@ module ActionView |
| 250 | 250 | return function |
| 251 | 251 | end |
| 252 | 252 | |
| 253 | - # Observes the field with the DOM ID specified by +field_id+ and makes | |
| 254 | - # an Ajax call when its contents have changed. | |
| 253 | + # Observes the field with the DOM ID specified by +field_id+ and calls a | |
| 254 | + # callback when its contents have changed. The default callback is an | |
| 255 | + # Ajax call. By default the value of the observed field is sent as a | |
| 256 | + # parameter with the Ajax call. | |
| 255 | 257 | # |
| 256 | 258 | # Required +options+ are either of: |
| 257 | 259 | # <tt>:url</tt>:: +url_for+-style options for the action to call |
| ... | ... | @@ -268,14 +270,24 @@ module ActionView |
| 268 | 270 | # <tt>:update</tt>:: Specifies the DOM ID of the element whose |
| 269 | 271 | # innerHTML should be updated with the |
| 270 | 272 | # XMLHttpRequest response text. |
| 271 | - # <tt>:with</tt>:: A JavaScript expression specifying the | |
| 272 | - # parameters for the XMLHttpRequest. This defaults | |
| 273 | - # to 'value', which in the evaluated context | |
| 274 | - # refers to the new field value. If you specify a | |
| 275 | - # string without a "=", it'll be extended to mean | |
| 276 | - # the form key that the value should be assigned to. | |
| 277 | - # So :with => "term" gives "'term'=value". If a "=" is | |
| 278 | - # present, no extension will happen. | |
| 273 | + # <tt>:with</tt>:: A JavaScript expression specifying the parameters | |
| 274 | + # for the XMLHttpRequest. The default is to send the | |
| 275 | + # key and value of the observed field. Any custom | |
| 276 | + # expressions should return a valid URL query string. | |
| 277 | + # The value of the field is stored in the JavaScript | |
| 278 | + # variable +value+. | |
| 279 | + # | |
| 280 | + # Examples | |
| 281 | + # | |
| 282 | + # :with => "'my_custom_key=' + value" | |
| 283 | + # :with => "'person[name]=' + prompt('New name')" | |
| 284 | + # :with => "Form.Element.serialize('other-field')" | |
| 285 | + # | |
| 286 | + # Finally | |
| 287 | + # :with => 'name' | |
| 288 | + # is shorthand for | |
| 289 | + # :with => "'name=' + value" | |
| 290 | + # This essentially just changes the key of the parameter. | |
| 279 | 291 | # <tt>:on</tt>:: Specifies which event handler to observe. By default, |
| 280 | 292 | # it's set to "changed" for text fields and areas and |
| 281 | 293 | # "click" for radio buttons and checkboxes. With this, |
| ... | ... | @@ -291,11 +303,15 @@ module ActionView |
| 291 | 303 | build_observer('Form.Element.EventObserver', field_id, options) |
| 292 | 304 | end |
| 293 | 305 | end |
| 294 | - | |
| 295 | - # Like +observe_field+, but operates on an entire form identified by the | |
| 296 | - # DOM ID +form_id+. +options+ are the same as +observe_field+, except | |
| 297 | - # the default value of the <tt>:with</tt> option evaluates to the | |
| 298 | - # serialized (request string) value of the form. | |
| 306 | + | |
| 307 | + # Observes the form with the DOM ID specified by +form_id+ and calls a | |
| 308 | + # callback when its contents have changed. The default callback is an | |
| 309 | + # Ajax call. By default all fields of the observed field are sent as | |
| 310 | + # parameters with the Ajax call. | |
| 311 | + # | |
| 312 | + # The +options+ for +observe_form+ are the same as the options for | |
| 313 | + # +observe_field+. The JavaScript variable +value+ available to the | |
| 314 | + # <tt>:with</tt> option is set to the serialized form by default. | |
| 299 | 315 | def observe_form(form_id, options = {}) |
| 300 | 316 | if options[:frequency] |
| 301 | 317 | build_observer('Form.Observer', form_id, options) |
| ... | ... | @@ -660,10 +676,10 @@ module ActionView |
| 660 | 676 | end |
| 661 | 677 | |
| 662 | 678 | def build_observer(klass, name, options = {}) |
| 663 | - if options[:with] && !options[:with].include?("=") | |
| 679 | + if options[:with] && (options[:with] !~ /[=(.]/) | |
| 664 | 680 | options[:with] = "'#{options[:with]}=' + value" |
| 665 | 681 | else |
| 666 | - options[:with] ||= 'value' if options[:update] | |
| 682 | + options[:with] ||= 'value' unless options[:function] | |
| 667 | 683 | end |
| 668 | 684 | |
| 669 | 685 | callback = options[:function] || remote_function(options) | ... | ... |
vendor/rails/actionpack/test/activerecord/pagination_test.rb
| ... | ... | @@ -5,6 +5,8 @@ class PaginationTest < ActiveRecordTestCase |
| 5 | 5 | |
| 6 | 6 | class PaginationController < ActionController::Base |
| 7 | 7 | self.template_root = "#{File.dirname(__FILE__)}/../fixtures/" |
| 8 | + | |
| 9 | + around_filter :silence_deprecation_warnings | |
| 8 | 10 | |
| 9 | 11 | def simple_paginate |
| 10 | 12 | @topic_pages, @topics = paginate(:topics) |
| ... | ... | @@ -67,6 +69,13 @@ class PaginationTest < ActiveRecordTestCase |
| 67 | 69 | :count => "d.id") |
| 68 | 70 | render :nothing => true |
| 69 | 71 | end |
| 72 | + | |
| 73 | + | |
| 74 | + def silence_deprecation_warnings | |
| 75 | + ActiveSupport::Deprecation.silence do | |
| 76 | + yield | |
| 77 | + end | |
| 78 | + end | |
| 70 | 79 | |
| 71 | 80 | def rescue_errors(e) raise e end |
| 72 | 81 | ... | ... |
vendor/rails/actionpack/test/controller/action_pack_assertions_test.rb
| ... | ... | @@ -19,6 +19,8 @@ class ActionPackAssertionsController < ActionController::Base |
| 19 | 19 | |
| 20 | 20 | def redirect_to_controller() redirect_to :controller => "elsewhere", :action => "flash_me"; end |
| 21 | 21 | |
| 22 | + def redirect_to_controller_with_symbol() redirect_to :controller => :elsewhere, :action => :flash_me; end | |
| 23 | + | |
| 22 | 24 | def redirect_to_path() redirect_to '/some/path' end |
| 23 | 25 | |
| 24 | 26 | def redirect_to_named_route() redirect_to route_one_url end |
| ... | ... | @@ -555,6 +557,17 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase |
| 555 | 557 | assert_redirected_to 'http://test.host/some/path' |
| 556 | 558 | end |
| 557 | 559 | |
| 560 | + def test_assert_redirection_with_symbol | |
| 561 | + process :redirect_to_controller_with_symbol | |
| 562 | + assert_nothing_raised { | |
| 563 | + assert_redirected_to :controller => "elsewhere", :action => "flash_me" | |
| 564 | + } | |
| 565 | + process :redirect_to_controller_with_symbol | |
| 566 | + assert_nothing_raised { | |
| 567 | + assert_redirected_to :controller => :elsewhere, :action => :flash_me | |
| 568 | + } | |
| 569 | + end | |
| 570 | + | |
| 558 | 571 | def test_redirected_to_with_nested_controller |
| 559 | 572 | @controller = Admin::InnerModuleController.new |
| 560 | 573 | get :redirect_to_absolute_controller | ... | ... |
vendor/rails/actionpack/test/controller/addresses_render_test.rb
| ... | ... | @@ -39,7 +39,10 @@ class AddressesTest < Test::Unit::TestCase |
| 39 | 39 | end |
| 40 | 40 | |
| 41 | 41 | def test_list |
| 42 | - get :list | |
| 42 | + # because pagination is deprecated | |
| 43 | + ActiveSupport::Deprecation.silence do | |
| 44 | + get :list | |
| 45 | + end | |
| 43 | 46 | assert_equal "We only need to get this far!", @response.body.chomp |
| 44 | 47 | end |
| 45 | 48 | end | ... | ... |
vendor/rails/actionpack/test/controller/base_test.rb
| ... | ... | @@ -88,7 +88,7 @@ class ControllerInstanceTests < Test::Unit::TestCase |
| 88 | 88 | # Mocha adds methods to Object which are then included in the public_instance_methods |
| 89 | 89 | # This method hides those from the controller so the above tests won't know the difference |
| 90 | 90 | def hide_mocha_methods_from_controller(controller) |
| 91 | - mocha_methods = [:expects, :metaclass, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify] | |
| 91 | + mocha_methods = [:expects, :metaclass, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify, :__is_a__, :__metaclass__] | |
| 92 | 92 | controller.class.send(:hide_action, *mocha_methods) |
| 93 | 93 | end |
| 94 | 94 | ... | ... |
vendor/rails/actionpack/test/controller/caching_test.rb
| ... | ... | @@ -97,6 +97,7 @@ class ActionCachingTestController < ActionController::Base |
| 97 | 97 | caches_action :index |
| 98 | 98 | |
| 99 | 99 | def index |
| 100 | + sleep 0.01 | |
| 100 | 101 | @cache_this = Time.now.to_f.to_s |
| 101 | 102 | render :text => @cache_this |
| 102 | 103 | end |
| ... | ... | @@ -195,7 +196,7 @@ class ActionCacheTest < Test::Unit::TestCase |
| 195 | 196 | def test_xml_version_of_resource_is_treated_as_different_cache |
| 196 | 197 | @mock_controller.mock_url_for = 'http://example.org/posts/' |
| 197 | 198 | @mock_controller.mock_path = '/posts/index.xml' |
| 198 | - path_object = @path_class.new(@mock_controller) | |
| 199 | + path_object = @path_class.new(@mock_controller, {}) | |
| 199 | 200 | assert_equal 'xml', path_object.extension |
| 200 | 201 | assert_equal 'example.org/posts/index.xml', path_object.path |
| 201 | 202 | end |
| ... | ... | @@ -204,7 +205,7 @@ class ActionCacheTest < Test::Unit::TestCase |
| 204 | 205 | @mock_controller.mock_url_for = 'http://example.org/' |
| 205 | 206 | @mock_controller.mock_path = '/' |
| 206 | 207 | |
| 207 | - assert_equal 'example.org/index', @path_class.path_for(@mock_controller) | |
| 208 | + assert_equal 'example.org/index', @path_class.path_for(@mock_controller, {}) | |
| 208 | 209 | end |
| 209 | 210 | |
| 210 | 211 | def test_file_extensions | ... | ... |
vendor/rails/actionpack/test/controller/cookie_test.rb
| ... | ... | @@ -22,7 +22,7 @@ class CookieTest < Test::Unit::TestCase |
| 22 | 22 | cookies["user_name"] = { "value" => "david", "expires" => Time.local(2005, 10, 10) } |
| 23 | 23 | cookies["login"] = "XJ-122" |
| 24 | 24 | end |
| 25 | - | |
| 25 | + | |
| 26 | 26 | def access_frozen_cookies |
| 27 | 27 | cookies["will"] = "work" |
| 28 | 28 | end |
| ... | ... | @@ -31,6 +31,11 @@ class CookieTest < Test::Unit::TestCase |
| 31 | 31 | cookies.delete("user_name") |
| 32 | 32 | end |
| 33 | 33 | |
| 34 | + def delete_cookie_with_path | |
| 35 | + cookies.delete("user_name", :path => '/beaten') | |
| 36 | + render_text "hello world" | |
| 37 | + end | |
| 38 | + | |
| 34 | 39 | def rescue_action(e) |
| 35 | 40 | raise unless ActionController::MissingTemplate # No templates here, and we don't care about the output |
| 36 | 41 | end |
| ... | ... | @@ -85,4 +90,18 @@ class CookieTest < Test::Unit::TestCase |
| 85 | 90 | assert_equal "david", jar["user_name"] |
| 86 | 91 | assert_equal nil, jar["something_else"] |
| 87 | 92 | end |
| 93 | + | |
| 94 | + def test_cookiejar_accessor_with_array_value | |
| 95 | + a = %w{1 2 3} | |
| 96 | + @request.cookies["pages"] = CGI::Cookie.new("name" => "pages", "value" => a, "expires" => Time.local(2025, 10, 10)) | |
| 97 | + @controller.request = @request | |
| 98 | + jar = ActionController::CookieJar.new(@controller) | |
| 99 | + assert_equal a, jar["pages"] | |
| 100 | + end | |
| 101 | + | |
| 102 | + def test_delete_cookie_with_path | |
| 103 | + get :delete_cookie_with_path | |
| 104 | + assert_equal "/beaten", @response.headers["cookie"].first.path | |
| 105 | + assert_not_equal "/", @response.headers["cookie"].first.path | |
| 106 | + end | |
| 88 | 107 | end | ... | ... |
vendor/rails/actionpack/test/controller/deprecation/deprecated_base_methods_test.rb
| 1 | 1 | require File.dirname(__FILE__) + '/../../abstract_unit' |
| 2 | 2 | |
| 3 | 3 | class DeprecatedBaseMethodsTest < Test::Unit::TestCase |
| 4 | + # ActiveRecord model mock to test pagination deprecation | |
| 5 | + class DummyModel | |
| 6 | + def self.find(*args) [] end | |
| 7 | + def self.count(*args) 0 end | |
| 8 | + end | |
| 9 | + | |
| 4 | 10 | class Target < ActionController::Base |
| 5 | 11 | def deprecated_symbol_parameter_to_url_for |
| 6 | 12 | redirect_to(url_for(:home_url, "superstars")) |
| ... | ... | @@ -18,6 +24,11 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase |
| 18 | 24 | this_method_doesnt_exist |
| 19 | 25 | end |
| 20 | 26 | |
| 27 | + def pagination | |
| 28 | + paginate :dummy_models, :class_name => 'DeprecatedBaseMethodsTest::DummyModel' | |
| 29 | + render :nothing => true | |
| 30 | + end | |
| 31 | + | |
| 21 | 32 | def rescue_action(e) raise e end |
| 22 | 33 | end |
| 23 | 34 | |
| ... | ... | @@ -27,6 +38,7 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase |
| 27 | 38 | @request = ActionController::TestRequest.new |
| 28 | 39 | @response = ActionController::TestResponse.new |
| 29 | 40 | @controller = Target.new |
| 41 | + @controller.logger = Logger.new(nil) unless @controller.logger | |
| 30 | 42 | end |
| 31 | 43 | |
| 32 | 44 | def test_deprecated_symbol_parameter_to_url_for |
| ... | ... | @@ -57,4 +69,10 @@ class DeprecatedBaseMethodsTest < Test::Unit::TestCase |
| 57 | 69 | error = Test::Unit::Error.new('testing ur doodz', e) |
| 58 | 70 | assert_not_deprecated { error.message } |
| 59 | 71 | end |
| 72 | + | |
| 73 | + def test_pagination_deprecation | |
| 74 | + assert_deprecated('svn://errtheblog.com/svn/plugins/classic_pagination') do | |
| 75 | + get :pagination | |
| 76 | + end | |
| 77 | + end | |
| 60 | 78 | end | ... | ... |
vendor/rails/actionpack/test/controller/filter_params_test.rb
| ... | ... | @@ -16,6 +16,7 @@ class FilterParamTest < Test::Unit::TestCase |
| 16 | 16 | assert @controller.respond_to?(:filter_parameters) |
| 17 | 17 | |
| 18 | 18 | test_hashes = [[{},{},[]], |
| 19 | + [{'foo'=>nil},{'foo'=>nil},[]], | |
| 19 | 20 | [{'foo'=>'bar'},{'foo'=>'bar'},[]], |
| 20 | 21 | [{'foo'=>'bar'},{'foo'=>'bar'},%w'food'], |
| 21 | 22 | [{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'], | ... | ... |
vendor/rails/actionpack/test/controller/filters_test.rb
| ... | ... | @@ -14,7 +14,7 @@ class FilterTest < Test::Unit::TestCase |
| 14 | 14 | @ran_filter ||= [] |
| 15 | 15 | @ran_filter << "ensure_login" |
| 16 | 16 | end |
| 17 | - | |
| 17 | + | |
| 18 | 18 | def clean_up |
| 19 | 19 | @ran_after_filter ||= [] |
| 20 | 20 | @ran_after_filter << "clean_up" |
| ... | ... | @@ -62,7 +62,7 @@ class FilterTest < Test::Unit::TestCase |
| 62 | 62 | render :inline => "something else" |
| 63 | 63 | end |
| 64 | 64 | end |
| 65 | - | |
| 65 | + | |
| 66 | 66 | class ConditionalFilterController < ActionController::Base |
| 67 | 67 | def show |
| 68 | 68 | render :inline => "ran action" |
| ... | ... | @@ -86,7 +86,7 @@ class FilterTest < Test::Unit::TestCase |
| 86 | 86 | @ran_filter ||= [] |
| 87 | 87 | @ran_filter << "clean_up_tmp" |
| 88 | 88 | end |
| 89 | - | |
| 89 | + | |
| 90 | 90 | def rescue_action(e) raise(e) end |
| 91 | 91 | end |
| 92 | 92 | |
| ... | ... | @@ -94,7 +94,7 @@ class FilterTest < Test::Unit::TestCase |
| 94 | 94 | before_filter :ensure_login, :except => [ :show_without_filter, :another_action ] |
| 95 | 95 | end |
| 96 | 96 | |
| 97 | - class OnlyConditionSymController < ConditionalFilterController | |
| 97 | + class OnlyConditionSymController < ConditionalFilterController | |
| 98 | 98 | before_filter :ensure_login, :only => :show |
| 99 | 99 | end |
| 100 | 100 | |
| ... | ... | @@ -104,10 +104,10 @@ class FilterTest < Test::Unit::TestCase |
| 104 | 104 | |
| 105 | 105 | class BeforeAndAfterConditionController < ConditionalFilterController |
| 106 | 106 | before_filter :ensure_login, :only => :show |
| 107 | - after_filter :clean_up_tmp, :only => :show | |
| 107 | + after_filter :clean_up_tmp, :only => :show | |
| 108 | 108 | end |
| 109 | - | |
| 110 | - class OnlyConditionProcController < ConditionalFilterController | |
| 109 | + | |
| 110 | + class OnlyConditionProcController < ConditionalFilterController | |
| 111 | 111 | before_filter(:only => :show) {|c| c.assigns["ran_proc_filter"] = true } |
| 112 | 112 | end |
| 113 | 113 | |
| ... | ... | @@ -131,6 +131,14 @@ class FilterTest < Test::Unit::TestCase |
| 131 | 131 | before_filter(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.assigns["ran_proc_filter1"] = true }, :except => :show_without_filter) { |c| c.assigns["ran_proc_filter2"] = true} |
| 132 | 132 | end |
| 133 | 133 | |
| 134 | + class EmptyFilterChainController < TestController | |
| 135 | + self.filter_chain.clear | |
| 136 | + def show | |
| 137 | + @action_executed = true | |
| 138 | + render :text => "yawp!" | |
| 139 | + end | |
| 140 | + end | |
| 141 | + | |
| 134 | 142 | class PrependingController < TestController |
| 135 | 143 | prepend_before_filter :wonderful_life |
| 136 | 144 | # skip_before_filter :fire_flash |
| ... | ... | @@ -145,7 +153,7 @@ class FilterTest < Test::Unit::TestCase |
| 145 | 153 | class ConditionalSkippingController < TestController |
| 146 | 154 | skip_before_filter :ensure_login, :only => [ :login ] |
| 147 | 155 | skip_after_filter :clean_up, :only => [ :login ] |
| 148 | - | |
| 156 | + | |
| 149 | 157 | before_filter :find_user, :only => [ :change_password ] |
| 150 | 158 | |
| 151 | 159 | def login |
| ... | ... | @@ -155,7 +163,7 @@ class FilterTest < Test::Unit::TestCase |
| 155 | 163 | def change_password |
| 156 | 164 | render :inline => "ran action" |
| 157 | 165 | end |
| 158 | - | |
| 166 | + | |
| 159 | 167 | protected |
| 160 | 168 | def find_user |
| 161 | 169 | @ran_filter ||= [] |
| ... | ... | @@ -166,15 +174,15 @@ class FilterTest < Test::Unit::TestCase |
| 166 | 174 | class ConditionalParentOfConditionalSkippingController < ConditionalFilterController |
| 167 | 175 | before_filter :conditional_in_parent, :only => [:show, :another_action] |
| 168 | 176 | after_filter :conditional_in_parent, :only => [:show, :another_action] |
| 169 | - | |
| 177 | + | |
| 170 | 178 | private |
| 171 | - | |
| 179 | + | |
| 172 | 180 | def conditional_in_parent |
| 173 | 181 | @ran_filter ||= [] |
| 174 | 182 | @ran_filter << 'conditional_in_parent' |
| 175 | 183 | end |
| 176 | 184 | end |
| 177 | - | |
| 185 | + | |
| 178 | 186 | class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController |
| 179 | 187 | skip_before_filter :conditional_in_parent, :only => :another_action |
| 180 | 188 | skip_after_filter :conditional_in_parent, :only => :another_action |
| ... | ... | @@ -197,7 +205,7 @@ class FilterTest < Test::Unit::TestCase |
| 197 | 205 | controller.assigns["was_audited"] = true |
| 198 | 206 | end |
| 199 | 207 | end |
| 200 | - | |
| 208 | + | |
| 201 | 209 | class AroundFilter |
| 202 | 210 | def before(controller) |
| 203 | 211 | @execution_log = "before" |
| ... | ... | @@ -209,7 +217,7 @@ class FilterTest < Test::Unit::TestCase |
| 209 | 217 | controller.assigns["execution_log"] = @execution_log + " and after" |
| 210 | 218 | controller.assigns["after_ran"] = true |
| 211 | 219 | controller.class.execution_log << " after aroundfilter " if controller.respond_to? :execution_log |
| 212 | - end | |
| 220 | + end | |
| 213 | 221 | end |
| 214 | 222 | |
| 215 | 223 | class AppendedAroundFilter |
| ... | ... | @@ -219,12 +227,12 @@ class FilterTest < Test::Unit::TestCase |
| 219 | 227 | |
| 220 | 228 | def after(controller) |
| 221 | 229 | controller.class.execution_log << " after appended aroundfilter " |
| 222 | - end | |
| 223 | - end | |
| 224 | - | |
| 230 | + end | |
| 231 | + end | |
| 232 | + | |
| 225 | 233 | class AuditController < ActionController::Base |
| 226 | 234 | before_filter(AuditFilter) |
| 227 | - | |
| 235 | + | |
| 228 | 236 | def show |
| 229 | 237 | render_text "hello" |
| 230 | 238 | end |
| ... | ... | @@ -234,6 +242,14 @@ class FilterTest < Test::Unit::TestCase |
| 234 | 242 | around_filter AroundFilter.new |
| 235 | 243 | end |
| 236 | 244 | |
| 245 | + class BeforeAfterClassFilterController < PrependingController | |
| 246 | + begin | |
| 247 | + filter = AroundFilter.new | |
| 248 | + before_filter filter | |
| 249 | + after_filter filter | |
| 250 | + end | |
| 251 | + end | |
| 252 | + | |
| 237 | 253 | class MixedFilterController < PrependingController |
| 238 | 254 | cattr_accessor :execution_log |
| 239 | 255 | |
| ... | ... | @@ -247,7 +263,7 @@ class FilterTest < Test::Unit::TestCase |
| 247 | 263 | after_filter { |c| c.class.execution_log << " after procfilter " } |
| 248 | 264 | append_around_filter AppendedAroundFilter.new |
| 249 | 265 | end |
| 250 | - | |
| 266 | + | |
| 251 | 267 | class MixedSpecializationController < ActionController::Base |
| 252 | 268 | class OutOfOrder < StandardError; end |
| 253 | 269 | |
| ... | ... | @@ -285,6 +301,101 @@ class FilterTest < Test::Unit::TestCase |
| 285 | 301 | end |
| 286 | 302 | end |
| 287 | 303 | |
| 304 | + class PrependingBeforeAndAfterController < ActionController::Base | |
| 305 | + prepend_before_filter :before_all | |
| 306 | + prepend_after_filter :after_all | |
| 307 | + before_filter :between_before_all_and_after_all | |
| 308 | + | |
| 309 | + def before_all | |
| 310 | + @ran_filter ||= [] | |
| 311 | + @ran_filter << 'before_all' | |
| 312 | + end | |
| 313 | + | |
| 314 | + def after_all | |
| 315 | + @ran_filter ||= [] | |
| 316 | + @ran_filter << 'after_all' | |
| 317 | + end | |
| 318 | + | |
| 319 | + def between_before_all_and_after_all | |
| 320 | + @ran_filter ||= [] | |
| 321 | + @ran_filter << 'between_before_all_and_after_all' | |
| 322 | + end | |
| 323 | + def show | |
| 324 | + render :text => 'hello' | |
| 325 | + end | |
| 326 | + end | |
| 327 | + | |
| 328 | + class NonYieldingAroundFilterController < ActionController::Base | |
| 329 | + | |
| 330 | + before_filter :filter_one | |
| 331 | + around_filter :non_yielding_filter | |
| 332 | + before_filter :filter_two | |
| 333 | + after_filter :filter_three | |
| 334 | + | |
| 335 | + def index | |
| 336 | + render :inline => "index" | |
| 337 | + end | |
| 338 | + | |
| 339 | + #make sure the controller complains | |
| 340 | + def rescue_action(e); raise e; end | |
| 341 | + | |
| 342 | + private | |
| 343 | + | |
| 344 | + def filter_one | |
| 345 | + @filters ||= [] | |
| 346 | + @filters << "filter_one" | |
| 347 | + end | |
| 348 | + | |
| 349 | + def filter_two | |
| 350 | + @filters << "filter_two" | |
| 351 | + end | |
| 352 | + | |
| 353 | + def non_yielding_filter | |
| 354 | + @filters << "zomg it didn't yield" | |
| 355 | + @filter_return_value | |
| 356 | + end | |
| 357 | + | |
| 358 | + def filter_three | |
| 359 | + @filters << "filter_three" | |
| 360 | + end | |
| 361 | + | |
| 362 | + end | |
| 363 | + | |
| 364 | + def test_non_yielding_around_filters_not_returning_false_do_not_raise | |
| 365 | + controller = NonYieldingAroundFilterController.new | |
| 366 | + controller.instance_variable_set "@filter_return_value", true | |
| 367 | + assert_nothing_raised do | |
| 368 | + test_process(controller, "index") | |
| 369 | + end | |
| 370 | + end | |
| 371 | + | |
| 372 | + def test_non_yielding_around_filters_returning_false_do_not_raise | |
| 373 | + controller = NonYieldingAroundFilterController.new | |
| 374 | + controller.instance_variable_set "@filter_return_value", false | |
| 375 | + assert_nothing_raised do | |
| 376 | + test_process(controller, "index") | |
| 377 | + end | |
| 378 | + end | |
| 379 | + | |
| 380 | + def test_after_filters_are_not_run_if_around_filter_returns_false | |
| 381 | + controller = NonYieldingAroundFilterController.new | |
| 382 | + controller.instance_variable_set "@filter_return_value", false | |
| 383 | + test_process(controller, "index") | |
| 384 | + assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters'] | |
| 385 | + end | |
| 386 | + | |
| 387 | + def test_after_filters_are_not_run_if_around_filter_does_not_yield | |
| 388 | + controller = NonYieldingAroundFilterController.new | |
| 389 | + controller.instance_variable_set "@filter_return_value", true | |
| 390 | + test_process(controller, "index") | |
| 391 | + assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters'] | |
| 392 | + end | |
| 393 | + | |
| 394 | + def test_empty_filter_chain | |
| 395 | + assert_equal 0, EmptyFilterChainController.filter_chain.size | |
| 396 | + assert test_process(EmptyFilterChainController).template.assigns['action_executed'] | |
| 397 | + end | |
| 398 | + | |
| 288 | 399 | def test_added_filter_to_inheritance_graph |
| 289 | 400 | assert_equal [ :ensure_login ], TestController.before_filters |
| 290 | 401 | end |
| ... | ... | @@ -292,11 +403,11 @@ class FilterTest < Test::Unit::TestCase |
| 292 | 403 | def test_base_class_in_isolation |
| 293 | 404 | assert_equal [ ], ActionController::Base.before_filters |
| 294 | 405 | end |
| 295 | - | |
| 406 | + | |
| 296 | 407 | def test_prepending_filter |
| 297 | 408 | assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_filters |
| 298 | 409 | end |
| 299 | - | |
| 410 | + | |
| 300 | 411 | def test_running_filters |
| 301 | 412 | assert_equal %w( wonderful_life ensure_login ), test_process(PrependingController).template.assigns["ran_filter"] |
| 302 | 413 | end |
| ... | ... | @@ -304,11 +415,11 @@ class FilterTest < Test::Unit::TestCase |
| 304 | 415 | def test_running_filters_with_proc |
| 305 | 416 | assert test_process(ProcController).template.assigns["ran_proc_filter"] |
| 306 | 417 | end |
| 307 | - | |
| 418 | + | |
| 308 | 419 | def test_running_filters_with_implicit_proc |
| 309 | 420 | assert test_process(ImplicitProcController).template.assigns["ran_proc_filter"] |
| 310 | 421 | end |
| 311 | - | |
| 422 | + | |
| 312 | 423 | def test_running_filters_with_class |
| 313 | 424 | assert test_process(AuditController).template.assigns["was_audited"] |
| 314 | 425 | end |
| ... | ... | @@ -319,7 +430,7 @@ class FilterTest < Test::Unit::TestCase |
| 319 | 430 | assert response.template.assigns["ran_class_filter"] |
| 320 | 431 | assert response.template.assigns["ran_proc_filter1"] |
| 321 | 432 | assert response.template.assigns["ran_proc_filter2"] |
| 322 | - | |
| 433 | + | |
| 323 | 434 | response = test_process(AnomolousYetValidConditionController, "show_without_filter") |
| 324 | 435 | assert_equal nil, response.template.assigns["ran_filter"] |
| 325 | 436 | assert !response.template.assigns["ran_class_filter"] |
| ... | ... | @@ -373,6 +484,12 @@ class FilterTest < Test::Unit::TestCase |
| 373 | 484 | assert controller.template.assigns["after_ran"] |
| 374 | 485 | end |
| 375 | 486 | |
| 487 | + def test_before_after_class_filter | |
| 488 | + controller = test_process(BeforeAfterClassFilterController) | |
| 489 | + assert controller.template.assigns["before_ran"] | |
| 490 | + assert controller.template.assigns["after_ran"] | |
| 491 | + end | |
| 492 | + | |
| 376 | 493 | def test_having_properties_in_around_filter |
| 377 | 494 | controller = test_process(AroundFilterController) |
| 378 | 495 | assert_equal "before and after", controller.template.assigns["execution_log"] |
| ... | ... | @@ -381,10 +498,10 @@ class FilterTest < Test::Unit::TestCase |
| 381 | 498 | def test_prepending_and_appending_around_filter |
| 382 | 499 | controller = test_process(MixedFilterController) |
| 383 | 500 | assert_equal " before aroundfilter before procfilter before appended aroundfilter " + |
| 384 | - " after appended aroundfilter after aroundfilter after procfilter ", | |
| 501 | + " after appended aroundfilter after aroundfilter after procfilter ", | |
| 385 | 502 | MixedFilterController.execution_log |
| 386 | 503 | end |
| 387 | - | |
| 504 | + | |
| 388 | 505 | def test_rendering_breaks_filtering_chain |
| 389 | 506 | response = test_process(RenderingController) |
| 390 | 507 | assert_equal "something else", response.body |
| ... | ... | @@ -412,6 +529,12 @@ class FilterTest < Test::Unit::TestCase |
| 412 | 529 | end |
| 413 | 530 | end |
| 414 | 531 | |
| 532 | + def test_running_prepended_before_and_after_filter | |
| 533 | + assert_equal 3, PrependingBeforeAndAfterController.filter_chain.length | |
| 534 | + response = test_process(PrependingBeforeAndAfterController) | |
| 535 | + assert_equal %w( before_all between_before_all_and_after_all after_all ), response.template.assigns["ran_filter"] | |
| 536 | + end | |
| 537 | + | |
| 415 | 538 | def test_conditional_skipping_of_filters |
| 416 | 539 | assert_nil test_process(ConditionalSkippingController, "login").template.assigns["ran_filter"] |
| 417 | 540 | assert_equal %w( ensure_login find_user ), test_process(ConditionalSkippingController, "change_password").template.assigns["ran_filter"] | ... | ... |
vendor/rails/actionpack/test/controller/integration_test.rb
| ... | ... | @@ -11,7 +11,7 @@ require 'stubba' |
| 11 | 11 | module ActionController |
| 12 | 12 | module Integration |
| 13 | 13 | class Session |
| 14 | - def process | |
| 14 | + def process(*args) | |
| 15 | 15 | end |
| 16 | 16 | |
| 17 | 17 | def generic_url_rewriter |
| ... | ... | @@ -56,8 +56,7 @@ class SessionTest < Test::Unit::TestCase |
| 56 | 56 | |
| 57 | 57 | @session.expects(:get).with(path,args) |
| 58 | 58 | |
| 59 | - redirects = [true, true, false] | |
| 60 | - @session.stubs(:redirect?).returns(lambda { redirects.shift }) | |
| 59 | + @session.stubs(:redirect?).returns(true).then.returns(true).then.returns(false) | |
| 61 | 60 | @session.expects(:follow_redirect!).times(2) |
| 62 | 61 | |
| 63 | 62 | @session.stubs(:status).returns(200) |
| ... | ... | @@ -69,8 +68,7 @@ class SessionTest < Test::Unit::TestCase |
| 69 | 68 | |
| 70 | 69 | @session.expects(:post).with(path,args) |
| 71 | 70 | |
| 72 | - redirects = [true, true, false] | |
| 73 | - @session.stubs(:redirect?).returns(lambda { redirects.shift }) | |
| 71 | + @session.stubs(:redirect?).returns(true).then.returns(true).then.returns(false) | |
| 74 | 72 | @session.expects(:follow_redirect!).times(2) |
| 75 | 73 | |
| 76 | 74 | @session.stubs(:status).returns(200) |
| ... | ... | @@ -134,15 +132,102 @@ class SessionTest < Test::Unit::TestCase |
| 134 | 132 | @session.head(path,params,headers) |
| 135 | 133 | end |
| 136 | 134 | |
| 137 | - def test_xml_http_request | |
| 135 | + def test_xml_http_request_deprecated_call | |
| 138 | 136 | path = "/index"; params = "blah"; headers = {:location => 'blah'} |
| 139 | 137 | headers_after_xhr = headers.merge( |
| 140 | 138 | "X-Requested-With" => "XMLHttpRequest", |
| 141 | 139 | "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" |
| 142 | 140 | ) |
| 143 | - @session.expects(:post).with(path,params,headers_after_xhr) | |
| 144 | - @session.xml_http_request(path,params,headers) | |
| 141 | + @session.expects(:process).with(:post,path,params,headers_after_xhr) | |
| 142 | + assert_deprecated { @session.xml_http_request(path,params,headers) } | |
| 145 | 143 | end |
| 144 | + | |
| 145 | + def test_xml_http_request_get | |
| 146 | + path = "/index"; params = "blah"; headers = {:location => 'blah'} | |
| 147 | + headers_after_xhr = headers.merge( | |
| 148 | + "X-Requested-With" => "XMLHttpRequest", | |
| 149 | + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" | |
| 150 | + ) | |
| 151 | + @session.expects(:process).with(:get,path,params,headers_after_xhr) | |
| 152 | + @session.xml_http_request(:get,path,params,headers) | |
| 153 | + end | |
| 154 | + | |
| 155 | + def test_xml_http_request_post | |
| 156 | + path = "/index"; params = "blah"; headers = {:location => 'blah'} | |
| 157 | + headers_after_xhr = headers.merge( | |
| 158 | + "X-Requested-With" => "XMLHttpRequest", | |
| 159 | + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" | |
| 160 | + ) | |
| 161 | + @session.expects(:process).with(:post,path,params,headers_after_xhr) | |
| 162 | + @session.xml_http_request(:post,path,params,headers) | |
| 163 | + end | |
| 164 | + | |
| 165 | + def test_xml_http_request_put | |
| 166 | + path = "/index"; params = "blah"; headers = {:location => 'blah'} | |
| 167 | + headers_after_xhr = headers.merge( | |
| 168 | + "X-Requested-With" => "XMLHttpRequest", | |
| 169 | + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" | |
| 170 | + ) | |
| 171 | + @session.expects(:process).with(:put,path,params,headers_after_xhr) | |
| 172 | + @session.xml_http_request(:put,path,params,headers) | |
| 173 | + end | |
| 174 | + | |
| 175 | + def test_xml_http_request_delete | |
| 176 | + path = "/index"; params = "blah"; headers = {:location => 'blah'} | |
| 177 | + headers_after_xhr = headers.merge( | |
| 178 | + "X-Requested-With" => "XMLHttpRequest", | |
| 179 | + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" | |
| 180 | + ) | |
| 181 | + @session.expects(:process).with(:delete,path,params,headers_after_xhr) | |
| 182 | + @session.xml_http_request(:delete,path,params,headers) | |
| 183 | + end | |
| 184 | + | |
| 185 | + def test_xml_http_request_head | |
| 186 | + path = "/index"; params = "blah"; headers = {:location => 'blah'} | |
| 187 | + headers_after_xhr = headers.merge( | |
| 188 | + "X-Requested-With" => "XMLHttpRequest", | |
| 189 | + "Accept" => "text/javascript, text/html, application/xml, text/xml, */*" | |
| 190 | + ) | |
| 191 | + @session.expects(:process).with(:head,path,params,headers_after_xhr) | |
| 192 | + @session.xml_http_request(:head,path,params,headers) | |
| 193 | + end | |
| 194 | +end | |
| 195 | + | |
| 196 | +class IntegrationTestTest < Test::Unit::TestCase | |
| 197 | + | |
| 198 | + def setup | |
| 199 | + @test = ::ActionController::IntegrationTest.new(:default_test) | |
| 200 | + @test.class.stubs(:fixture_table_names).returns([]) | |
| 201 | + @session = @test.open_session | |
| 202 | + end | |
| 203 | + | |
| 204 | + def test_opens_new_session | |
| 205 | + @test.class.expects(:fixture_table_names).times(2).returns(['foo']) | |
| 206 | + | |
| 207 | + session1 = @test.open_session { |sess| } | |
| 208 | + session2 = @test.open_session # implicit session | |
| 209 | + | |
| 210 | + assert_equal ::ActionController::Integration::Session, session1.class | |
| 211 | + assert_equal ::ActionController::Integration::Session, session2.class | |
| 212 | + assert_not_equal session1, session2 | |
| 213 | + end | |
| 214 | + | |
| 215 | +end | |
| 216 | + | |
| 217 | +# Tests that integration tests don't call Controller test methods for processing. | |
| 218 | +# Integration tests have their own setup and teardown. | |
| 219 | +class IntegrationTestUsesCorrectClass < ActionController::IntegrationTest | |
| 220 | + | |
| 221 | + def self.fixture_table_names | |
| 222 | + [] | |
| 223 | + end | |
| 224 | + | |
| 225 | + def test_integration_methods_called | |
| 226 | + %w( get post head put delete ).each do |verb| | |
| 227 | + assert_nothing_raised("'#{verb}' should use integration test methods") { send(verb, '/') } | |
| 228 | + end | |
| 229 | + end | |
| 230 | + | |
| 146 | 231 | end |
| 147 | 232 | |
| 148 | 233 | # TODO | ... | ... |
vendor/rails/actionpack/test/controller/resources_test.rb
| ... | ... | @@ -10,8 +10,9 @@ class ThreadsController < ResourcesController; end |
| 10 | 10 | class MessagesController < ResourcesController; end |
| 11 | 11 | class CommentsController < ResourcesController; end |
| 12 | 12 | |
| 13 | -class AccountController < ResourcesController; end | |
| 14 | -class AdminController < ResourcesController; end | |
| 13 | +class AccountController < ResourcesController; end | |
| 14 | +class AdminController < ResourcesController; end | |
| 15 | +class ProductsController < ResourcesController; end | |
| 15 | 16 | |
| 16 | 17 | class ResourcesTest < Test::Unit::TestCase |
| 17 | 18 | def test_should_arrange_actions |
| ... | ... | @@ -63,13 +64,13 @@ class ResourcesTest < Test::Unit::TestCase |
| 63 | 64 | end |
| 64 | 65 | end |
| 65 | 66 | |
| 66 | - def test_multile_with_path_prefix | |
| 67 | + def test_multiple_with_path_prefix | |
| 67 | 68 | with_restful_routing :messages, :comments, :path_prefix => '/thread/:thread_id' do |
| 68 | 69 | assert_simply_restful_for :messages, :path_prefix => 'thread/5/', :options => { :thread_id => '5' } |
| 69 | 70 | assert_simply_restful_for :comments, :path_prefix => 'thread/5/', :options => { :thread_id => '5' } |
| 70 | 71 | end |
| 71 | 72 | end |
| 72 | - | |
| 73 | + | |
| 73 | 74 | def test_with_name_prefix |
| 74 | 75 | with_restful_routing :messages, :name_prefix => 'post_' do |
| 75 | 76 | assert_simply_restful_for :messages, :name_prefix => 'post_' |
| ... | ... | @@ -78,7 +79,7 @@ class ResourcesTest < Test::Unit::TestCase |
| 78 | 79 | |
| 79 | 80 | def test_with_collection_action |
| 80 | 81 | rss_options = {:action => 'rss'} |
| 81 | - rss_path = "/messages;rss" | |
| 82 | + rss_path = "/messages/rss" | |
| 82 | 83 | actions = { 'a' => :put, 'b' => :post, 'c' => :delete } |
| 83 | 84 | |
| 84 | 85 | with_restful_routing :messages, :collection => { :rss => :get }.merge(actions) do |
| ... | ... | @@ -86,14 +87,14 @@ class ResourcesTest < Test::Unit::TestCase |
| 86 | 87 | assert_routing rss_path, options.merge(rss_options) |
| 87 | 88 | |
| 88 | 89 | actions.each do |action, method| |
| 89 | - assert_recognizes(options.merge(:action => action), :path => "/messages;#{action}", :method => method) | |
| 90 | + assert_recognizes(options.merge(:action => action), :path => "/messages/#{action}", :method => method) | |
| 90 | 91 | end |
| 91 | 92 | end |
| 92 | 93 | |
| 93 | 94 | assert_restful_named_routes_for :messages do |options| |
| 94 | 95 | assert_named_route rss_path, :rss_messages_path, rss_options |
| 95 | 96 | actions.keys.each do |action| |
| 96 | - assert_named_route "/messages;#{action}", "#{action}_messages_path", :action => action | |
| 97 | + assert_named_route "/messages/#{action}", "#{action}_messages_path", :action => action | |
| 97 | 98 | end |
| 98 | 99 | end |
| 99 | 100 | end |
| ... | ... | @@ -103,7 +104,7 @@ class ResourcesTest < Test::Unit::TestCase |
| 103 | 104 | [:put, :post].each do |method| |
| 104 | 105 | with_restful_routing :messages, :member => { :mark => method } do |
| 105 | 106 | mark_options = {:action => 'mark', :id => '1'} |
| 106 | - mark_path = "/messages/1;mark" | |
| 107 | + mark_path = "/messages/1/mark" | |
| 107 | 108 | assert_restful_routes_for :messages do |options| |
| 108 | 109 | assert_recognizes(options.merge(mark_options), :path => mark_path, :method => method) |
| 109 | 110 | end |
| ... | ... | @@ -120,7 +121,7 @@ class ResourcesTest < Test::Unit::TestCase |
| 120 | 121 | with_restful_routing :messages, :member => { :mark => method, :unmark => method } do |
| 121 | 122 | %w(mark unmark).each do |action| |
| 122 | 123 | action_options = {:action => action, :id => '1'} |
| 123 | - action_path = "/messages/1;#{action}" | |
| 124 | + action_path = "/messages/1/#{action}" | |
| 124 | 125 | assert_restful_routes_for :messages do |options| |
| 125 | 126 | assert_recognizes(options.merge(action_options), :path => action_path, :method => method) |
| 126 | 127 | end |
| ... | ... | @@ -136,7 +137,7 @@ class ResourcesTest < Test::Unit::TestCase |
| 136 | 137 | def test_with_new_action |
| 137 | 138 | with_restful_routing :messages, :new => { :preview => :post } do |
| 138 | 139 | preview_options = {:action => 'preview'} |
| 139 | - preview_path = "/messages/new;preview" | |
| 140 | + preview_path = "/messages/new/preview" | |
| 140 | 141 | assert_restful_routes_for :messages do |options| |
| 141 | 142 | assert_recognizes(options.merge(preview_options), :path => preview_path, :method => :post) |
| 142 | 143 | end |
| ... | ... | @@ -178,9 +179,11 @@ class ResourcesTest < Test::Unit::TestCase |
| 178 | 179 | assert_simply_restful_for :threads |
| 179 | 180 | assert_simply_restful_for :messages, |
| 180 | 181 | :path_prefix => 'threads/1/', |
| 182 | + :name_prefix => 'thread_', | |
| 181 | 183 | :options => { :thread_id => '1' } |
| 182 | 184 | assert_simply_restful_for :comments, |
| 183 | 185 | :path_prefix => 'threads/1/messages/2/', |
| 186 | + :name_prefix => 'thread_message_', | |
| 184 | 187 | :options => { :thread_id => '1', :message_id => '2' } |
| 185 | 188 | end |
| 186 | 189 | end |
| ... | ... | @@ -217,9 +220,9 @@ class ResourcesTest < Test::Unit::TestCase |
| 217 | 220 | admin.resource :account |
| 218 | 221 | end |
| 219 | 222 | end |
| 220 | - | |
| 223 | + | |
| 221 | 224 | assert_singleton_restful_for :admin |
| 222 | - assert_singleton_restful_for :account, :path_prefix => 'admin/' | |
| 225 | + assert_singleton_restful_for :account, :path_prefix => 'admin/', :name_prefix => 'admin_' | |
| 223 | 226 | end |
| 224 | 227 | end |
| 225 | 228 | |
| ... | ... | @@ -227,7 +230,7 @@ class ResourcesTest < Test::Unit::TestCase |
| 227 | 230 | [:put, :post].each do |method| |
| 228 | 231 | with_singleton_resources :account, :member => { :reset => method } do |
| 229 | 232 | reset_options = {:action => 'reset'} |
| 230 | - reset_path = "/account;reset" | |
| 233 | + reset_path = "/account/reset" | |
| 231 | 234 | assert_singleton_routes_for :account do |options| |
| 232 | 235 | assert_recognizes(options.merge(reset_options), :path => reset_path, :method => method) |
| 233 | 236 | end |
| ... | ... | @@ -244,7 +247,7 @@ class ResourcesTest < Test::Unit::TestCase |
| 244 | 247 | with_singleton_resources :account, :member => { :reset => method, :disable => method } do |
| 245 | 248 | %w(reset disable).each do |action| |
| 246 | 249 | action_options = {:action => action} |
| 247 | - action_path = "/account;#{action}" | |
| 250 | + action_path = "/account/#{action}" | |
| 248 | 251 | assert_singleton_routes_for :account do |options| |
| 249 | 252 | assert_recognizes(options.merge(action_options), :path => action_path, :method => method) |
| 250 | 253 | end |
| ... | ... | @@ -264,9 +267,9 @@ class ResourcesTest < Test::Unit::TestCase |
| 264 | 267 | account.resources :messages |
| 265 | 268 | end |
| 266 | 269 | end |
| 267 | - | |
| 270 | + | |
| 268 | 271 | assert_singleton_restful_for :account |
| 269 | - assert_simply_restful_for :messages, :path_prefix => 'account/' | |
| 272 | + assert_simply_restful_for :messages, :path_prefix => 'account/', :name_prefix => 'account_' | |
| 270 | 273 | end |
| 271 | 274 | end |
| 272 | 275 | |
| ... | ... | @@ -279,10 +282,10 @@ class ResourcesTest < Test::Unit::TestCase |
| 279 | 282 | end |
| 280 | 283 | |
| 281 | 284 | assert_singleton_restful_for :account, :path_prefix => '7/', :options => { :site_id => '7' } |
| 282 | - assert_simply_restful_for :messages, :path_prefix => '7/account/', :options => { :site_id => '7' } | |
| 285 | + assert_simply_restful_for :messages, :path_prefix => '7/account/', :name_prefix => 'account_', :options => { :site_id => '7' } | |
| 283 | 286 | end |
| 284 | 287 | end |
| 285 | - | |
| 288 | + | |
| 286 | 289 | def test_should_nest_singleton_resource_in_resources |
| 287 | 290 | with_routing do |set| |
| 288 | 291 | set.draw do |map| |
| ... | ... | @@ -290,9 +293,9 @@ class ResourcesTest < Test::Unit::TestCase |
| 290 | 293 | thread.resource :admin |
| 291 | 294 | end |
| 292 | 295 | end |
| 293 | - | |
| 296 | + | |
| 294 | 297 | assert_simply_restful_for :threads |
| 295 | - assert_singleton_restful_for :admin, :path_prefix => 'threads/5/', :options => { :thread_id => '5' } | |
| 298 | + assert_singleton_restful_for :admin, :path_prefix => 'threads/5/', :name_prefix => 'thread_', :options => { :thread_id => '5' } | |
| 296 | 299 | end |
| 297 | 300 | end |
| 298 | 301 | |
| ... | ... | @@ -312,6 +315,181 @@ class ResourcesTest < Test::Unit::TestCase |
| 312 | 315 | end |
| 313 | 316 | end |
| 314 | 317 | |
| 318 | + def test_resource_action_separator | |
| 319 | + with_routing do |set| | |
| 320 | + set.draw do |map| | |
| 321 | + map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id' | |
| 322 | + map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin' | |
| 323 | + end | |
| 324 | + | |
| 325 | + action_separator = ActionController::Base.resource_action_separator | |
| 326 | + | |
| 327 | + assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' } | |
| 328 | + assert_named_route "/threads/1/messages#{action_separator}search", "search_thread_messages_path", {} | |
| 329 | + assert_named_route "/threads/1/messages/new", "new_thread_message_path", {} | |
| 330 | + assert_named_route "/threads/1/messages/new#{action_separator}preview", "preview_new_thread_message_path", {} | |
| 331 | + assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/' | |
| 332 | + assert_named_route "/admin/account#{action_separator}login", "login_admin_account_path", {} | |
| 333 | + assert_named_route "/admin/account/new", "new_admin_account_path", {} | |
| 334 | + assert_named_route "/admin/account/new#{action_separator}preview", "preview_new_admin_account_path", {} | |
| 335 | + end | |
| 336 | + end | |
| 337 | + | |
| 338 | + def test_new_style_named_routes_for_resource | |
| 339 | + with_routing do |set| | |
| 340 | + set.draw do |map| | |
| 341 | + map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id' | |
| 342 | + end | |
| 343 | + assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' } | |
| 344 | + assert_named_route "/threads/1/messages/search", "search_thread_messages_path", {} | |
| 345 | + assert_named_route "/threads/1/messages/new", "new_thread_message_path", {} | |
| 346 | + assert_named_route "/threads/1/messages/new/preview", "preview_new_thread_message_path", {} | |
| 347 | + end | |
| 348 | + end | |
| 349 | + | |
| 350 | + def test_new_style_named_routes_for_singleton_resource | |
| 351 | + with_routing do |set| | |
| 352 | + set.draw do |map| | |
| 353 | + map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin' | |
| 354 | + end | |
| 355 | + assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/' | |
| 356 | + assert_named_route "/admin/account/login", "login_admin_account_path", {} | |
| 357 | + assert_named_route "/admin/account/new", "new_admin_account_path", {} | |
| 358 | + assert_named_route "/admin/account/new/preview", "preview_new_admin_account_path", {} | |
| 359 | + end | |
| 360 | + end | |
| 361 | + | |
| 362 | + def test_should_add_deprecated_named_routes_for_resource | |
| 363 | + with_routing do |set| | |
| 364 | + set.draw do |map| | |
| 365 | + map.resources :messages, :collection => {:search => :get}, :new => {:preview => :any}, :name_prefix => 'thread_', :path_prefix => '/threads/:thread_id' | |
| 366 | + end | |
| 367 | + assert_simply_restful_for :messages, :name_prefix => 'thread_', :path_prefix => 'threads/1/', :options => { :thread_id => '1' } | |
| 368 | + assert_deprecated do | |
| 369 | + assert_named_route "/threads/1/messages/search", "thread_search_messages_path", {} | |
| 370 | + assert_named_route "/threads/1/messages/new", "thread_new_message_path", {} | |
| 371 | + assert_named_route "/threads/1/messages/new/preview", "thread_preview_new_message_path", {} | |
| 372 | + end | |
| 373 | + end | |
| 374 | + end | |
| 375 | + | |
| 376 | + def test_should_add_deprecated_named_routes_for_singleton_resource | |
| 377 | + with_routing do |set| | |
| 378 | + set.draw do |map| | |
| 379 | + map.resource :account, :member => {:login => :get}, :new => {:preview => :any}, :name_prefix => 'admin_', :path_prefix => '/admin' | |
| 380 | + end | |
| 381 | + assert_singleton_restful_for :account, :name_prefix => 'admin_', :path_prefix => 'admin/' | |
| 382 | + assert_deprecated do | |
| 383 | + assert_named_route "/admin/account/login", "admin_login_account_path", {} | |
| 384 | + assert_named_route "/admin/account/new", "admin_new_account_path", {} | |
| 385 | + assert_named_route "/admin/account/new/preview", "admin_preview_new_account_path", {} | |
| 386 | + end | |
| 387 | + end | |
| 388 | + end | |
| 389 | + | |
| 390 | + def test_should_add_deprecated_named_routes_for_nested_resources | |
| 391 | + with_routing do |set| | |
| 392 | + set.draw do |map| | |
| 393 | + map.resources :threads do |map| | |
| 394 | + map.resources :messages do |map| | |
| 395 | + map.resources :comments | |
| 396 | + end | |
| 397 | + end | |
| 398 | + end | |
| 399 | + | |
| 400 | + assert_simply_restful_for :threads | |
| 401 | + assert_simply_restful_for :messages, | |
| 402 | + :path_prefix => 'threads/1/', | |
| 403 | + :name_prefix => 'thread_', | |
| 404 | + :options => { :thread_id => '1' } | |
| 405 | + assert_simply_restful_for :comments, | |
| 406 | + :path_prefix => 'threads/1/messages/2/', | |
| 407 | + :name_prefix => 'thread_message_', | |
| 408 | + :options => { :thread_id => '1', :message_id => '2' } | |
| 409 | + | |
| 410 | + assert_deprecated do | |
| 411 | + assert_named_route "/threads/1/messages", "messages_path", {} | |
| 412 | + assert_named_route "/threads/1/messages/1", "message_path", {:thread_id => '1', :id => '1'} | |
| 413 | + assert_named_route "/threads/1/messages/new", "new_message_path", {:thread_id => '1'} | |
| 414 | + assert_named_route "/threads/1/messages/1/edit", "edit_message_path", {:thread_id => '1', :id => '1'} | |
| 415 | + end | |
| 416 | + end | |
| 417 | + end | |
| 418 | + | |
| 419 | + def test_should_add_deprecated_named_routes_for_nested_singleton_resources | |
| 420 | + with_routing do |set| | |
| 421 | + set.draw do |map| | |
| 422 | + map.resource :admin do |admin| | |
| 423 | + admin.resource :account | |
| 424 | + end | |
| 425 | + end | |
| 426 | + | |
| 427 | + assert_singleton_restful_for :admin | |
| 428 | + assert_singleton_restful_for :account, :path_prefix => 'admin/', :name_prefix => 'admin_' | |
| 429 | + | |
| 430 | + assert_deprecated do | |
| 431 | + assert_named_route "/admin/account", "account_path", {} | |
| 432 | + assert_named_route "/admin/account/new", "new_account_path", {} | |
| 433 | + assert_named_route "/admin/account/edit", "edit_account_path", {} | |
| 434 | + end | |
| 435 | + end | |
| 436 | + end | |
| 437 | + | |
| 438 | + def test_should_add_deprecated_named_routes_for_nested_resources_in_singleton_resource | |
| 439 | + with_routing do |set| | |
| 440 | + set.draw do |map| | |
| 441 | + map.resource :account do |account| | |
| 442 | + account.resources :messages | |
| 443 | + end | |
| 444 | + end | |
| 445 | + | |
| 446 | + assert_singleton_restful_for :account | |
| 447 | + assert_simply_restful_for :messages, :path_prefix => 'account/', :name_prefix => 'account_' | |
| 448 | + | |
| 449 | + assert_deprecated do | |
| 450 | + assert_named_route "/account/messages", "messages_path", {} | |
| 451 | + assert_named_route "/account/messages/1", "message_path", {:id => '1'} | |
| 452 | + assert_named_route "/account/messages/new", "new_message_path", {} | |
| 453 | + assert_named_route "/account/messages/1/edit", "edit_message_path", {:id => '1'} | |
| 454 | + end | |
| 455 | + end | |
| 456 | + end | |
| 457 | + | |
| 458 | + def test_should_add_deprecated_named_routes_for_nested_singleton_resource_in_resources | |
| 459 | + with_routing do |set| | |
| 460 | + set.draw do |map| | |
| 461 | + map.resources :threads do |thread| | |
| 462 | + thread.resource :admin | |
| 463 | + end | |
| 464 | + end | |
| 465 | + | |
| 466 | + assert_simply_restful_for :threads | |
| 467 | + assert_singleton_restful_for :admin, :path_prefix => 'threads/5/', :name_prefix => 'thread_', :options => { :thread_id => '5' } | |
| 468 | + | |
| 469 | + assert_deprecated do | |
| 470 | + assert_named_route "/threads/5/admin", "admin_path", {} | |
| 471 | + assert_named_route "/threads/5/admin/new", "new_admin_path", {} | |
| 472 | + assert_named_route "/threads/5/admin/edit", "edit_admin_path", {} | |
| 473 | + end | |
| 474 | + end | |
| 475 | + end | |
| 476 | + | |
| 477 | + def test_should_add_deprecated_formatted_routes | |
| 478 | + with_routing do |set| | |
| 479 | + set.draw do |map| | |
| 480 | + map.resources :products, :collection => { :specials => :get }, :member => { :thumbnail => :get } | |
| 481 | + map.resource :account, :member => { :icon => :get } | |
| 482 | + end | |
| 483 | + assert_restful_routes_for :products do |options| | |
| 484 | + assert_recognizes options.merge({ :action => 'specials', :format => 'xml' }), :path => '/products.xml;specials', :method => :get | |
| 485 | + assert_recognizes options.merge({ :action => 'thumbnail', :format => 'jpg', :id => '1' }), :path => '/products/1.jpg;thumbnail', :method => :get | |
| 486 | + end | |
| 487 | + assert_singleton_restful_for :account do |options| | |
| 488 | + assert_recognizes options.merge({ :action => 'icon', :format => 'jpg' }), :path => '/account.jpg;icon', :method => :get | |
| 489 | + end | |
| 490 | + end | |
| 491 | + end | |
| 492 | + | |
| 315 | 493 | protected |
| 316 | 494 | def with_restful_routing(*args) |
| 317 | 495 | with_routing do |set| |
| ... | ... | @@ -319,7 +497,7 @@ class ResourcesTest < Test::Unit::TestCase |
| 319 | 497 | yield |
| 320 | 498 | end |
| 321 | 499 | end |
| 322 | - | |
| 500 | + | |
| 323 | 501 | def with_singleton_resources(*args) |
| 324 | 502 | with_routing do |set| |
| 325 | 503 | set.draw { |map| map.resource(*args) } |
| ... | ... | @@ -344,8 +522,8 @@ class ResourcesTest < Test::Unit::TestCase |
| 344 | 522 | collection_path = "/#{options[:path_prefix]}#{controller_name}" |
| 345 | 523 | member_path = "#{collection_path}/1" |
| 346 | 524 | new_path = "#{collection_path}/new" |
| 347 | - edit_member_path = "#{member_path};edit" | |
| 348 | - formatted_edit_member_path = "#{member_path}.xml;edit" | |
| 525 | + edit_member_path = "#{member_path}/edit" | |
| 526 | + formatted_edit_member_path = "#{member_path}/edit.xml" | |
| 349 | 527 | |
| 350 | 528 | with_options(options[:options]) do |controller| |
| 351 | 529 | controller.assert_routing collection_path, :action => 'index' |
| ... | ... | @@ -395,13 +573,13 @@ class ResourcesTest < Test::Unit::TestCase |
| 395 | 573 | name_prefix = options[:name_prefix] |
| 396 | 574 | |
| 397 | 575 | assert_named_route "#{full_prefix}", "#{name_prefix}#{controller_name}_path", options[:options] |
| 398 | - assert_named_route "#{full_prefix}/new", "#{name_prefix}new_#{singular_name}_path", options[:options] | |
| 576 | + assert_named_route "#{full_prefix}/new", "new_#{name_prefix}#{singular_name}_path", options[:options] | |
| 399 | 577 | assert_named_route "#{full_prefix}/1", "#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1') |
| 400 | - assert_named_route "#{full_prefix}/1;edit", "#{name_prefix}edit_#{singular_name}_path", options[:options].merge(:id => '1') | |
| 578 | + assert_named_route "#{full_prefix}/1/edit", "edit_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1') | |
| 401 | 579 | assert_named_route "#{full_prefix}.xml", "formatted_#{name_prefix}#{controller_name}_path", options[:options].merge( :format => 'xml') |
| 402 | - assert_named_route "#{full_prefix}/new.xml", "formatted_#{name_prefix}new_#{singular_name}_path", options[:options].merge( :format => 'xml') | |
| 580 | + assert_named_route "#{full_prefix}/new.xml", "formatted_new_#{name_prefix}#{singular_name}_path", options[:options].merge( :format => 'xml') | |
| 403 | 581 | assert_named_route "#{full_prefix}/1.xml", "formatted_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml') |
| 404 | - assert_named_route "#{full_prefix}/1.xml;edit", "formatted_#{name_prefix}edit_#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml') | |
| 582 | + assert_named_route "#{full_prefix}/1/edit.xml", "formatted_edit_#{name_prefix}#{singular_name}_path", options[:options].merge(:id => '1', :format => 'xml') | |
| 405 | 583 | yield options[:options] if block_given? |
| 406 | 584 | end |
| 407 | 585 | |
| ... | ... | @@ -410,8 +588,8 @@ class ResourcesTest < Test::Unit::TestCase |
| 410 | 588 | |
| 411 | 589 | full_path = "/#{options[:path_prefix]}#{singleton_name}" |
| 412 | 590 | new_path = "#{full_path}/new" |
| 413 | - edit_path = "#{full_path};edit" | |
| 414 | - formatted_edit_path = "#{full_path}.xml;edit" | |
| 591 | + edit_path = "#{full_path}/edit" | |
| 592 | + formatted_edit_path = "#{full_path}/edit.xml" | |
| 415 | 593 | |
| 416 | 594 | with_options options[:options] do |controller| |
| 417 | 595 | controller.assert_routing full_path, :action => 'show' |
| ... | ... | @@ -448,13 +626,14 @@ class ResourcesTest < Test::Unit::TestCase |
| 448 | 626 | options[:options].delete :action |
| 449 | 627 | |
| 450 | 628 | full_path = "/#{options[:path_prefix]}#{singleton_name}" |
| 451 | - | |
| 452 | - assert_named_route "#{full_path}", "#{singleton_name}_path", options[:options] | |
| 453 | - assert_named_route "#{full_path}/new", "new_#{singleton_name}_path", options[:options] | |
| 454 | - assert_named_route "#{full_path};edit", "edit_#{singleton_name}_path", options[:options] | |
| 455 | - assert_named_route "#{full_path}.xml", "formatted_#{singleton_name}_path", options[:options].merge(:format => 'xml') | |
| 456 | - assert_named_route "#{full_path}/new.xml", "formatted_new_#{singleton_name}_path", options[:options].merge(:format => 'xml') | |
| 457 | - assert_named_route "#{full_path}.xml;edit", "formatted_edit_#{singleton_name}_path", options[:options].merge(:format => 'xml') | |
| 629 | + full_name = "#{options[:name_prefix]}#{singleton_name}" | |
| 630 | + | |
| 631 | + assert_named_route "#{full_path}", "#{full_name}_path", options[:options] | |
| 632 | + assert_named_route "#{full_path}/new", "new_#{full_name}_path", options[:options] | |
| 633 | + assert_named_route "#{full_path}/edit", "edit_#{full_name}_path", options[:options] | |
| 634 | + assert_named_route "#{full_path}.xml", "formatted_#{full_name}_path", options[:options].merge(:format => 'xml') | |
| 635 | + assert_named_route "#{full_path}/new.xml", "formatted_new_#{full_name}_path", options[:options].merge(:format => 'xml') | |
| 636 | + assert_named_route "#{full_path}/edit.xml", "formatted_edit_#{full_name}_path", options[:options].merge(:format => 'xml') | |
| 458 | 637 | end |
| 459 | 638 | |
| 460 | 639 | def assert_named_route(expected, route, options) | ... | ... |
vendor/rails/actionpack/test/controller/routing_test.rb
| ... | ... | @@ -265,7 +265,7 @@ class LegacyRouteSetTests < Test::Unit::TestCase |
| 265 | 265 | map.content '/content/:query', :controller => 'content', :action => 'show' |
| 266 | 266 | end |
| 267 | 267 | exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'content', :action => 'show', :use_route => "content") } |
| 268 | - expected_message = %[content_url failed to generate from {:action=>"show", :controller=>"content"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: ["content", :query] - are they all satisifed?] | |
| 268 | + expected_message = "content_url failed to generate from #{{:action=>"show", :controller=>"content"}.inspect} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: [\"content\", :query] - are they all satisifed?" | |
| 269 | 269 | assert_equal expected_message, exception.message |
| 270 | 270 | end |
| 271 | 271 | |
| ... | ... | @@ -946,7 +946,7 @@ class RouteTest < Test::Unit::TestCase |
| 946 | 946 | end |
| 947 | 947 | |
| 948 | 948 | def test_expand_array_build_query_string |
| 949 | - assert_equal '?x[]=1&x[]=2', order_query_string(@route.build_query_string(:x => [1, 2])) | |
| 949 | + assert_equal '?x%5B%5D=1&x%5B%5D=2', order_query_string(@route.build_query_string(:x => [1, 2])) | |
| 950 | 950 | end |
| 951 | 951 | |
| 952 | 952 | def test_escape_spaces_build_query_string_selected_keys | ... | ... |
vendor/rails/actionpack/test/controller/session_fixation_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,92 @@ |
| 1 | +require File.dirname(__FILE__) + '/../abstract_unit' | |
| 2 | + | |
| 3 | +class SessionFixationTest < Test::Unit::TestCase | |
| 4 | + class MockCGI < CGI #:nodoc: | |
| 5 | + attr_accessor :stdoutput, :env_table | |
| 6 | + | |
| 7 | + def initialize(env, data = '') | |
| 8 | + self.env_table = env | |
| 9 | + self.stdoutput = StringIO.new | |
| 10 | + super(StringIO.new(data)) | |
| 11 | + end | |
| 12 | + end | |
| 13 | + | |
| 14 | + class TestController < ActionController::Base | |
| 15 | + session :session_key => '_myapp_session_id', :secret => 'secret', :except => :default_session_key | |
| 16 | + session :cookie_only => false, :only => :allow_session_fixation | |
| 17 | + | |
| 18 | + def default_session_key | |
| 19 | + render :text => "default_session_key" | |
| 20 | + end | |
| 21 | + | |
| 22 | + def custom_session_key | |
| 23 | + render :text => "custom_session_key: #{params[:id]}" | |
| 24 | + end | |
| 25 | + | |
| 26 | + def allow_session_fixation | |
| 27 | + render :text => "allow_session_fixation" | |
| 28 | + end | |
| 29 | + | |
| 30 | + def rescue_action(e) raise end | |
| 31 | + end | |
| 32 | + | |
| 33 | + def setup | |
| 34 | + @controller = TestController.new | |
| 35 | + end | |
| 36 | + | |
| 37 | + def test_should_be_able_to_make_a_successful_request | |
| 38 | + cgi = mock_cgi_for_request_to(:custom_session_key, :id => 1) | |
| 39 | + | |
| 40 | + assert_nothing_raised do | |
| 41 | + @controller.send(:process, mock_request(cgi), ActionController::CgiResponse.new(cgi)) | |
| 42 | + end | |
| 43 | + assert_equal 'custom_session_key: 1', @controller.response.body | |
| 44 | + assert_not_nil @controller.session | |
| 45 | + end | |
| 46 | + | |
| 47 | + def test_should_catch_session_fixation_attempt | |
| 48 | + cgi = mock_cgi_for_request_to(:custom_session_key, :_myapp_session_id => 42) | |
| 49 | + | |
| 50 | + assert_raises ActionController::CgiRequest::SessionFixationAttempt do | |
| 51 | + @controller.send(:process, mock_request(cgi), ActionController::CgiResponse.new(cgi)) | |
| 52 | + end | |
| 53 | + assert_nil @controller.session | |
| 54 | + end | |
| 55 | + | |
| 56 | + def test_should_not_catch_session_fixation_attempt_when_cookie_only_setting_is_disabled | |
| 57 | + cgi = mock_cgi_for_request_to(:allow_session_fixation, :_myapp_session_id => 42) | |
| 58 | + | |
| 59 | + assert_nothing_raised do | |
| 60 | + @controller.send(:process, mock_request(cgi), ActionController::CgiResponse.new(cgi)) | |
| 61 | + end | |
| 62 | + assert !@controller.response.body.blank? | |
| 63 | + assert_not_nil @controller.session | |
| 64 | + end | |
| 65 | + | |
| 66 | + def test_should_catch_session_fixation_attempt_with_default_session_key | |
| 67 | + ActionController::Base.session_store = :p_store # using the default session_key is not possible with cookie store | |
| 68 | + cgi = mock_cgi_for_request_to(:default_session_key, :_session_id => 42) | |
| 69 | + | |
| 70 | + assert_raises ActionController::CgiRequest::SessionFixationAttempt do | |
| 71 | + @controller.send(:process, mock_request(cgi) , ActionController::CgiResponse.new(cgi)) | |
| 72 | + end | |
| 73 | + assert @controller.response.body.blank? | |
| 74 | + assert_nil @controller.session | |
| 75 | + end | |
| 76 | + | |
| 77 | +private | |
| 78 | + | |
| 79 | + def mock_cgi_for_request_to(action, params = {}) | |
| 80 | + MockCGI.new({ | |
| 81 | + "REQUEST_METHOD" => "GET", | |
| 82 | + "QUERY_STRING" => "action=#{action}&#{params.to_query}", | |
| 83 | + "REQUEST_URI" => "/", | |
| 84 | + "SERVER_PORT" => "80", | |
| 85 | + "HTTP_HOST" => "testdomain.com" }, '') | |
| 86 | + end | |
| 87 | + | |
| 88 | + def mock_request(cgi) | |
| 89 | + ActionController::CgiRequest.new(cgi, {}) | |
| 90 | + end | |
| 91 | + | |
| 92 | +end | ... | ... |
vendor/rails/actionpack/test/controller/test_test.rb
| ... | ... | @@ -482,6 +482,22 @@ HTML |
| 482 | 482 | end |
| 483 | 483 | end |
| 484 | 484 | |
| 485 | + def test_request_uri_updates | |
| 486 | + get :test_params | |
| 487 | + uri = @request.request_uri | |
| 488 | + assert_equal @request.env['REQUEST_URI'], uri | |
| 489 | + | |
| 490 | + get :test_uri | |
| 491 | + assert_not_equal uri, @request.request_uri | |
| 492 | + uri = @request.request_uri | |
| 493 | + assert_equal @request.env['REQUEST_URI'], uri | |
| 494 | + | |
| 495 | + get :test_uri, :testing => true | |
| 496 | + assert_not_equal uri, @request.request_uri | |
| 497 | + uri = @request.request_uri | |
| 498 | + assert_equal @request.env['REQUEST_URI'], uri | |
| 499 | + end | |
| 500 | + | |
| 485 | 501 | protected |
| 486 | 502 | def with_foo_routing |
| 487 | 503 | with_routing do |set| | ... | ... |
vendor/rails/actionpack/test/controller/url_rewriter_test.rb
| ... | ... | @@ -17,15 +17,12 @@ class UrlRewriterTests < Test::Unit::TestCase |
| 17 | 17 | assert_match %r(/hi/hi/2$), u |
| 18 | 18 | end |
| 19 | 19 | |
| 20 | - | |
| 21 | - private | |
| 22 | - def split_query_string(str) | |
| 23 | - [str[0].chr] + str[1..-1].split(/&/).sort | |
| 24 | - end | |
| 25 | - | |
| 26 | - def assert_query_equal(q1, q2) | |
| 27 | - assert_equal(split_query_string(q1), split_query_string(q2)) | |
| 28 | - end | |
| 20 | + def test_anchor | |
| 21 | + assert_equal( | |
| 22 | + 'http://test.host/c/a/i#anchor', | |
| 23 | + @rewriter.rewrite(:controller => 'c', :action => 'a', :id => 'i', :anchor => 'anchor') | |
| 24 | + ) | |
| 25 | + end | |
| 29 | 26 | end |
| 30 | 27 | |
| 31 | 28 | class UrlWriterTests < Test::Unit::TestCase |
| ... | ... | @@ -75,6 +72,12 @@ class UrlWriterTests < Test::Unit::TestCase |
| 75 | 72 | W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https') |
| 76 | 73 | ) |
| 77 | 74 | end |
| 75 | + | |
| 76 | + def test_anchor | |
| 77 | + assert_equal('/c/a#anchor', | |
| 78 | + W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => 'anchor') | |
| 79 | + ) | |
| 80 | + end | |
| 78 | 81 | |
| 79 | 82 | def test_named_route |
| 80 | 83 | ActionController::Routing::Routes.draw do |map| |
| ... | ... | @@ -111,5 +114,58 @@ class UrlWriterTests < Test::Unit::TestCase |
| 111 | 114 | ensure |
| 112 | 115 | ActionController::Routing::Routes.load! |
| 113 | 116 | end |
| 114 | - | |
| 117 | + | |
| 118 | + def test_one_parameter | |
| 119 | + assert_equal('/c/a?param=val', | |
| 120 | + W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :param => 'val') | |
| 121 | + ) | |
| 122 | + end | |
| 123 | + | |
| 124 | + def test_two_parameters | |
| 125 | + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :p1 => 'X1', :p2 => 'Y2') | |
| 126 | + params = extract_params(url) | |
| 127 | + assert_equal params[0], { :p1 => 'X1' }.to_query | |
| 128 | + assert_equal params[1], { :p2 => 'Y2' }.to_query | |
| 129 | + end | |
| 130 | + | |
| 131 | + def test_hash_parameter | |
| 132 | + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => {:name => 'Bob', :category => 'prof'}) | |
| 133 | + params = extract_params(url) | |
| 134 | + assert_equal params[0], { 'query[category]' => 'prof' }.to_query | |
| 135 | + assert_equal params[1], { 'query[name]' => 'Bob' }.to_query | |
| 136 | + end | |
| 137 | + | |
| 138 | + def test_array_parameter | |
| 139 | + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => ['Bob', 'prof']) | |
| 140 | + params = extract_params(url) | |
| 141 | + assert_equal params[0], { 'query[]' => 'Bob' }.to_query | |
| 142 | + assert_equal params[1], { 'query[]' => 'prof' }.to_query | |
| 143 | + end | |
| 144 | + | |
| 145 | + def test_hash_recursive_parameters | |
| 146 | + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :query => {:person => {:name => 'Bob', :position => 'prof'}, :hobby => 'piercing'}) | |
| 147 | + params = extract_params(url) | |
| 148 | + assert_equal params[0], { 'query[hobby]' => 'piercing' }.to_query | |
| 149 | + assert_equal params[1], { 'query[person][name]' => 'Bob' }.to_query | |
| 150 | + assert_equal params[2], { 'query[person][position]' => 'prof' }.to_query | |
| 151 | + end | |
| 152 | + | |
| 153 | + def test_hash_recursive_and_array_parameters | |
| 154 | + url = W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :id => 101, :query => {:person => {:name => 'Bob', :position => ['prof', 'art director']}, :hobby => 'piercing'}) | |
| 155 | + assert_match %r(^/c/a/101), url | |
| 156 | + params = extract_params(url) | |
| 157 | + assert_equal params[0], { 'query[hobby]' => 'piercing' }.to_query | |
| 158 | + assert_equal params[1], { 'query[person][name]' => 'Bob' }.to_query | |
| 159 | + assert_equal params[2], { 'query[person][position][]' => 'art director' }.to_query | |
| 160 | + assert_equal params[3], { 'query[person][position][]' => 'prof' }.to_query | |
| 161 | + end | |
| 162 | + | |
| 163 | + def test_path_generation_for_symbol_parameter_keys | |
| 164 | + assert_generates("/image", :controller=> :image) | |
| 165 | + end | |
| 166 | + | |
| 167 | + private | |
| 168 | + def extract_params(url) | |
| 169 | + url.split('?', 2).last.split('&') | |
| 170 | + end | |
| 115 | 171 | end | ... | ... |
vendor/rails/actionpack/test/controller/verification_test.rb
| ... | ... | @@ -34,9 +34,16 @@ class VerificationTest < Test::Unit::TestCase |
| 34 | 34 | |
| 35 | 35 | verify :only => :must_be_post, :method => :post, :render => { :status => 405, :text => "Must be post" }, :add_headers => { "Allow" => "POST" } |
| 36 | 36 | |
| 37 | + verify :only => :guarded_one_for_named_route_test, :params => "one", | |
| 38 | + :redirect_to => :foo_url | |
| 39 | + | |
| 37 | 40 | def guarded_one |
| 38 | 41 | render :text => "#{params[:one]}" |
| 39 | 42 | end |
| 43 | + | |
| 44 | + def guarded_one_for_named_route_test | |
| 45 | + render :text => "#{params[:one]}" | |
| 46 | + end | |
| 40 | 47 | |
| 41 | 48 | def guarded_with_flash |
| 42 | 49 | render :text => "#{params[:one]}" |
| ... | ... | @@ -94,6 +101,14 @@ class VerificationTest < Test::Unit::TestCase |
| 94 | 101 | @controller = TestController.new |
| 95 | 102 | @request = ActionController::TestRequest.new |
| 96 | 103 | @response = ActionController::TestResponse.new |
| 104 | + ActionController::Routing::Routes.add_named_route :foo, '/foo', :controller => 'test', :action => 'foo' | |
| 105 | + end | |
| 106 | + | |
| 107 | + def test_no_deprecation_warning_for_named_route | |
| 108 | + assert_not_deprecated do | |
| 109 | + get :guarded_one_for_named_route_test, :two => "not one" | |
| 110 | + assert_redirected_to '/foo' | |
| 111 | + end | |
| 97 | 112 | end |
| 98 | 113 | |
| 99 | 114 | def test_guarded_one_with_prereqs | ... | ... |
vendor/rails/actionpack/test/fixtures/test/hello_world.rxml
vendor/rails/actionpack/test/template/asset_tag_helper_test.rb
| ... | ... | @@ -165,7 +165,12 @@ class AssetTagHelperTest < Test::Unit::TestCase |
| 165 | 165 | |
| 166 | 166 | def test_preset_empty_asset_id |
| 167 | 167 | Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + "/../fixtures/") |
| 168 | + # on windows, setting ENV["XXX"] to "" makes ENV["XXX"] return nil | |
| 169 | + if RUBY_PLATFORM =~ /win32/ | |
| 170 | + ENV["RAILS_ASSET_ID"] = " " | |
| 171 | + else | |
| 168 | 172 | ENV["RAILS_ASSET_ID"] = "" |
| 173 | + end | |
| 169 | 174 | assert_equal %(<img alt="Rails" src="/images/rails.png" />), image_tag("rails.png") |
| 170 | 175 | end |
| 171 | 176 | ... | ... |
vendor/rails/actionpack/test/template/compiled_templates_test.rb
| ... | ... | @@ -71,7 +71,12 @@ class CompiledTemplateTests < Test::Unit::TestCase |
| 71 | 71 | end |
| 72 | 72 | |
| 73 | 73 | def test_compile_time |
| 74 | - `echo '#{@a}' > #{@a}; echo '#{@b}' > #{@b}; ln -s #{@a} #{@s}` | |
| 74 | + File.open(@a, "w"){|f| f.puts @a} | |
| 75 | + File.open(@b, "w"){|f| f.puts @b} | |
| 76 | + | |
| 77 | + # windows doesn't support symlinks (even under cygwin) | |
| 78 | + windows = (RUBY_PLATFORM =~ /win32/) | |
| 79 | + `ln -s #{@a} #{@s}` unless windows | |
| 75 | 80 | |
| 76 | 81 | v = ActionView::Base.new |
| 77 | 82 | v.base_path = '.' |
| ... | ... | @@ -79,47 +84,54 @@ class CompiledTemplateTests < Test::Unit::TestCase |
| 79 | 84 | |
| 80 | 85 | sleep 1 |
| 81 | 86 | t = Time.now |
| 87 | + sleep 1 | |
| 88 | + | |
| 82 | 89 | v.compile_and_render_template(:rhtml, '', @a) |
| 83 | 90 | v.compile_and_render_template(:rhtml, '', @b) |
| 84 | - v.compile_and_render_template(:rhtml, '', @s) | |
| 91 | + v.compile_and_render_template(:rhtml, '', @s) unless windows | |
| 92 | + | |
| 85 | 93 | a_n = v.method_names[@a] |
| 86 | 94 | b_n = v.method_names[@b] |
| 87 | - s_n = v.method_names[@s] | |
| 95 | + s_n = v.method_names[@s] unless windows | |
| 96 | + ct_a = v.compile_time[a_n] | |
| 97 | + ct_b = v.compile_time[b_n] | |
| 98 | + ct_s = v.compile_time[s_n] unless windows | |
| 88 | 99 | # all of the files have changed since last compile |
| 89 | 100 | assert v.compile_time[a_n] > t |
| 90 | 101 | assert v.compile_time[b_n] > t |
| 91 | - assert v.compile_time[s_n] > t | |
| 102 | + assert v.compile_time[s_n] > t unless windows | |
| 92 | 103 | |
| 93 | 104 | sleep 1 |
| 94 | - t = Time.now | |
| 95 | 105 | v.compile_and_render_template(:rhtml, '', @a) |
| 96 | 106 | v.compile_and_render_template(:rhtml, '', @b) |
| 97 | - v.compile_and_render_template(:rhtml, '', @s) | |
| 107 | + v.compile_and_render_template(:rhtml, '', @s) unless windows | |
| 98 | 108 | # none of the files have changed since last compile |
| 99 | - assert v.compile_time[a_n] < t | |
| 100 | - assert v.compile_time[b_n] < t | |
| 101 | - assert v.compile_time[s_n] < t | |
| 109 | + # so they should not have been recmpiled | |
| 110 | + assert_equal ct_a, v.compile_time[a_n] | |
| 111 | + assert_equal ct_b, v.compile_time[b_n] | |
| 112 | + assert_equal ct_s, v.compile_time[s_n] unless windows | |
| 102 | 113 | |
| 103 | - `rm #{@s}; ln -s #{@b} #{@s}` | |
| 114 | + `rm #{@s}; ln -s #{@b} #{@s}` unless windows | |
| 104 | 115 | v.compile_and_render_template(:rhtml, '', @a) |
| 105 | 116 | v.compile_and_render_template(:rhtml, '', @b) |
| 106 | - v.compile_and_render_template(:rhtml, '', @s) | |
| 117 | + v.compile_and_render_template(:rhtml, '', @s) unless windows | |
| 107 | 118 | # the symlink has changed since last compile |
| 108 | - assert v.compile_time[a_n] < t | |
| 109 | - assert v.compile_time[b_n] < t | |
| 110 | - assert v.compile_time[s_n] > t | |
| 119 | + assert_equal ct_a, v.compile_time[a_n] | |
| 120 | + assert_equal ct_b, v.compile_time[b_n] | |
| 121 | + assert v.compile_time[s_n] > t unless windows | |
| 111 | 122 | |
| 112 | 123 | sleep 1 |
| 113 | - `touch #{@b}` | |
| 124 | + FileUtils.touch @b | |
| 114 | 125 | t = Time.now |
| 126 | + sleep 1 | |
| 115 | 127 | v.compile_and_render_template(:rhtml, '', @a) |
| 116 | 128 | v.compile_and_render_template(:rhtml, '', @b) |
| 117 | - v.compile_and_render_template(:rhtml, '', @s) | |
| 129 | + v.compile_and_render_template(:rhtml, '', @s) unless windows | |
| 118 | 130 | # the file at the end of the symlink has changed since last compile |
| 119 | 131 | # both the symlink and the file at the end of it should be recompiled |
| 120 | 132 | assert v.compile_time[a_n] < t |
| 121 | 133 | assert v.compile_time[b_n] > t |
| 122 | - assert v.compile_time[s_n] > t | |
| 134 | + assert v.compile_time[s_n] > t unless windows | |
| 123 | 135 | end |
| 124 | 136 | end |
| 125 | 137 | ... | ... |
vendor/rails/actionpack/test/template/javascript_helper_test.rb
| ... | ... | @@ -36,14 +36,14 @@ class JavaScriptHelperTest < Test::Unit::TestCase |
| 36 | 36 | html = link_to_function( "Greet me!" ) do |page| |
| 37 | 37 | page.replace_html 'header', "<h1>Greetings</h1>" |
| 38 | 38 | end |
| 39 | - assert_dom_equal %(<a href="#" onclick="Element.update("header", "<h1>Greetings</h1>");; return false;">Greet me!</a>), html | |
| 39 | + assert_dom_equal %q(<a href="#" onclick="Element.update("header", "\074h1\076Greetings\074/h1\076");; return false;">Greet me!</a>), html | |
| 40 | 40 | end |
| 41 | 41 | |
| 42 | 42 | def test_link_to_function_with_rjs_block_and_options |
| 43 | 43 | html = link_to_function( "Greet me!", :class => "updater" ) do |page| |
| 44 | 44 | page.replace_html 'header', "<h1>Greetings</h1>" |
| 45 | 45 | end |
| 46 | - assert_dom_equal %(<a href="#" class="updater" onclick="Element.update("header", "<h1>Greetings</h1>");; return false;">Greet me!</a>), html | |
| 46 | + assert_dom_equal %q(<a href="#" class="updater" onclick="Element.update("header", "\074h1\076Greetings\074/h1\076");; return false;">Greet me!</a>), html | |
| 47 | 47 | end |
| 48 | 48 | |
| 49 | 49 | def test_button_to_function |
| ... | ... | @@ -55,13 +55,13 @@ class JavaScriptHelperTest < Test::Unit::TestCase |
| 55 | 55 | html = button_to_function( "Greet me!" ) do |page| |
| 56 | 56 | page.replace_html 'header', "<h1>Greetings</h1>" |
| 57 | 57 | end |
| 58 | - assert_dom_equal %(<input type="button" onclick="Element.update("header", "<h1>Greetings</h1>");;" value="Greet me!" />), html | |
| 58 | + assert_dom_equal %q(<input type="button" onclick="Element.update("header", "\074h1\076Greetings\074/h1\076");;" value="Greet me!" />), html | |
| 59 | 59 | end |
| 60 | 60 | |
| 61 | 61 | def test_button_to_function_with_rjs_block_and_options |
| 62 | 62 | html = button_to_function( "Greet me!", :class => "greeter" ) do |page| |
| 63 | 63 | page.replace_html 'header', "<h1>Greetings</h1>" |
| 64 | 64 | end |
| 65 | - assert_dom_equal %(<input type="button" class="greeter" onclick="Element.update("header", "<h1>Greetings</h1>");;" value="Greet me!" />), html | |
| 65 | + assert_dom_equal %q(<input type="button" class="greeter" onclick="Element.update("header", "\074h1\076Greetings\074/h1\076");;" value="Greet me!" />), html | |
| 66 | 66 | end |
| 67 | 67 | end | ... | ... |
vendor/rails/actionpack/test/template/number_helper_test.rb
| ... | ... | @@ -22,7 +22,7 @@ class NumberHelperTest < Test::Unit::TestCase |
| 22 | 22 | def test_number_to_currency |
| 23 | 23 | assert_equal("$1,234,567,890.50", number_to_currency(1234567890.50)) |
| 24 | 24 | assert_equal("$1,234,567,890.51", number_to_currency(1234567890.506)) |
| 25 | - assert_equal("$1,234,567,890", number_to_currency(1234567890.50, {:precision => 0})) | |
| 25 | + assert_equal("$1,234,567,891", number_to_currency(1234567890.51, {:precision => 0})) | |
| 26 | 26 | assert_equal("$1,234,567,890.5", number_to_currency(1234567890.50, {:precision => 1})) |
| 27 | 27 | assert_equal("£1234567890,50", number_to_currency(1234567890.50, {:unit => "£", :separator => ",", :delimiter => ""})) |
| 28 | 28 | assert_equal("$1,234,567,890.50", number_to_currency("1234567890.50")) | ... | ... |
vendor/rails/actionpack/test/template/prototype_helper_test.rb
| ... | ... | @@ -125,7 +125,7 @@ class PrototypeHelperTest < Test::Unit::TestCase |
| 125 | 125 | end |
| 126 | 126 | |
| 127 | 127 | def test_observe_field |
| 128 | - assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/reorder_if_empty', {asynchronous:true, evalScripts:true})})\n//]]>\n</script>), | |
| 128 | + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/reorder_if_empty', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>), | |
| 129 | 129 | observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) |
| 130 | 130 | end |
| 131 | 131 | |
| ... | ... | @@ -135,7 +135,7 @@ class PrototypeHelperTest < Test::Unit::TestCase |
| 135 | 135 | end |
| 136 | 136 | |
| 137 | 137 | def test_observe_form |
| 138 | - assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {new Ajax.Request('http://www.example.com/cart_changed', {asynchronous:true, evalScripts:true})})\n//]]>\n</script>), | |
| 138 | + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {new Ajax.Request('http://www.example.com/cart_changed', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>), | |
| 139 | 139 | observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" }) |
| 140 | 140 | end |
| 141 | 141 | |
| ... | ... | @@ -170,23 +170,23 @@ class JavaScriptGeneratorTest < Test::Unit::TestCase |
| 170 | 170 | end |
| 171 | 171 | |
| 172 | 172 | def test_insert_html_with_string |
| 173 | - assert_equal 'new Insertion.Top("element", "<p>This is a test</p>");', | |
| 173 | + assert_equal 'new Insertion.Top("element", "\074p\076This is a test\074/p\076");', | |
| 174 | 174 | @generator.insert_html(:top, 'element', '<p>This is a test</p>') |
| 175 | - assert_equal 'new Insertion.Bottom("element", "<p>This is a test</p>");', | |
| 175 | + assert_equal 'new Insertion.Bottom("element", "\074p\076This is a test\074/p\076");', | |
| 176 | 176 | @generator.insert_html(:bottom, 'element', '<p>This is a test</p>') |
| 177 | - assert_equal 'new Insertion.Before("element", "<p>This is a test</p>");', | |
| 177 | + assert_equal 'new Insertion.Before("element", "\074p\076This is a test\074/p\076");', | |
| 178 | 178 | @generator.insert_html(:before, 'element', '<p>This is a test</p>') |
| 179 | - assert_equal 'new Insertion.After("element", "<p>This is a test</p>");', | |
| 179 | + assert_equal 'new Insertion.After("element", "\074p\076This is a test\074/p\076");', | |
| 180 | 180 | @generator.insert_html(:after, 'element', '<p>This is a test</p>') |
| 181 | 181 | end |
| 182 | 182 | |
| 183 | 183 | def test_replace_html_with_string |
| 184 | - assert_equal 'Element.update("element", "<p>This is a test</p>");', | |
| 184 | + assert_equal 'Element.update("element", "\074p\076This is a test\074/p\076");', | |
| 185 | 185 | @generator.replace_html('element', '<p>This is a test</p>') |
| 186 | 186 | end |
| 187 | 187 | |
| 188 | 188 | def test_replace_element_with_string |
| 189 | - assert_equal 'Element.replace("element", "<div id=\"element\"><p>This is a test</p></div>");', | |
| 189 | + assert_equal 'Element.replace("element", "\074div id=\"element\"\076\074p\076This is a test\074/p\076\074/div\076");', | |
| 190 | 190 | @generator.replace('element', '<div id="element"><p>This is a test</p></div>') |
| 191 | 191 | end |
| 192 | 192 | |
| ... | ... | @@ -241,12 +241,12 @@ class JavaScriptGeneratorTest < Test::Unit::TestCase |
| 241 | 241 | @generator.remove('foo', 'bar') |
| 242 | 242 | @generator.replace_html('baz', '<p>This is a test</p>') |
| 243 | 243 | |
| 244 | - assert_equal <<-EOS.chomp, @generator.to_s | |
| 245 | -new Insertion.Top("element", "<p>This is a test</p>"); | |
| 246 | -new Insertion.Bottom("element", "<p>This is a test</p>"); | |
| 244 | + expected = %q(new Insertion.Top("element", "\074p\076This is a test\074/p\076"); | |
| 245 | +new Insertion.Bottom("element", "\074p\076This is a test\074/p\076"); | |
| 247 | 246 | ["foo", "bar"].each(Element.remove); |
| 248 | -Element.update("baz", "<p>This is a test</p>"); | |
| 249 | - EOS | |
| 247 | +Element.update("baz", "\074p\076This is a test\074/p\076");) | |
| 248 | + | |
| 249 | + assert_equal expected, @generator.to_s | |
| 250 | 250 | end |
| 251 | 251 | |
| 252 | 252 | def test_element_access | ... | ... |
vendor/rails/actionwebservice/CHANGELOG
| 1 | +*1.2.6* (November 24th, 2007) | |
| 2 | + | |
| 3 | +* Depend on Action Pack 1.13.6 | |
| 4 | + | |
| 5 | +* Depend on Active Record 1.15.6 | |
| 6 | + | |
| 7 | + | |
| 8 | +*1.2.5* (October 12th, 2007) | |
| 9 | + | |
| 10 | +* Depend on Action Pack 1.13.5 | |
| 11 | + | |
| 12 | +* Depend on Active Record 1.15.5 | |
| 13 | + | |
| 14 | + | |
| 15 | +*1.2.4* (October 4th, 2007) | |
| 16 | + | |
| 17 | +* Depend on Action Pack 1.13.4 | |
| 18 | + | |
| 19 | +* Depend on Active Record 1.15.4 | |
| 20 | + | |
| 21 | + | |
| 1 | 22 | *1.2.3* (March 12th, 2007) |
| 2 | 23 | |
| 3 | 24 | * Depend on Action Pack 1.13.3 | ... | ... |
vendor/rails/actionwebservice/Rakefile
| ... | ... | @@ -71,8 +71,8 @@ spec = Gem::Specification.new do |s| |
| 71 | 71 | s.rubyforge_project = "aws" |
| 72 | 72 | s.homepage = "http://www.rubyonrails.org" |
| 73 | 73 | |
| 74 | - s.add_dependency('actionpack', '= 1.13.3' + PKG_BUILD) | |
| 75 | - s.add_dependency('activerecord', '= 1.15.3' + PKG_BUILD) | |
| 74 | + s.add_dependency('actionpack', '= 1.13.6' + PKG_BUILD) | |
| 75 | + s.add_dependency('activerecord', '= 1.15.6' + PKG_BUILD) | |
| 76 | 76 | |
| 77 | 77 | s.has_rdoc = true |
| 78 | 78 | s.requirements << 'none' | ... | ... |
vendor/rails/actionwebservice/lib/action_web_service/version.rb
vendor/rails/activerecord/CHANGELOG
| 1 | +*1.15.6* (November 24th, 2007) | |
| 2 | + | |
| 3 | +* Allow association redefinition in subclasses. #9346 [wildchild] | |
| 4 | + | |
| 5 | +* Fix has_many :through delete with custom foreign keys. #6466 [naffis] | |
| 6 | + | |
| 7 | +* Fix regression where the association would not construct new finder SQL on save causing bogus queries for "WHERE owner_id = NULL" even after owner was saved. #8713 [Bryan Helmkamp] | |
| 8 | + | |
| 9 | + | |
| 10 | +*1.15.5* (October 12th, 2007) | |
| 11 | + | |
| 12 | +* Depend on Action Pack 1.4.4 | |
| 13 | + | |
| 14 | + | |
| 15 | +*1.15.4* (October 4th, 2007) | |
| 16 | + | |
| 17 | +* Fix #count on a has_many :through association so that it recognizes the :uniq option. Closes #8801 [lifofifo] | |
| 18 | + | |
| 19 | +* Don't clobber includes passed to has_many.count [danger] | |
| 20 | + | |
| 21 | +* Make sure has_many uses :include when counting [danger] | |
| 22 | + | |
| 23 | +* Save associated records only if the association is already loaded. #8713 [blaine] | |
| 24 | + | |
| 25 | +* Changing the :default Date format doesn't break date quoting. #6312 [bshand, Elias] | |
| 26 | + | |
| 27 | +* Allow nil serialized attributes with a set class constraint. #7293 [sandofsky] | |
| 28 | + | |
| 29 | +* belongs_to assignment creates a new proxy rather than modifying its target in-place. #8412 [mmangino@elevatedrails.com] | |
| 30 | + | |
| 31 | +* Fix column type detection while loading fixtures. Closes #7987 [roderickvd] | |
| 32 | + | |
| 33 | +* Document deep eager includes. #6267 [Josh Susser, Dan Manges] | |
| 34 | + | |
| 35 | +* Oracle: extract column length for CHAR also. #7866 [ymendel] | |
| 36 | + | |
| 37 | +* Small additions and fixes for ActiveRecord documentation. Closes #7342 [jeremymcanally] | |
| 38 | + | |
| 39 | +* SQLite: binary escaping works with $KCODE='u'. #7862 [tsuka] | |
| 40 | + | |
| 41 | +* Improved cloning performance by relying less on exception raising #8159 [Blaine] | |
| 42 | + | |
| 43 | + | |
| 1 | 44 | *1.15.3* (March 12th, 2007) |
| 2 | 45 | |
| 3 | 46 | * Allow a polymorphic :source for has_many :through associations. Closes #7143 [protocool] | ... | ... |
vendor/rails/activerecord/Rakefile
| ... | ... | @@ -151,7 +151,7 @@ spec = Gem::Specification.new do |s| |
| 151 | 151 | s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) } |
| 152 | 152 | end |
| 153 | 153 | |
| 154 | - s.add_dependency('activesupport', '= 1.4.2' + PKG_BUILD) | |
| 154 | + s.add_dependency('activesupport', '= 1.4.4' + PKG_BUILD) | |
| 155 | 155 | |
| 156 | 156 | s.files.delete "test/fixtures/fixture_database.sqlite" |
| 157 | 157 | s.files.delete "test/fixtures/fixture_database_2.sqlite" | ... | ... |
vendor/rails/activerecord/lib/active_record/acts/list.rb
| ... | ... | @@ -63,7 +63,7 @@ module ActiveRecord |
| 63 | 63 | |
| 64 | 64 | #{scope_condition_method} |
| 65 | 65 | |
| 66 | - after_destroy :remove_from_list | |
| 66 | + before_destroy :remove_from_list | |
| 67 | 67 | before_create :add_to_list_bottom |
| 68 | 68 | EOV |
| 69 | 69 | end |
| ... | ... | @@ -74,6 +74,7 @@ module ActiveRecord |
| 74 | 74 | # lower in the list of all chapters. Likewise, <tt>chapter.first?</tt> would return true if that chapter is |
| 75 | 75 | # the first in the list of all chapters. |
| 76 | 76 | module InstanceMethods |
| 77 | + # Insert the item at the given position (defaults to the top position of 1). | |
| 77 | 78 | def insert_at(position = 1) |
| 78 | 79 | insert_at_position(position) |
| 79 | 80 | end |
| ... | ... | @@ -118,8 +119,12 @@ module ActiveRecord |
| 118 | 119 | end |
| 119 | 120 | end |
| 120 | 121 | |
| 122 | + # Removes the item from the list. | |
| 121 | 123 | def remove_from_list |
| 122 | - decrement_positions_on_lower_items if in_list? | |
| 124 | + if in_list? | |
| 125 | + decrement_positions_on_lower_items | |
| 126 | + update_attribute position_column, nil | |
| 127 | + end | |
| 123 | 128 | end |
| 124 | 129 | |
| 125 | 130 | # Increase the position of this item without adjusting the rest of the list. |
| ... | ... | @@ -162,6 +167,7 @@ module ActiveRecord |
| 162 | 167 | ) |
| 163 | 168 | end |
| 164 | 169 | |
| 170 | + # Test if this record is in a list | |
| 165 | 171 | def in_list? |
| 166 | 172 | !send(position_column).nil? |
| 167 | 173 | end |
| ... | ... | @@ -178,21 +184,26 @@ module ActiveRecord |
| 178 | 184 | # Overwrite this method to define the scope of the list changes |
| 179 | 185 | def scope_condition() "1" end |
| 180 | 186 | |
| 187 | + # Returns the bottom position number in the list. | |
| 188 | + # bottom_position_in_list # => 2 | |
| 181 | 189 | def bottom_position_in_list(except = nil) |
| 182 | 190 | item = bottom_item(except) |
| 183 | 191 | item ? item.send(position_column) : 0 |
| 184 | 192 | end |
| 185 | 193 | |
| 194 | + # Returns the bottom item | |
| 186 | 195 | def bottom_item(except = nil) |
| 187 | 196 | conditions = scope_condition |
| 188 | 197 | conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except |
| 189 | 198 | acts_as_list_class.find(:first, :conditions => conditions, :order => "#{position_column} DESC") |
| 190 | 199 | end |
| 191 | 200 | |
| 201 | + # Forces item to assume the bottom position in the list. | |
| 192 | 202 | def assume_bottom_position |
| 193 | 203 | update_attribute(position_column, bottom_position_in_list(self).to_i + 1) |
| 194 | 204 | end |
| 195 | 205 | |
| 206 | + # Forces item to assume the top position in the list. | |
| 196 | 207 | def assume_top_position |
| 197 | 208 | update_attribute(position_column, 1) |
| 198 | 209 | end |
| ... | ... | @@ -227,6 +238,7 @@ module ActiveRecord |
| 227 | 238 | ) |
| 228 | 239 | end |
| 229 | 240 | |
| 241 | + # Increments position (<tt>position_column</tt>) of all items in the list. | |
| 230 | 242 | def increment_positions_on_all_items |
| 231 | 243 | acts_as_list_class.update_all( |
| 232 | 244 | "#{position_column} = (#{position_column} + 1)", "#{scope_condition}" | ... | ... |
vendor/rails/activerecord/lib/active_record/acts/tree.rb
| ... | ... | @@ -70,16 +70,23 @@ module ActiveRecord |
| 70 | 70 | nodes |
| 71 | 71 | end |
| 72 | 72 | |
| 73 | + # Returns the root node of the tree. | |
| 73 | 74 | def root |
| 74 | 75 | node = self |
| 75 | 76 | node = node.parent while node.parent |
| 76 | 77 | node |
| 77 | 78 | end |
| 78 | 79 | |
| 80 | + # Returns all siblings of the current node. | |
| 81 | + # | |
| 82 | + # subchild1.siblings # => [subchild2] | |
| 79 | 83 | def siblings |
| 80 | 84 | self_and_siblings - [self] |
| 81 | 85 | end |
| 82 | 86 | |
| 87 | + # Returns all siblings and a reference to the current node. | |
| 88 | + # | |
| 89 | + # subchild1.self_and_siblings # => [subchild1, subchild2] | |
| 83 | 90 | def self_and_siblings |
| 84 | 91 | parent ? parent.children : self.class.roots |
| 85 | 92 | end | ... | ... |
vendor/rails/activerecord/lib/active_record/associations.rb
| ... | ... | @@ -50,6 +50,12 @@ module ActiveRecord |
| 50 | 50 | end |
| 51 | 51 | end |
| 52 | 52 | |
| 53 | + class HasManyThroughCantDissociateNewRecords < ActiveRecordError #:nodoc: | |
| 54 | + def initialize(owner, reflection) | |
| 55 | + super("Cannot dissociate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to delete the has_many :through record associating them.") | |
| 56 | + end | |
| 57 | + end | |
| 58 | + | |
| 53 | 59 | class EagerLoadPolymorphicError < ActiveRecordError #:nodoc: |
| 54 | 60 | def initialize(reflection) |
| 55 | 61 | super("Can not eagerly load the polymorphic association #{reflection.name.inspect}") |
| ... | ... | @@ -352,7 +358,15 @@ module ActiveRecord |
| 352 | 358 | # for post in Post.find(:all, :include => [ :author, :comments ]) |
| 353 | 359 | # |
| 354 | 360 | # That'll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we'll be down to 1 query. |
| 355 | - # But that shouldn't fool you to think that you can pull out huge amounts of data with no performance penalty just because you've reduced | |
| 361 | + # | |
| 362 | + # To include a deep hierarchy of associations, using a hash: | |
| 363 | + # | |
| 364 | + # for post in Post.find(:all, :include => [ :author, { :comments => { :author => :gravatar } } ]) | |
| 365 | + # | |
| 366 | + # That'll grab not only all the comments but all their authors and gravatar pictures. You can mix and match | |
| 367 | + # symbols, arrays and hashes in any combination to describe the associations you want to load. | |
| 368 | + # | |
| 369 | + # All of this power shouldn't fool you into thinking that you can pull out huge amounts of data with no performance penalty just because you've reduced | |
| 356 | 370 | # the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no |
| 357 | 371 | # catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above. |
| 358 | 372 | # |
| ... | ... | @@ -734,6 +748,7 @@ module ActiveRecord |
| 734 | 748 | deprecated_association_comparison_method(reflection.name, reflection.class_name) |
| 735 | 749 | end |
| 736 | 750 | |
| 751 | + # Create the callbacks to update counter cache | |
| 737 | 752 | if options[:counter_cache] |
| 738 | 753 | cache_column = options[:counter_cache] == true ? |
| 739 | 754 | "#{self.to_s.underscore.pluralize}_count" : |
| ... | ... | @@ -853,7 +868,7 @@ module ActiveRecord |
| 853 | 868 | # Don't use a before_destroy callback since users' before_destroy |
| 854 | 869 | # callbacks will be executed after the association is wiped out. |
| 855 | 870 | old_method = "destroy_without_habtm_shim_for_#{reflection.name}" |
| 856 | - class_eval <<-end_eval | |
| 871 | + class_eval <<-end_eval unless method_defined?(old_method) | |
| 857 | 872 | alias_method :#{old_method}, :destroy_without_callbacks |
| 858 | 873 | def destroy_without_callbacks |
| 859 | 874 | #{reflection.name}.clear |
| ... | ... | @@ -871,6 +886,12 @@ module ActiveRecord |
| 871 | 886 | end |
| 872 | 887 | |
| 873 | 888 | private |
| 889 | + # Generate a join table name from two provided tables names. | |
| 890 | + # The order of names in join name is determined by lexical precedence. | |
| 891 | + # join_table_name("members", "clubs") | |
| 892 | + # => "clubs_members" | |
| 893 | + # join_table_name("members", "special_clubs") | |
| 894 | + # => "members_special_clubs" | |
| 874 | 895 | def join_table_name(first_table_name, second_table_name) |
| 875 | 896 | if first_table_name < second_table_name |
| 876 | 897 | join_table = "#{first_table_name}_#{second_table_name}" |
| ... | ... | @@ -880,7 +901,7 @@ module ActiveRecord |
| 880 | 901 | |
| 881 | 902 | table_name_prefix + join_table + table_name_suffix |
| 882 | 903 | end |
| 883 | - | |
| 904 | + | |
| 884 | 905 | def association_accessor_methods(reflection, association_proxy_class) |
| 885 | 906 | define_method(reflection.name) do |*params| |
| 886 | 907 | force_reload = params.first unless params.empty? |
| ... | ... | @@ -901,7 +922,7 @@ module ActiveRecord |
| 901 | 922 | |
| 902 | 923 | define_method("#{reflection.name}=") do |new_value| |
| 903 | 924 | association = instance_variable_get("@#{reflection.name}") |
| 904 | - if association.nil? | |
| 925 | + if association.nil? || association.target != new_value | |
| 905 | 926 | association = association_proxy_class.new(self, reflection) |
| 906 | 927 | end |
| 907 | 928 | |
| ... | ... | @@ -911,10 +932,7 @@ module ActiveRecord |
| 911 | 932 | instance_variable_set("@#{reflection.name}", association) |
| 912 | 933 | else |
| 913 | 934 | instance_variable_set("@#{reflection.name}", nil) |
| 914 | - return nil | |
| 915 | 935 | end |
| 916 | - | |
| 917 | - association | |
| 918 | 936 | end |
| 919 | 937 | |
| 920 | 938 | define_method("set_#{reflection.name}_target") do |target| |
| ... | ... | @@ -981,18 +999,21 @@ module ActiveRecord |
| 981 | 999 | |
| 982 | 1000 | after_callback = <<-end_eval |
| 983 | 1001 | association = instance_variable_get("@#{association_name}") |
| 984 | - | |
| 985 | - if association.respond_to?(:loaded?) | |
| 986 | - if @new_record_before_save | |
| 987 | - records_to_save = association | |
| 988 | - else | |
| 989 | - records_to_save = association.select { |record| record.new_record? } | |
| 990 | - end | |
| 991 | - records_to_save.each { |record| association.send(:insert_record, record) } | |
| 992 | - association.send(:construct_sql) # reconstruct the SQL queries now that we know the owner's id | |
| 1002 | + | |
| 1003 | + records_to_save = if @new_record_before_save | |
| 1004 | + association | |
| 1005 | + elsif association.respond_to?(:loaded?) && association.loaded? | |
| 1006 | + association.select { |record| record.new_record? } | |
| 1007 | + else | |
| 1008 | + [] | |
| 993 | 1009 | end |
| 1010 | + | |
| 1011 | + records_to_save.each { |record| association.send(:insert_record, record) } unless records_to_save.blank? | |
| 1012 | + | |
| 1013 | + # reconstruct the SQL queries now that we know the owner's id | |
| 1014 | + association.send(:construct_sql) if association.respond_to?(:construct_sql) | |
| 994 | 1015 | end_eval |
| 995 | - | |
| 1016 | + | |
| 996 | 1017 | # Doesn't use after_save as that would save associations added in after_create/after_update twice |
| 997 | 1018 | after_create(after_callback) |
| 998 | 1019 | after_update(after_callback) |
| ... | ... | @@ -1271,7 +1292,9 @@ module ActiveRecord |
| 1271 | 1292 | defined_callbacks = options[callback_name.to_sym] |
| 1272 | 1293 | if options.has_key?(callback_name.to_sym) |
| 1273 | 1294 | class_inheritable_reader full_callback_name.to_sym |
| 1274 | - write_inheritable_array(full_callback_name.to_sym, [defined_callbacks].flatten) | |
| 1295 | + write_inheritable_attribute(full_callback_name.to_sym, [defined_callbacks].flatten) | |
| 1296 | + else | |
| 1297 | + write_inheritable_attribute(full_callback_name.to_sym, []) | |
| 1275 | 1298 | end |
| 1276 | 1299 | end |
| 1277 | 1300 | end | ... | ... |
vendor/rails/activerecord/lib/active_record/associations/association_collection.rb
| ... | ... | @@ -91,7 +91,11 @@ module ActiveRecord |
| 91 | 91 | attributes.collect { |attr| create(attr) } |
| 92 | 92 | else |
| 93 | 93 | record = build(attributes) |
| 94 | - record.save unless @owner.new_record? | |
| 94 | + if @owner.new_record? | |
| 95 | + ActiveSupport::Deprecation.warn("Calling .create on a has_many association without saving its owner will not work in rails 2.0, you probably want .build instead") | |
| 96 | + else | |
| 97 | + record.save | |
| 98 | + end | |
| 95 | 99 | record |
| 96 | 100 | end |
| 97 | 101 | end | ... | ... |
vendor/rails/activerecord/lib/active_record/associations/has_many_association.rb
| ... | ... | @@ -50,7 +50,7 @@ module ActiveRecord |
| 50 | 50 | options[:conditions] = options[:conditions].nil? ? |
| 51 | 51 | @finder_sql : |
| 52 | 52 | @finder_sql + " AND (#{sanitize_sql(options[:conditions])})" |
| 53 | - options[:include] = @reflection.options[:include] | |
| 53 | + options[:include] ||= @reflection.options[:include] | |
| 54 | 54 | |
| 55 | 55 | @reflection.klass.count(column_name, options) |
| 56 | 56 | end |
| ... | ... | @@ -138,7 +138,7 @@ module ActiveRecord |
| 138 | 138 | elsif @reflection.options[:counter_sql] |
| 139 | 139 | @reflection.klass.count_by_sql(@counter_sql) |
| 140 | 140 | else |
| 141 | - @reflection.klass.count(:conditions => @counter_sql) | |
| 141 | + @reflection.klass.count(:conditions => @counter_sql, :include => @reflection.options[:include]) | |
| 142 | 142 | end |
| 143 | 143 | |
| 144 | 144 | @target = [] and loaded if count == 0 | ... | ... |
vendor/rails/activerecord/lib/active_record/associations/has_many_through_association.rb
| ... | ... | @@ -71,20 +71,26 @@ module ActiveRecord |
| 71 | 71 | |
| 72 | 72 | # Remove +records+ from this association. Does not destroy +records+. |
| 73 | 73 | def delete(*records) |
| 74 | - records = flatten_deeper(records) | |
| 75 | - records.each { |associate| raise_on_type_mismatch(associate) } | |
| 76 | - records.reject! { |associate| @target.delete(associate) if associate.new_record? } | |
| 77 | 74 | return if records.empty? |
| 78 | - | |
| 79 | - @delete_join_finder ||= "find_all_by_#{@reflection.source_reflection.association_foreign_key}" | |
| 75 | + records.each { |associate| raise_on_type_mismatch(associate) } | |
| 76 | + | |
| 80 | 77 | through = @reflection.through_reflection |
| 81 | - through.klass.transaction do | |
| 82 | - records.each do |associate| | |
| 83 | - joins = @owner.send(through.name).send(@delete_join_finder, associate.id) | |
| 84 | - @owner.send(through.name).delete(joins) | |
| 78 | + raise ActiveRecord::HasManyThroughCantDissociateNewRecords.new(@owner, through) if @owner.new_record? | |
| 79 | + | |
| 80 | + load_target | |
| 81 | + | |
| 82 | + klass = through.klass | |
| 83 | + klass.transaction do | |
| 84 | + flatten_deeper(records).each do |associate| | |
| 85 | + raise_on_type_mismatch(associate) | |
| 86 | + raise ActiveRecord::HasManyThroughCantDissociateNewRecords.new(@owner, through) unless associate.respond_to?(:new_record?) && !associate.new_record? | |
| 87 | + | |
| 88 | + @owner.send(@reflection.through_reflection.name).proxy_target.delete(klass.delete_all(construct_join_attributes(associate))) | |
| 85 | 89 | @target.delete(associate) |
| 86 | 90 | end |
| 87 | 91 | end |
| 92 | + | |
| 93 | + self | |
| 88 | 94 | end |
| 89 | 95 | |
| 90 | 96 | def build(attrs = nil) |
| ... | ... | @@ -101,6 +107,16 @@ module ActiveRecord |
| 101 | 107 | def sum(*args, &block) |
| 102 | 108 | calculate(:sum, *args, &block) |
| 103 | 109 | end |
| 110 | + | |
| 111 | + def count(*args) | |
| 112 | + column_name, options = @reflection.klass.send(:construct_count_options_from_legacy_args, *args) | |
| 113 | + if @reflection.options[:uniq] | |
| 114 | + # This is needed becase 'SELECT count(DISTINCT *)..' is not valid sql statement. | |
| 115 | + column_name = "#{@reflection.klass.table_name}.#{@reflection.klass.primary_key}" if column_name == :all | |
| 116 | + options.merge!(:distinct => true) | |
| 117 | + end | |
| 118 | + @reflection.klass.send(:with_scope, construct_scope) { @reflection.klass.count(column_name, options) } | |
| 119 | + end | |
| 104 | 120 | |
| 105 | 121 | protected |
| 106 | 122 | def method_missing(method, *args, &block) | ... | ... |
vendor/rails/activerecord/lib/active_record/base.rb
| ... | ... | @@ -575,7 +575,7 @@ module ActiveRecord #:nodoc: |
| 575 | 575 | |
| 576 | 576 | # Specifies that the attribute by the name of +attr_name+ should be serialized before saving to the database and unserialized |
| 577 | 577 | # after loading from the database. The serialization is done through YAML. If +class_name+ is specified, the serialized |
| 578 | - # object must be of that class on retrieval or +SerializationTypeMismatch+ will be raised. | |
| 578 | + # object must be of that class on retrieval, or nil. Otherwise, +SerializationTypeMismatch+ will be raised. | |
| 579 | 579 | def serialize(attr_name, class_name = Object) |
| 580 | 580 | serialized_attributes[attr_name.to_s] = class_name |
| 581 | 581 | end |
| ... | ... | @@ -1188,6 +1188,9 @@ module ActiveRecord #:nodoc: |
| 1188 | 1188 | # |
| 1189 | 1189 | # It's even possible to use all the additional parameters to find. For example, the full interface for find_all_by_amount |
| 1190 | 1190 | # is actually find_all_by_amount(amount, options). |
| 1191 | + # | |
| 1192 | + # This also enables you to initialize a record if it is not found, such as find_or_initialize_by_amount(amount) | |
| 1193 | + # or find_or_create_by_user_and_password(user, password). | |
| 1191 | 1194 | def method_missing(method_id, *arguments) |
| 1192 | 1195 | if match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(method_id.to_s) |
| 1193 | 1196 | finder, deprecated_finder = determine_finder(match), determine_deprecated_finder(match) |
| ... | ... | @@ -1957,7 +1960,7 @@ module ActiveRecord #:nodoc: |
| 1957 | 1960 | def unserialize_attribute(attr_name) |
| 1958 | 1961 | unserialized_object = object_from_yaml(@attributes[attr_name]) |
| 1959 | 1962 | |
| 1960 | - if unserialized_object.is_a?(self.class.serialized_attributes[attr_name]) | |
| 1963 | + if unserialized_object.is_a?(self.class.serialized_attributes[attr_name]) || unserialized_object.nil? | |
| 1961 | 1964 | @attributes[attr_name] = unserialized_object |
| 1962 | 1965 | else |
| 1963 | 1966 | raise SerializationTypeMismatch, |
| ... | ... | @@ -2156,7 +2159,13 @@ module ActiveRecord #:nodoc: |
| 2156 | 2159 | |
| 2157 | 2160 | def clone_attribute_value(reader_method, attribute_name) |
| 2158 | 2161 | value = send(reader_method, attribute_name) |
| 2159 | - value.clone | |
| 2162 | + | |
| 2163 | + case value | |
| 2164 | + when nil, Fixnum, true, false | |
| 2165 | + value | |
| 2166 | + else | |
| 2167 | + value.clone | |
| 2168 | + end | |
| 2160 | 2169 | rescue TypeError, NoMethodError |
| 2161 | 2170 | value |
| 2162 | 2171 | end | ... | ... |
vendor/rails/activerecord/lib/active_record/calculations.rb
| ... | ... | @@ -242,8 +242,8 @@ module ActiveRecord |
| 242 | 242 | options.assert_valid_keys(CALCULATIONS_OPTIONS) |
| 243 | 243 | end |
| 244 | 244 | |
| 245 | - # converts a given key to the value that the database adapter returns as | |
| 246 | - # | |
| 245 | + # Converts a given key to the value that the database adapter returns as | |
| 246 | + # as a usable column name. | |
| 247 | 247 | # users.id #=> users_id |
| 248 | 248 | # sum(id) #=> sum_id |
| 249 | 249 | # count(distinct users.id) #=> count_distinct_users_id | ... | ... |
vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
| ... | ... | @@ -24,7 +24,7 @@ module ActiveRecord |
| 24 | 24 | when Float, Fixnum, Bignum then value.to_s |
| 25 | 25 | # BigDecimals need to be output in a non-normalized form and quoted. |
| 26 | 26 | when BigDecimal then value.to_s('F') |
| 27 | - when Date then "'#{value.to_s}'" | |
| 27 | + when Date then "'#{value.to_s(:db)}'" | |
| 28 | 28 | when Time, DateTime then "'#{quoted_date(value)}'" |
| 29 | 29 | else "'#{quote_string(value.to_yaml)}'" |
| 30 | 30 | end | ... | ... |
vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
| ... | ... | @@ -119,7 +119,7 @@ module ActiveRecord |
| 119 | 119 | # |
| 120 | 120 | # * <tt>:host</tt> -- Defaults to localhost |
| 121 | 121 | # * <tt>:port</tt> -- Defaults to 3306 |
| 122 | - # * <tt>:socket</tt> -- Defaults to /tmp/mysql.sock | |
| 122 | + # * <tt>:socket</tt> -- Defaults to /var/run/mysqld/mysqld.sock | |
| 123 | 123 | # * <tt>:username</tt> -- Defaults to root |
| 124 | 124 | # * <tt>:password</tt> -- Defaults to nothing |
| 125 | 125 | # * <tt>:database</tt> -- The name of the database. No default, must be provided. | ... | ... |
vendor/rails/activerecord/lib/active_record/connection_adapters/oracle_adapter.rb
| ... | ... | @@ -320,6 +320,7 @@ begin |
| 320 | 320 | decode(data_type, 'NUMBER', data_precision, |
| 321 | 321 | 'FLOAT', data_precision, |
| 322 | 322 | 'VARCHAR2', data_length, |
| 323 | + 'CHAR', data_length, | |
| 323 | 324 | null) as limit, |
| 324 | 325 | decode(data_type, 'NUMBER', data_scale, null) as scale |
| 325 | 326 | from all_tab_columns | ... | ... |
vendor/rails/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
| ... | ... | @@ -68,7 +68,7 @@ module ActiveRecord |
| 68 | 68 | class SQLiteColumn < Column #:nodoc: |
| 69 | 69 | class << self |
| 70 | 70 | def string_to_binary(value) |
| 71 | - value.gsub(/\0|\%/) do |b| | |
| 71 | + value.gsub(/\0|\%/n) do |b| | |
| 72 | 72 | case b |
| 73 | 73 | when "\0" then "%00" |
| 74 | 74 | when "%" then "%25" |
| ... | ... | @@ -77,7 +77,7 @@ module ActiveRecord |
| 77 | 77 | end |
| 78 | 78 | |
| 79 | 79 | def binary_to_string(value) |
| 80 | - value.gsub(/%00|%25/) do |b| | |
| 80 | + value.gsub(/%00|%25/n) do |b| | |
| 81 | 81 | case b |
| 82 | 82 | when "%00" then "\0" |
| 83 | 83 | when "%25" then "%" | ... | ... |
vendor/rails/activerecord/lib/active_record/deprecated_finders.rb
| 1 | 1 | module ActiveRecord |
| 2 | 2 | class Base |
| 3 | 3 | class << self |
| 4 | - # This method is deprecated in favor of find with the :conditions option. | |
| 4 | + # DEPRECATION NOTICE: This method is deprecated in favor of find with the :conditions option. | |
| 5 | 5 | # |
| 6 | 6 | # Works like find, but the record matching +id+ must also meet the +conditions+. |
| 7 | 7 | # +RecordNotFound+ is raised if no record can be found matching the +id+ or meeting the condition. |
| ... | ... | @@ -12,7 +12,7 @@ module ActiveRecord |
| 12 | 12 | end |
| 13 | 13 | deprecate :find_on_conditions => "use find(ids, :conditions => conditions)" |
| 14 | 14 | |
| 15 | - # This method is deprecated in favor of find(:first, options). | |
| 15 | + # DEPRECATION NOTICE: This method is deprecated in favor of find(:first, options). | |
| 16 | 16 | # |
| 17 | 17 | # Returns the object for the first record responding to the conditions in +conditions+, |
| 18 | 18 | # such as "group = 'master'". If more than one record is returned from the query, it's the first that'll |
| ... | ... | @@ -24,7 +24,7 @@ module ActiveRecord |
| 24 | 24 | end |
| 25 | 25 | deprecate :find_first => "use find(:first, ...)" |
| 26 | 26 | |
| 27 | - # This method is deprecated in favor of find(:all, options). | |
| 27 | + # DEPRECATION NOTICE: This method is deprecated in favor of find(:all, options). | |
| 28 | 28 | # |
| 29 | 29 | # Returns an array of all the objects that could be instantiated from the associated |
| 30 | 30 | # table in the database. The +conditions+ can be used to narrow the selection of objects (WHERE-part), | ... | ... |
vendor/rails/activerecord/lib/active_record/fixtures.rb
| ... | ... | @@ -412,7 +412,7 @@ class Fixture #:nodoc: |
| 412 | 412 | klass = @class_name.constantize rescue nil |
| 413 | 413 | |
| 414 | 414 | list = @fixture.inject([]) do |fixtures, (key, value)| |
| 415 | - col = klass.columns_hash[key] if klass.kind_of?(ActiveRecord::Base) | |
| 415 | + col = klass.columns_hash[key] if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base) | |
| 416 | 416 | fixtures << ActiveRecord::Base.connection.quote(value, col).gsub('[^\]\\n', "\n").gsub('[^\]\\r', "\r") |
| 417 | 417 | end |
| 418 | 418 | list * ', ' | ... | ... |
vendor/rails/activerecord/lib/active_record/timestamp.rb
| ... | ... | @@ -5,15 +5,6 @@ module ActiveRecord |
| 5 | 5 | # Timestamping can be turned off by setting |
| 6 | 6 | # <tt>ActiveRecord::Base.record_timestamps = false</tt> |
| 7 | 7 | # |
| 8 | - # Keep in mind that, via inheritance, you can turn off timestamps on a per | |
| 9 | - # model basis by setting <tt>record_timestamps</tt> to false in the desired | |
| 10 | - # models. | |
| 11 | - # | |
| 12 | - # class Feed < ActiveRecord::Base | |
| 13 | - # self.record_timestamps = false | |
| 14 | - # # ... | |
| 15 | - # end | |
| 16 | - # | |
| 17 | 8 | # Timestamps are in the local timezone by default but can use UTC by setting |
| 18 | 9 | # <tt>ActiveRecord::Base.default_timezone = :utc</tt> |
| 19 | 10 | module Timestamp | ... | ... |
vendor/rails/activerecord/lib/active_record/vendor/mysql.rb
vendor/rails/activerecord/lib/active_record/version.rb
vendor/rails/activerecord/test/aggregations_test.rb
| ... | ... | @@ -93,3 +93,21 @@ class AggregationsTest < Test::Unit::TestCase |
| 93 | 93 | assert_raises(NoMethodError) { customers(:david).balance = nil } |
| 94 | 94 | end |
| 95 | 95 | end |
| 96 | + | |
| 97 | +class OverridingAggregationsTest < Test::Unit::TestCase | |
| 98 | + class Name; end | |
| 99 | + class DifferentName; end | |
| 100 | + | |
| 101 | + class Person < ActiveRecord::Base | |
| 102 | + composed_of :composed_of, :mapping => %w(person_first_name first_name) | |
| 103 | + end | |
| 104 | + | |
| 105 | + class DifferentPerson < Person | |
| 106 | + composed_of :composed_of, :class_name => 'DifferentName', :mapping => %w(different_person_first_name first_name) | |
| 107 | + end | |
| 108 | + | |
| 109 | + def test_composed_of_aggregation_redefinition_reflections_should_differ_and_not_inherited | |
| 110 | + assert_not_equal Person.reflect_on_aggregation(:composed_of), | |
| 111 | + DifferentPerson.reflect_on_aggregation(:composed_of) | |
| 112 | + end | |
| 113 | +end | ... | ... |
vendor/rails/activerecord/test/associations/eager_test.rb
| ... | ... | @@ -168,6 +168,12 @@ class EagerAssociationTest < Test::Unit::TestCase |
| 168 | 168 | posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.title = 'magic forest'") |
| 169 | 169 | assert_equal 0, posts.size |
| 170 | 170 | end |
| 171 | + | |
| 172 | + def test_eager_count_performed_on_a_has_many_association_with_multi_table_conditional | |
| 173 | + author = authors(:david) | |
| 174 | + author_posts_without_comments = author.posts.select { |post| post.comments.blank? } | |
| 175 | + assert_equal author_posts_without_comments.size, author.posts.count(:all, :include => :comments, :conditions => 'comments.id is null') | |
| 176 | + end | |
| 171 | 177 | |
| 172 | 178 | def test_eager_with_has_and_belongs_to_many_and_limit |
| 173 | 179 | posts = Post.find(:all, :include => :categories, :order => "posts.id", :limit => 3) |
| ... | ... | @@ -271,6 +277,13 @@ class EagerAssociationTest < Test::Unit::TestCase |
| 271 | 277 | assert_not_nil f.account |
| 272 | 278 | assert_equal companies(:first_firm, :reload).account, f.account |
| 273 | 279 | end |
| 280 | + | |
| 281 | + def test_eager_with_multi_table_conditional_properly_counts_the_records_when_using_size | |
| 282 | + author = authors(:david) | |
| 283 | + posts_with_no_comments = author.posts.select { |post| post.comments.blank? } | |
| 284 | + assert_equal posts_with_no_comments.size, author.posts_with_no_comments.size | |
| 285 | + assert_equal posts_with_no_comments, author.posts_with_no_comments | |
| 286 | + end | |
| 274 | 287 | |
| 275 | 288 | def test_eager_with_invalid_association_reference |
| 276 | 289 | assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") { | ... | ... |
vendor/rails/activerecord/test/associations/join_model_test.rb
| ... | ... | @@ -8,10 +8,12 @@ require 'fixtures/category' |
| 8 | 8 | require 'fixtures/categorization' |
| 9 | 9 | require 'fixtures/vertex' |
| 10 | 10 | require 'fixtures/edge' |
| 11 | +require 'fixtures/book' | |
| 12 | +require 'fixtures/citation' | |
| 11 | 13 | |
| 12 | 14 | class AssociationsJoinModelTest < Test::Unit::TestCase |
| 13 | 15 | self.use_transactional_fixtures = false |
| 14 | - fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices | |
| 16 | + fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :books | |
| 15 | 17 | |
| 16 | 18 | def test_has_many |
| 17 | 19 | assert authors(:david).categories.include?(categories(:general)) |
| ... | ... | @@ -29,7 +31,16 @@ class AssociationsJoinModelTest < Test::Unit::TestCase |
| 29 | 31 | assert_equal 2, authors(:mary).categorized_posts.size |
| 30 | 32 | assert_equal 1, authors(:mary).unique_categorized_posts.size |
| 31 | 33 | end |
| 32 | - | |
| 34 | + | |
| 35 | + def test_has_many_uniq_through_count | |
| 36 | + author = authors(:mary) | |
| 37 | + assert !authors(:mary).unique_categorized_posts.loaded? | |
| 38 | + assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count } | |
| 39 | + assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title, {}) } | |
| 40 | + assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, { :conditions => "title is NULL" }) } | |
| 41 | + assert !authors(:mary).unique_categorized_posts.loaded? | |
| 42 | + end | |
| 43 | + | |
| 33 | 44 | def test_polymorphic_has_many |
| 34 | 45 | assert posts(:welcome).taggings.include?(taggings(:welcome_general)) |
| 35 | 46 | end |
| ... | ... | @@ -441,7 +452,21 @@ class AssociationsJoinModelTest < Test::Unit::TestCase |
| 441 | 452 | tags = posts(:thinking).tags |
| 442 | 453 | assert_equal tags, posts(:thinking).tags.push(tags(:general)) |
| 443 | 454 | end |
| 444 | - | |
| 455 | + | |
| 456 | + def test_delete_associate_when_deleting_from_has_many_through_with_non_standard_id | |
| 457 | + count = books(:awdr).references.count | |
| 458 | + references_before = books(:awdr).references | |
| 459 | + book = Book.create!(:name => 'Getting Real') | |
| 460 | + book_awdr = books(:awdr) | |
| 461 | + book_awdr.references << book | |
| 462 | + assert_equal(count + 1, book_awdr.references(true).size) | |
| 463 | + | |
| 464 | + assert_nothing_raised { book_awdr.references.delete(book) } | |
| 465 | + assert_equal(count, book_awdr.references.size) | |
| 466 | + assert_equal(count, book_awdr.references(true).size) | |
| 467 | + assert_equal(references_before.sort, book_awdr.references.sort) | |
| 468 | + end | |
| 469 | + | |
| 445 | 470 | def test_delete_associate_when_deleting_from_has_many_through |
| 446 | 471 | count = posts(:thinking).tags.count |
| 447 | 472 | tags_before = posts(:thinking).tags | ... | ... |
vendor/rails/activerecord/test/associations_test.rb
| ... | ... | @@ -10,6 +10,8 @@ require 'fixtures/order' |
| 10 | 10 | require 'fixtures/category' |
| 11 | 11 | require 'fixtures/post' |
| 12 | 12 | require 'fixtures/author' |
| 13 | +require 'fixtures/person' | |
| 14 | +require 'fixtures/reader' | |
| 13 | 15 | |
| 14 | 16 | |
| 15 | 17 | class AssociationsTest < Test::Unit::TestCase |
| ... | ... | @@ -21,6 +23,14 @@ class AssociationsTest < Test::Unit::TestCase |
| 21 | 23 | Class.new(ActiveRecord::Base).has_many(:wheels, :name => 'wheels') |
| 22 | 24 | end |
| 23 | 25 | end |
| 26 | + | |
| 27 | + def test_should_construct_new_finder_sql_after_create | |
| 28 | + person = Person.new | |
| 29 | + assert_equal [], person.readers.find(:all) | |
| 30 | + person.save! | |
| 31 | + reader = Reader.create! :person => person, :post => Post.new(:title => "foo", :body => "bar") | |
| 32 | + assert_equal [reader], person.readers.find(:all) | |
| 33 | + end | |
| 24 | 34 | |
| 25 | 35 | def test_force_reload |
| 26 | 36 | firm = Firm.new("name" => "A New Firm, Inc") |
| ... | ... | @@ -67,8 +77,8 @@ class AssociationsTest < Test::Unit::TestCase |
| 67 | 77 | end |
| 68 | 78 | |
| 69 | 79 | class AssociationProxyTest < Test::Unit::TestCase |
| 70 | - fixtures :authors, :posts | |
| 71 | - | |
| 80 | + fixtures :authors, :posts, :developers, :projects, :developers_projects | |
| 81 | + | |
| 72 | 82 | def test_proxy_accessors |
| 73 | 83 | welcome = posts(:welcome) |
| 74 | 84 | assert_equal welcome, welcome.author.proxy_owner |
| ... | ... | @@ -87,6 +97,19 @@ class AssociationProxyTest < Test::Unit::TestCase |
| 87 | 97 | david.posts_with_extension.first # force load target |
| 88 | 98 | assert_equal david.posts_with_extension, david.posts_with_extension.testing_proxy_target |
| 89 | 99 | end |
| 100 | + | |
| 101 | + def test_save_on_parent_does_not_load_target | |
| 102 | + david = developers(:david) | |
| 103 | + | |
| 104 | + assert !david.projects.loaded? | |
| 105 | + david.update_attribute(:created_at, Time.now) | |
| 106 | + assert !david.projects.loaded? | |
| 107 | + end | |
| 108 | + | |
| 109 | + def test_save_on_parent_saves_children | |
| 110 | + developer = Developer.create :name => "Bryan", :salary => 50_000 | |
| 111 | + assert_equal 1, developer.reload.audit_logs.size | |
| 112 | + end | |
| 90 | 113 | end |
| 91 | 114 | |
| 92 | 115 | class HasOneAssociationsTest < Test::Unit::TestCase |
| ... | ... | @@ -583,6 +606,13 @@ class HasManyAssociationsTest < Test::Unit::TestCase |
| 583 | 606 | assert_equal 3, first_firm.plain_clients.size |
| 584 | 607 | end |
| 585 | 608 | |
| 609 | + def test_regular_create_on_has_many_when_parent_is_new_raises | |
| 610 | + assert_deprecated(/.build instead/) do | |
| 611 | + firm = Firm.new | |
| 612 | + firm.plain_clients.create :name=>"Whoever" | |
| 613 | + end | |
| 614 | + end | |
| 615 | + | |
| 586 | 616 | def test_adding_a_mismatch_class |
| 587 | 617 | assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil } |
| 588 | 618 | assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << 1 } |
| ... | ... | @@ -1007,7 +1037,20 @@ class BelongsToAssociationsTest < Test::Unit::TestCase |
| 1007 | 1037 | citibank.firm = apple |
| 1008 | 1038 | assert_equal apple.id, citibank.firm_id |
| 1009 | 1039 | end |
| 1010 | - | |
| 1040 | + | |
| 1041 | + def test_no_unexpected_aliasing | |
| 1042 | + first_firm = companies(:first_firm) | |
| 1043 | + another_firm = companies(:another_firm) | |
| 1044 | + | |
| 1045 | + citibank = Account.create("credit_limit" => 10) | |
| 1046 | + citibank.firm = first_firm | |
| 1047 | + original_proxy = citibank.firm | |
| 1048 | + citibank.firm = another_firm | |
| 1049 | + | |
| 1050 | + assert_equal first_firm.object_id, original_proxy.object_id | |
| 1051 | + assert_equal another_firm.object_id, citibank.firm.object_id | |
| 1052 | + end | |
| 1053 | + | |
| 1011 | 1054 | def test_creating_the_belonging_object |
| 1012 | 1055 | citibank = Account.create("credit_limit" => 10) |
| 1013 | 1056 | apple = citibank.create_firm("name" => "Apple") |
| ... | ... | @@ -1807,3 +1850,68 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase |
| 1807 | 1850 | assert_equal %w(1 2), projects.scan(/\d/).sort |
| 1808 | 1851 | end |
| 1809 | 1852 | end |
| 1853 | + | |
| 1854 | + | |
| 1855 | +class OverridingAssociationsTest < Test::Unit::TestCase | |
| 1856 | + class Person < ActiveRecord::Base; end | |
| 1857 | + class DifferentPerson < ActiveRecord::Base; end | |
| 1858 | + | |
| 1859 | + class PeopleList < ActiveRecord::Base | |
| 1860 | + has_and_belongs_to_many :has_and_belongs_to_many, :before_add => :enlist | |
| 1861 | + has_many :has_many, :before_add => :enlist | |
| 1862 | + belongs_to :belongs_to | |
| 1863 | + has_one :has_one | |
| 1864 | + end | |
| 1865 | + | |
| 1866 | + class DifferentPeopleList < PeopleList | |
| 1867 | + # Different association with the same name, callbacks should be omitted here. | |
| 1868 | + has_and_belongs_to_many :has_and_belongs_to_many, :class_name => 'DifferentPerson' | |
| 1869 | + has_many :has_many, :class_name => 'DifferentPerson' | |
| 1870 | + belongs_to :belongs_to, :class_name => 'DifferentPerson', :foreign_key => 'belongs_to_id' | |
| 1871 | + has_one :has_one, :class_name => 'DifferentPerson' | |
| 1872 | + end | |
| 1873 | + | |
| 1874 | + def test_habtm_association_redefinition_callbacks_should_differ_and_not_inherited | |
| 1875 | + # redeclared association on AR descendant should not inherit callbacks from superclass | |
| 1876 | + callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many) | |
| 1877 | + assert_equal([:enlist], callbacks) | |
| 1878 | + callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many) | |
| 1879 | + assert_equal([], callbacks) | |
| 1880 | + end | |
| 1881 | + | |
| 1882 | + def test_has_many_association_redefinition_callbacks_should_differ_and_not_inherited | |
| 1883 | + # redeclared association on AR descendant should not inherit callbacks from superclass | |
| 1884 | + callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_many) | |
| 1885 | + assert_equal([:enlist], callbacks) | |
| 1886 | + callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_many) | |
| 1887 | + assert_equal([], callbacks) | |
| 1888 | + end | |
| 1889 | + | |
| 1890 | + def test_habtm_association_redefinition_reflections_should_differ_and_not_inherited | |
| 1891 | + assert_not_equal( | |
| 1892 | + PeopleList.reflect_on_association(:has_and_belongs_to_many), | |
| 1893 | + DifferentPeopleList.reflect_on_association(:has_and_belongs_to_many) | |
| 1894 | + ) | |
| 1895 | + end | |
| 1896 | + | |
| 1897 | + def test_has_many_association_redefinition_reflections_should_differ_and_not_inherited | |
| 1898 | + assert_not_equal( | |
| 1899 | + PeopleList.reflect_on_association(:has_many), | |
| 1900 | + DifferentPeopleList.reflect_on_association(:has_many) | |
| 1901 | + ) | |
| 1902 | + end | |
| 1903 | + | |
| 1904 | + def test_belongs_to_association_redefinition_reflections_should_differ_and_not_inherited | |
| 1905 | + assert_not_equal( | |
| 1906 | + PeopleList.reflect_on_association(:belongs_to), | |
| 1907 | + DifferentPeopleList.reflect_on_association(:belongs_to) | |
| 1908 | + ) | |
| 1909 | + end | |
| 1910 | + | |
| 1911 | + def test_has_one_association_redefinition_reflections_should_differ_and_not_inherited | |
| 1912 | + assert_not_equal( | |
| 1913 | + PeopleList.reflect_on_association(:has_one), | |
| 1914 | + DifferentPeopleList.reflect_on_association(:has_one) | |
| 1915 | + ) | |
| 1916 | + end | |
| 1917 | +end | ... | ... |
vendor/rails/activerecord/test/base_test.rb
| ... | ... | @@ -1086,16 +1086,29 @@ class BasicsTest < Test::Unit::TestCase |
| 1086 | 1086 | assert_equal(myobj, topic.content) |
| 1087 | 1087 | end |
| 1088 | 1088 | |
| 1089 | - def test_serialized_attribute_with_class_constraint | |
| 1089 | + def test_nil_serialized_attribute_with_class_constraint | |
| 1090 | 1090 | myobj = MyObject.new('value1', 'value2') |
| 1091 | - topic = Topic.create("content" => myobj) | |
| 1092 | - Topic.serialize(:content, Hash) | |
| 1091 | + topic = Topic.new | |
| 1092 | + assert_nil topic.content | |
| 1093 | + end | |
| 1093 | 1094 | |
| 1095 | + def test_should_raise_exception_on_serialized_attribute_with_type_mismatch | |
| 1096 | + myobj = MyObject.new('value1', 'value2') | |
| 1097 | + topic = Topic.new(:content => myobj) | |
| 1098 | + assert topic.save | |
| 1099 | + Topic.serialize(:content, Hash) | |
| 1094 | 1100 | assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content } |
| 1101 | + ensure | |
| 1102 | + Topic.serialize(:content) | |
| 1103 | + end | |
| 1095 | 1104 | |
| 1105 | + def test_serialized_attribute_with_class_constraint | |
| 1096 | 1106 | settings = { "color" => "blue" } |
| 1097 | - Topic.find(topic.id).update_attribute("content", settings) | |
| 1107 | + Topic.serialize(:content, Hash) | |
| 1108 | + topic = Topic.new(:content => settings) | |
| 1109 | + assert topic.save | |
| 1098 | 1110 | assert_equal(settings, Topic.find(topic.id).content) |
| 1111 | + ensure | |
| 1099 | 1112 | Topic.serialize(:content) |
| 1100 | 1113 | end |
| 1101 | 1114 | ... | ... |
vendor/rails/activerecord/test/fixtures/author.rb
| ... | ... | @@ -25,6 +25,7 @@ class Author < ActiveRecord::Base |
| 25 | 25 | |
| 26 | 26 | has_many :hello_posts, :class_name => "Post", :conditions => "posts.body = 'hello'" |
| 27 | 27 | has_many :hello_post_comments, :through => :hello_posts, :source => :comments |
| 28 | + has_many :posts_with_no_comments, :class_name => 'Post', :conditions => 'comments.id is null', :include => :comments | |
| 28 | 29 | |
| 29 | 30 | has_many :other_posts, :class_name => "Post" |
| 30 | 31 | has_many :posts_with_callbacks, :class_name => "Post", :before_add => :log_before_adding, | ... | ... |
| ... | ... | @@ -0,0 +1,437 @@ |
| 1 | +flowers: | |
| 2 | + id: 1 | |
| 3 | + data: !binary | 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 | |
| 436 | + KKpVChRRRQAUUUUAFFFFABRRRQAUUUUAf//Z | |
| 437 | + | ... | ... |
| ... | ... | @@ -0,0 +1,6 @@ |
| 1 | +class Citation < ActiveRecord::Base | |
| 2 | + belongs_to :reference_of, :class_name => "Book", :foreign_key => :book2_id | |
| 3 | + | |
| 4 | + belongs_to :book1, :class_name => "Book", :foreign_key => :book1_id | |
| 5 | + belongs_to :book2, :class_name => "Book", :foreign_key => :book2_id | |
| 6 | +end | ... | ... |
vendor/rails/activerecord/test/fixtures/db_definitions/schema.rb
| ... | ... | @@ -57,4 +57,18 @@ ActiveRecord::Schema.define do |
| 57 | 57 | create_table :lock_without_defaults_cust, :force => true do |t| |
| 58 | 58 | t.column :custom_lock_version, :integer |
| 59 | 59 | end |
| 60 | + | |
| 61 | + create_table :audit_logs, :force => true do |t| | |
| 62 | + t.column :message, :string, :null=>false | |
| 63 | + t.column :developer_id, :integer, :null=>false | |
| 64 | + end | |
| 65 | + | |
| 66 | + create_table :books, :force => true do |t| | |
| 67 | + t.column :name, :string | |
| 68 | + end | |
| 69 | + | |
| 70 | + create_table :citations, :force => true do |t| | |
| 71 | + t.column :book1_id, :integer | |
| 72 | + t.column :book2_id, :integer | |
| 73 | + end | |
| 60 | 74 | end | ... | ... |
vendor/rails/activerecord/test/fixtures/developer.rb
| ... | ... | @@ -31,8 +31,18 @@ class Developer < ActiveRecord::Base |
| 31 | 31 | |
| 32 | 32 | has_and_belongs_to_many :special_projects, :join_table => 'developers_projects', :association_foreign_key => 'project_id' |
| 33 | 33 | |
| 34 | + has_many :audit_logs | |
| 35 | + | |
| 34 | 36 | validates_inclusion_of :salary, :in => 50000..200000 |
| 35 | 37 | validates_length_of :name, :within => 3..20 |
| 38 | + | |
| 39 | + before_create do |developer| | |
| 40 | + developer.audit_logs.build :message => "Computer created" | |
| 41 | + end | |
| 42 | +end | |
| 43 | + | |
| 44 | +class AuditLog < ActiveRecord::Base | |
| 45 | + belongs_to :developer | |
| 36 | 46 | end |
| 37 | 47 | |
| 38 | 48 | DeveloperSalary = Struct.new(:amount) | ... | ... |
vendor/rails/activerecord/test/fixtures_test.rb
| ... | ... | @@ -12,13 +12,15 @@ class FixturesTest < Test::Unit::TestCase |
| 12 | 12 | self.use_instantiated_fixtures = true |
| 13 | 13 | self.use_transactional_fixtures = false |
| 14 | 14 | |
| 15 | - fixtures :topics, :developers, :accounts, :tasks, :categories, :funny_jokes | |
| 15 | + fixtures :topics, :developers, :accounts, :tasks, :categories, :funny_jokes, :binaries | |
| 16 | 16 | |
| 17 | - FIXTURES = %w( accounts companies customers | |
| 17 | + FIXTURES = %w( accounts binaries companies customers | |
| 18 | 18 | developers developers_projects entrants |
| 19 | 19 | movies projects subscribers topics tasks ) |
| 20 | 20 | MATCH_ATTRIBUTE_NAME = /[a-zA-Z][-_\w]*/ |
| 21 | 21 | |
| 22 | + BINARY_FIXTURE_PATH = File.dirname(__FILE__) + '/fixtures/flowers.jpg' | |
| 23 | + | |
| 22 | 24 | def test_clean_fixtures |
| 23 | 25 | FIXTURES.each do |name| |
| 24 | 26 | fixtures = nil |
| ... | ... | @@ -100,7 +102,6 @@ class FixturesTest < Test::Unit::TestCase |
| 100 | 102 | assert first |
| 101 | 103 | end |
| 102 | 104 | |
| 103 | - | |
| 104 | 105 | def test_bad_format |
| 105 | 106 | path = File.join(File.dirname(__FILE__), 'fixtures', 'bad_fixtures') |
| 106 | 107 | Dir.entries(path).each do |file| |
| ... | ... | @@ -174,7 +175,6 @@ class FixturesTest < Test::Unit::TestCase |
| 174 | 175 | end |
| 175 | 176 | end |
| 176 | 177 | |
| 177 | - | |
| 178 | 178 | def test_yml_file_in_subdirectory |
| 179 | 179 | assert_equal(categories(:sub_special_1).name, "A special category in a subdir file") |
| 180 | 180 | assert_equal(categories(:sub_special_1).class, SpecialCategory) |
| ... | ... | @@ -185,7 +185,11 @@ class FixturesTest < Test::Unit::TestCase |
| 185 | 185 | assert_equal(categories(:sub_special_3).class, SpecialCategory) |
| 186 | 186 | end |
| 187 | 187 | |
| 188 | - | |
| 188 | + def test_binary_in_fixtures | |
| 189 | + assert_equal 1, @binaries.size | |
| 190 | + data = File.read(BINARY_FIXTURE_PATH).freeze | |
| 191 | + assert_equal data, @flowers.data | |
| 192 | + end | |
| 189 | 193 | end |
| 190 | 194 | |
| 191 | 195 | if Account.connection.respond_to?(:reset_pk_sequence!) | ... | ... |
vendor/rails/activerecord/test/migration_test.rb
| ... | ... | @@ -170,7 +170,7 @@ if ActiveRecord::Base.connection.supports_migrations? |
| 170 | 170 | # SQL Server and Sybase will not allow you to add a NOT NULL column |
| 171 | 171 | # to a table without specifying a default value, so the |
| 172 | 172 | # following test must be skipped |
| 173 | - unless current_adapter?(:SQLServerAdapter, :SybaseAdapter) | |
| 173 | + unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :SQLiteAdapter) | |
| 174 | 174 | def test_add_column_not_null_without_default |
| 175 | 175 | Person.connection.create_table :testings do |t| |
| 176 | 176 | t.column :foo, :string |
| ... | ... | @@ -209,7 +209,7 @@ if ActiveRecord::Base.connection.supports_migrations? |
| 209 | 209 | def test_native_decimal_insert_manual_vs_automatic |
| 210 | 210 | # SQLite3 always uses float in violation of SQL |
| 211 | 211 | # 16 decimal places |
| 212 | - correct_value = (current_adapter?(:SQLiteAdapter) ? '0.123456789012346E20' : '0012345678901234567890.0123456789').to_d | |
| 212 | + correct_value = '0012345678901234567890.0123456789'.to_d | |
| 213 | 213 | |
| 214 | 214 | Person.delete_all |
| 215 | 215 | Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10' |
| ... | ... | @@ -227,8 +227,9 @@ if ActiveRecord::Base.connection.supports_migrations? |
| 227 | 227 | assert_kind_of BigDecimal, row.wealth |
| 228 | 228 | |
| 229 | 229 | # If this assert fails, that means the SELECT is broken! |
| 230 | - assert_equal correct_value, row.wealth | |
| 231 | - | |
| 230 | + unless current_adapter?(:SQLite3Adapter) | |
| 231 | + assert_equal correct_value, row.wealth | |
| 232 | + end | |
| 232 | 233 | # Reset to old state |
| 233 | 234 | Person.delete_all |
| 234 | 235 | |
| ... | ... | @@ -240,8 +241,9 @@ if ActiveRecord::Base.connection.supports_migrations? |
| 240 | 241 | assert_kind_of BigDecimal, row.wealth |
| 241 | 242 | |
| 242 | 243 | # If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken! |
| 243 | - assert_equal correct_value, row.wealth | |
| 244 | - | |
| 244 | + unless current_adapter?(:SQLite3Adapter) | |
| 245 | + assert_equal correct_value, row.wealth | |
| 246 | + end | |
| 245 | 247 | # Reset to old state |
| 246 | 248 | Person.connection.del_column "people", "wealth" rescue nil |
| 247 | 249 | Person.reset_column_information |
| ... | ... | @@ -267,10 +269,7 @@ if ActiveRecord::Base.connection.supports_migrations? |
| 267 | 269 | |
| 268 | 270 | # Test for 30 significent digits (beyond the 16 of float), 10 of them |
| 269 | 271 | # after the decimal place. |
| 270 | - if current_adapter?(:SQLiteAdapter) | |
| 271 | - # SQLite3 uses float in violation of SQL. Test for 16 decimal places. | |
| 272 | - assert_equal BigDecimal.new('0.123456789012346E20'), bob.wealth | |
| 273 | - else | |
| 272 | + unless current_adapter?(:SQLite3Adapter) | |
| 274 | 273 | assert_equal BigDecimal.new("0012345678901234567890.0123456789"), bob.wealth |
| 275 | 274 | end |
| 276 | 275 | ... | ... |
vendor/rails/activerecord/test/mixin_test.rb
| ... | ... | @@ -211,6 +211,53 @@ class ListTest < Test::Unit::TestCase |
| 211 | 211 | assert_equal [new2, new1, new3], ListMixin.find(:all, :conditions => 'parent_id IS NULL', :order => 'pos') |
| 212 | 212 | end |
| 213 | 213 | |
| 214 | + def test_remove_from_list_should_then_fail_in_list? | |
| 215 | + assert_equal true, mixins(:list_1).in_list? | |
| 216 | + mixins(:list_1).remove_from_list | |
| 217 | + assert_equal false, mixins(:list_1).in_list? | |
| 218 | + end | |
| 219 | + | |
| 220 | + def test_remove_from_list_should_set_position_to_nil | |
| 221 | + assert_equal [mixins(:list_1), | |
| 222 | + mixins(:list_2), | |
| 223 | + mixins(:list_3), | |
| 224 | + mixins(:list_4)], | |
| 225 | + ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos') | |
| 226 | + | |
| 227 | + mixins(:list_2).remove_from_list | |
| 228 | + | |
| 229 | + assert_equal [mixins(:list_2, :reload), | |
| 230 | + mixins(:list_1, :reload), | |
| 231 | + mixins(:list_3, :reload), | |
| 232 | + mixins(:list_4, :reload)], | |
| 233 | + ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos') | |
| 234 | + | |
| 235 | + assert_equal 1, mixins(:list_1).pos | |
| 236 | + assert_equal nil, mixins(:list_2).pos | |
| 237 | + assert_equal 2, mixins(:list_3).pos | |
| 238 | + assert_equal 3, mixins(:list_4).pos | |
| 239 | + end | |
| 240 | + | |
| 241 | + def test_remove_before_destroy_does_not_shift_lower_items_twice | |
| 242 | + assert_equal [mixins(:list_1), | |
| 243 | + mixins(:list_2), | |
| 244 | + mixins(:list_3), | |
| 245 | + mixins(:list_4)], | |
| 246 | + ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos') | |
| 247 | + | |
| 248 | + mixins(:list_2).remove_from_list | |
| 249 | + mixins(:list_2).destroy | |
| 250 | + | |
| 251 | + assert_equal [mixins(:list_1, :reload), | |
| 252 | + mixins(:list_3, :reload), | |
| 253 | + mixins(:list_4, :reload)], | |
| 254 | + ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos') | |
| 255 | + | |
| 256 | + assert_equal 1, mixins(:list_1).pos | |
| 257 | + assert_equal 2, mixins(:list_3).pos | |
| 258 | + assert_equal 3, mixins(:list_4).pos | |
| 259 | + end | |
| 260 | + | |
| 214 | 261 | end |
| 215 | 262 | |
| 216 | 263 | class TreeTest < Test::Unit::TestCase | ... | ... |
vendor/rails/activerecord/test/validations_test.rb
| ... | ... | @@ -631,7 +631,7 @@ class ValidationsTest < Test::Unit::TestCase |
| 631 | 631 | t = Topic.new('title' => 'noreplies', 'content' => 'whatever') |
| 632 | 632 | assert !t.save |
| 633 | 633 | assert t.errors.on(:replies) |
| 634 | - t.replies.create('title' => 'areply', 'content' => 'whateveragain') | |
| 634 | + t.replies.build('title' => 'areply', 'content' => 'whateveragain') | |
| 635 | 635 | assert t.valid? |
| 636 | 636 | end |
| 637 | 637 | |
| ... | ... | @@ -824,7 +824,7 @@ class ValidationsTest < Test::Unit::TestCase |
| 824 | 824 | t = Topic.new('title' => 'あいうえお', 'content' => 'かきくけこ') |
| 825 | 825 | assert !t.save |
| 826 | 826 | assert t.errors.on(:replies) |
| 827 | - t.replies.create('title' => 'あいうえお', 'content' => 'かきくけこ') | |
| 827 | + t.replies.build('title' => 'あいうえお', 'content' => 'かきくけこ') | |
| 828 | 828 | assert t.valid? |
| 829 | 829 | end |
| 830 | 830 | end | ... | ... |
vendor/rails/activesupport/CHANGELOG
| 1 | +*1.4.4* (October 12th, 2007) | |
| 2 | + | |
| 3 | +* Backport: allow array and hash query parameters. Array route parameters are converted/to/a/path as before. #6765, #7047, #7462 [bgipsy, Jeremy McAnally, Dan Kubb, brendan, Diego Algorta Casamayou] | |
| 4 | + | |
| 5 | + | |
| 6 | +*1.4.3* (October 4th, 2007) | |
| 7 | + | |
| 8 | +* Demote Hash#to_xml to use XmlSimple#xml_in_string so it can't read files or stdin. #8453 [candlerb, Jeremy Kemper] | |
| 9 | + | |
| 10 | +* Document Object#blank?. #6491 [Chris Mear] | |
| 11 | + | |
| 12 | +* Update Dependencies to ignore constants inherited from ancestors. Closes #6951. [Nicholas Seckar] | |
| 13 | + | |
| 14 | +* Improved multibyte performance by relying less on exception raising #8159 [Blaine] | |
| 15 | + | |
| 16 | + | |
| 1 | 17 | *1.4.2* (March 12th, 2007) |
| 2 | 18 | |
| 3 | 19 | * Ruby 1.8.6 and 1.9 define private Time#to_date and #to_datetime; make them | ... | ... |