actionpack 3.0.3 → 3.0.4.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

@@ -31,10 +31,9 @@ module AbstractController
31
31
  # A list of all internal methods for a controller. This finds the first
32
32
  # abstract superclass of a controller, and gets a list of all public
33
33
  # instance methods on that abstract class. Public instance methods of
34
- # a controller would normally be considered action methods, so we
35
- # are removing those methods on classes declared as abstract
36
- # (ActionController::Metal and ActionController::Base are defined
37
- # as abstract)
34
+ # a controller would normally be considered action methods, so methods
35
+ # declared on abstract classes are being removed.
36
+ # (ActionController::Metal and ActionController::Base are defined as abstract)
38
37
  def internal_methods
39
38
  controller = self
40
39
  controller = controller.superclass until controller.abstract?
@@ -13,7 +13,7 @@ module AbstractController
13
13
 
14
14
  # Override AbstractController::Base's process_action to run the
15
15
  # process_action callbacks around the normal behavior.
16
- def process_action(method_name)
16
+ def process_action(method_name, *args)
17
17
  run_callbacks(:process_action, method_name) do
18
18
  super
19
19
  end
@@ -235,13 +235,10 @@ module AbstractController
235
235
  controller_path
236
236
  end
237
237
 
238
- # Takes the specified layout and creates a _layout method to be called
239
- # by _default_layout
238
+ # Creates a _layout method to be called by _default_layout .
240
239
  #
241
- # If there is no explicit layout specified:
242
- # If a layout is found in the view paths with the controller's
243
- # name, return that string. Otherwise, use the superclass'
244
- # layout (which might also be implied)
240
+ # If a layout is not explicitly mentioned then look for a layout with the controller's name.
241
+ # if nothing is found then try same procedure to find super class's layout.
245
242
  def _write_layout_method
246
243
  remove_possible_method(:_layout)
247
244
 
@@ -14,14 +14,15 @@ module AbstractController
14
14
  # it will trigger the lookup_context and consequently expire the cache.
15
15
  # TODO Add some deprecation warnings to remove I18n.locale from controllers
16
16
  class I18nProxy < ::I18n::Config #:nodoc:
17
- attr_reader :i18n_config, :lookup_context
17
+ attr_reader :original_config, :lookup_context
18
18
 
19
- def initialize(i18n_config, lookup_context)
20
- @i18n_config, @lookup_context = i18n_config, lookup_context
19
+ def initialize(original_config, lookup_context)
20
+ original_config = original_config.original_config if original_config.respond_to?(:original_config)
21
+ @original_config, @lookup_context = original_config, lookup_context
21
22
  end
22
23
 
23
24
  def locale
24
- @i18n_config.locale
25
+ @original_config.locale
25
26
  end
26
27
 
27
28
  def locale=(value)
@@ -4,29 +4,30 @@ module ActionController #:nodoc:
4
4
  module Caching
5
5
  # Action caching is similar to page caching by the fact that the entire
6
6
  # output of the response is cached, but unlike page caching, every
7
- # request still goes through the Action Pack. The key benefit
8
- # of this is that filters are run before the cache is served, which
9
- # allows for authentication and other restrictions on whether someone
10
- # is allowed to see the cache. Example:
7
+ # request still goes through Action Pack. The key benefit of this is
8
+ # that filters run before the cache is served, which allows for
9
+ # authentication and other restrictions on whether someone is allowed
10
+ # to execute such action. Example:
11
11
  #
12
12
  # class ListsController < ApplicationController
13
13
  # before_filter :authenticate, :except => :public
14
+ #
14
15
  # caches_page :public
15
- # caches_action :index, :show, :feed
16
+ # caches_action :index, :show
16
17
  # end
17
18
  #
18
- # In this example, the public action doesn't require authentication,
19
- # so it's possible to use the faster page caching method. But both
20
- # the show and feed action are to be shielded behind the authenticate
21
- # filter, so we need to implement those as action caches.
22
- #
23
- # Action caching internally uses the fragment caching and an around
24
- # filter to do the job. The fragment cache is named according to both
25
- # the current host and the path. So a page that is accessed at
26
- # http://david.somewhere.com/lists/show/1 will result in a fragment named
27
- # "david.somewhere.com/lists/show/1". This allows the cacher to
28
- # differentiate between "david.somewhere.com/lists/" and
29
- # "jamis.somewhere.com/lists/" -- which is a helpful way of assisting
19
+ # In this example, the +public+ action doesn't require authentication
20
+ # so it's possible to use the faster page caching. On the other hand
21
+ # +index+ and +show+ require authentication. They can still be cached,
22
+ # but we need action caching for them.
23
+ #
24
+ # Action caching uses fragment caching internally and an around
25
+ # filter to do the job. The fragment cache is named according to
26
+ # the host and path of the request. A page that is accessed at
27
+ # <tt>http://david.example.com/lists/show/1</tt> will result in a fragment named
28
+ # <tt>david.example.com/lists/show/1</tt>. This allows the cacher to
29
+ # differentiate between <tt>david.example.com/lists/</tt> and
30
+ # <tt>jamis.example.com/lists/</tt> -- which is a helpful way of assisting
30
31
  # the subdomain-as-account-key pattern.
31
32
  #
32
33
  # Different representations of the same resource, e.g.
@@ -38,19 +39,23 @@ module ActionController #:nodoc:
38
39
  # <tt>:action => 'list', :format => :xml</tt>.
39
40
  #
40
41
  # You can set modify the default action cache path by passing a
41
- # :cache_path option. This will be passed directly to
42
- # ActionCachePath.path_for. This is handy for actions with multiple
43
- # possible routes that should be cached differently. If a block is
44
- # given, it is called with the current controller instance.
42
+ # <tt>:cache_path</tt> option. This will be passed directly to
43
+ # <tt>ActionCachePath.path_for</tt>. This is handy for actions with
44
+ # multiple possible routes that should be cached differently. If a
45
+ # block is given, it is called with the current controller instance.
45
46
  #
46
- # And you can also use :if (or :unless) to pass a Proc that
47
- # specifies when the action should be cached.
47
+ # And you can also use <tt>:if</tt> (or <tt>:unless</tt>) to pass a
48
+ # proc that specifies when the action should be cached.
48
49
  #
49
- # Finally, if you are using memcached, you can also pass :expires_in.
50
+ # Finally, if you are using memcached, you can also pass <tt>:expires_in</tt>.
51
+ #
52
+ # The following example depicts some of the points made above:
50
53
  #
51
54
  # class ListsController < ApplicationController
52
55
  # before_filter :authenticate, :except => :public
53
- # caches_page :public
56
+ #
57
+ # caches_page :public
58
+ #
54
59
  # caches_action :index, :if => proc do |c|
55
60
  # !c.request.format.json? # cache if is not a JSON request
56
61
  # end
@@ -58,19 +63,28 @@ module ActionController #:nodoc:
58
63
  # caches_action :show, :cache_path => { :project => 1 },
59
64
  # :expires_in => 1.hour
60
65
  #
61
- # caches_action :feed, :cache_path => proc do |controller|
62
- # if controller.params[:user_id]
63
- # controller.send(:user_list_url,
64
- # controller.params[:user_id], controller.params[:id])
66
+ # caches_action :feed, :cache_path => proc do |c|
67
+ # if c.params[:user_id]
68
+ # c.send(:user_list_url,
69
+ # c.params[:user_id], c.params[:id])
65
70
  # else
66
- # controller.send(:list_url, controller.params[:id])
71
+ # c.send(:list_url, c.params[:id])
67
72
  # end
68
73
  # end
69
74
  # end
70
75
  #
71
- # If you pass :layout => false, it will only cache your action
72
- # content. It is useful when your layout has dynamic information.
76
+ # If you pass <tt>:layout => false</tt>, it will only cache your action
77
+ # content. That's useful when your layout has dynamic information.
78
+ #
79
+ # Warning: If the format of the request is determined by the Accept HTTP
80
+ # header the Content-Type of the cached response could be wrong because
81
+ # no information about the MIME type is stored in the cache key. So, if
82
+ # you first ask for MIME type M in the Accept header, a cache entry is
83
+ # created, and then perform a second resquest to the same resource asking
84
+ # for a different MIME type, you'd get the content cached for M.
73
85
  #
86
+ # The <tt>:format</tt> parameter is taken into account though. The safest
87
+ # way to cache by MIME type is to pass the format in the route.
74
88
  module Actions
75
89
  extend ActiveSupport::Concern
76
90
 
@@ -71,9 +71,9 @@ module ActionController #:nodoc:
71
71
 
72
72
  # Manually cache the +content+ in the key determined by +path+. Example:
73
73
  # cache_page "I'm the cached content", "/lists/show"
74
- def cache_page(content, path)
74
+ def cache_page(content, path, extension = nil)
75
75
  return unless perform_caching
76
- path = page_cache_path(path)
76
+ path = page_cache_path(path, extension)
77
77
 
78
78
  instrument_page_cache :write_page, path do
79
79
  FileUtils.makedirs(File.dirname(path))
@@ -98,14 +98,16 @@ module ActionController #:nodoc:
98
98
  end
99
99
 
100
100
  private
101
- def page_cache_file(path)
101
+ def page_cache_file(path, extension)
102
102
  name = (path.empty? || path == "/") ? "/index" : URI.unescape(path.chomp('/'))
103
- name << page_cache_extension unless (name.split('/').last || name).include? '.'
103
+ unless (name.split('/').last || name).include? '.'
104
+ name << (extension || self.page_cache_extension)
105
+ end
104
106
  return name
105
107
  end
106
108
 
107
- def page_cache_path(path)
108
- page_cache_directory + page_cache_file(path)
109
+ def page_cache_path(path, extension = nil)
110
+ page_cache_directory + page_cache_file(path, extension)
109
111
  end
110
112
 
111
113
  def instrument_page_cache(name, path)
@@ -146,7 +148,12 @@ module ActionController #:nodoc:
146
148
  request.path
147
149
  end
148
150
 
149
- self.class.cache_page(content || response.body, path)
151
+
152
+ if (type = Mime::LOOKUP[self.content_type]) && (type_symbol = type.symbol).present?
153
+ extension = ".#{type_symbol}"
154
+ end
155
+
156
+ self.class.cache_page(content || response.body, path, extension)
150
157
  end
151
158
 
152
159
  private
@@ -71,7 +71,7 @@ module ActionController
71
71
  end
72
72
 
73
73
  add :json do |json, options|
74
- json = json.to_json(options) unless json.respond_to?(:to_str)
74
+ json = json.to_json(options) unless json.kind_of?(String)
75
75
  json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
76
76
  self.content_type ||= Mime::JSON
77
77
  self.response_body = json
@@ -71,9 +71,13 @@ module ActionController #:nodoc:
71
71
  # class FooController < ApplicationController
72
72
  # protect_from_forgery :except => :index
73
73
  #
74
- # # you can disable csrf protection on controller-by-controller basis:
75
- # skip_before_filter :verify_authenticity_token
76
- # end
74
+ # You can disable csrf protection on controller-by-controller basis:
75
+ #
76
+ # skip_before_filter :verify_authenticity_token
77
+ #
78
+ # It can also be disabled for specific controller actions:
79
+ #
80
+ # skip_before_filter :verify_authenticity_token, :except => [:create]
77
81
  #
78
82
  # Valid Options:
79
83
  #
@@ -36,7 +36,7 @@ module ActionDispatch
36
36
  #
37
37
  # GET /posts/5.xml | request.format => Mime::XML
38
38
  # GET /posts/5.xhtml | request.format => Mime::HTML
39
- # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
39
+ # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first
40
40
  #
41
41
  def format(view_path = [])
42
42
  formats.first
@@ -216,7 +216,7 @@ module ActionDispatch
216
216
  # TODO This should be broken apart into AD::Request::Session and probably
217
217
  # be included by the session middleware.
218
218
  def reset_session
219
- session.destroy if session
219
+ session.destroy if session && session.respond_to?(:destroy)
220
220
  self.session = {}
221
221
  @env['action_dispatch.request.flash_hash'] = nil
222
222
  end
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/object/blank'
2
-
3
1
  module ActionDispatch
4
2
  module Http
5
3
  class UploadedFile
@@ -13,6 +11,14 @@ module ActionDispatch
13
11
  raise(ArgumentError, ':tempfile is required') unless @tempfile
14
12
  end
15
13
 
14
+ def open
15
+ @tempfile.open
16
+ end
17
+
18
+ def path
19
+ @tempfile.path
20
+ end
21
+
16
22
  def read(*args)
17
23
  @tempfile.read(*args)
18
24
  end
@@ -16,17 +16,23 @@ module ActionDispatch
16
16
  # Examples for writing:
17
17
  #
18
18
  # # Sets a simple session cookie.
19
+ # # This cookie will be deleted when the user's browser is closed.
19
20
  # cookies[:user_name] = "david"
20
21
  #
22
+ # # Assign an array of values to a cookie.
23
+ # cookies[:lat_lon] = [47.68, -122.37]
24
+ #
21
25
  # # Sets a cookie that expires in 1 hour.
22
26
  # cookies[:login] = { :value => "XJ-122", :expires => 1.hour.from_now }
23
27
  #
24
28
  # # Sets a signed cookie, which prevents a user from tampering with its value.
25
- # # You must specify a value in ActionController::Base.cookie_verifier_secret.
26
- # cookies.signed[:remember_me] = [current_user.id, current_user.salt]
29
+ # # The cookie is signed by your app's <tt>config.secret_token</tt> value.
30
+ # # Rails generates this value by default when you create a new Rails app.
31
+ # cookies.signed[:user_id] = current_user.id
27
32
  #
28
33
  # # Sets a "permanent" cookie (which expires in 20 years from now).
29
34
  # cookies.permanent[:login] = "XJ-122"
35
+ #
30
36
  # # You can also chain these methods:
31
37
  # cookies.permanent.signed[:login] = "XJ-122"
32
38
  #
@@ -34,6 +40,7 @@ module ActionDispatch
34
40
  #
35
41
  # cookies[:user_name] # => "david"
36
42
  # cookies.size # => 2
43
+ # cookies[:lat_lon] # => [47.68, -122.37]
37
44
  #
38
45
  # Example for deleting:
39
46
  #
@@ -275,7 +282,7 @@ module ActionDispatch
275
282
  "integrity hash for cookie session data. Use " +
276
283
  "config.secret_token = \"some secret phrase of at " +
277
284
  "least #{SECRET_MIN_LENGTH} characters\"" +
278
- "in config/application.rb"
285
+ "in config/initializers/secret_token.rb"
279
286
  end
280
287
 
281
288
  if secret.length < SECRET_MIN_LENGTH
@@ -43,20 +43,20 @@ module ActionDispatch
43
43
  end
44
44
 
45
45
  def call(env)
46
- status, headers, body = @app.call(env)
47
-
48
- # Only this middleware cares about RoutingError. So, let's just raise
49
- # it here.
50
- # TODO: refactor this middleware to handle the X-Cascade scenario without
51
- # having to raise an exception.
52
- if headers['X-Cascade'] == 'pass'
53
- raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect}"
46
+ begin
47
+ status, headers, body = @app.call(env)
48
+ exception = nil
49
+
50
+ # Only this middleware cares about RoutingError. So, let's just raise
51
+ # it here.
52
+ if headers['X-Cascade'] == 'pass'
53
+ raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect}"
54
+ end
55
+ rescue Exception => exception
56
+ raise exception if env['action_dispatch.show_exceptions'] == false
54
57
  end
55
58
 
56
- [status, headers, body]
57
- rescue Exception => exception
58
- raise exception if env['action_dispatch.show_exceptions'] == false
59
- render_exception(env, exception)
59
+ exception ? render_exception(env, exception) : [status, headers, body]
60
60
  end
61
61
 
62
62
  private
@@ -66,6 +66,18 @@ module ActionDispatch
66
66
  end
67
67
 
68
68
  @options.merge!(default_controller_and_action(to_shorthand))
69
+
70
+ requirements.each do |name, requirement|
71
+ # segment_keys.include?(k.to_s) || k == :controller
72
+ next unless Regexp === requirement && !constraints[name]
73
+
74
+ if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
75
+ raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
76
+ end
77
+ if requirement.multiline?
78
+ raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}"
79
+ end
80
+ end
69
81
  end
70
82
 
71
83
  # match "account/overview"
@@ -113,15 +125,6 @@ module ActionDispatch
113
125
  @requirements ||= (@options[:constraints].is_a?(Hash) ? @options[:constraints] : {}).tap do |requirements|
114
126
  requirements.reverse_merge!(@scope[:constraints]) if @scope[:constraints]
115
127
  @options.each { |k, v| requirements[k] = v if v.is_a?(Regexp) }
116
-
117
- requirements.values.grep(Regexp).each do |requirement|
118
- if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
119
- raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
120
- end
121
- if requirement.multiline?
122
- raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}"
123
- end
124
- end
125
128
  end
126
129
  end
127
130
 
@@ -243,7 +246,11 @@ module ActionDispatch
243
246
  #
244
247
  # root :to => 'pages#main'
245
248
  #
246
- # You should put the root route at the end of <tt>config/routes.rb</tt>.
249
+ # For options, see the +match+ method's documentation, as +root+ uses it internally.
250
+ #
251
+ # You should put the root route at the top of <tt>config/routes.rb</tt>,
252
+ # because this means it will be matched first. As this is the most popular route
253
+ # of most Rails applications, this is beneficial.
247
254
  def root(options = {})
248
255
  match '/', options.reverse_merge(:as => :root)
249
256
  end
@@ -265,18 +272,18 @@ module ActionDispatch
265
272
 
266
273
  # Mount a Rack-based application to be used within the application.
267
274
  #
268
- # mount SomeRackApp, :at => "some_route"
275
+ # mount SomeRackApp, :at => "some_route"
269
276
  #
270
277
  # Alternatively:
271
278
  #
272
- # mount(SomeRackApp => "some_route")
279
+ # mount(SomeRackApp => "some_route")
273
280
  #
274
281
  # All mounted applications come with routing helpers to access them.
275
282
  # These are named after the class specified, so for the above example
276
283
  # the helper is either +some_rack_app_path+ or +some_rack_app_url+.
277
284
  # To customize this helper's name, use the +:as+ option:
278
285
  #
279
- # mount(SomeRackApp => "some_route", :as => "exciting")
286
+ # mount(SomeRackApp => "some_route", :as => "exciting")
280
287
  #
281
288
  # This will generate the +exciting_path+ and +exciting_url+ helpers
282
289
  # which can be used to navigate to this mounted app.
@@ -445,8 +452,18 @@ module ActionDispatch
445
452
  super
446
453
  end
447
454
 
448
- # Used to route <tt>/photos</tt> (without the prefix <tt>/admin</tt>)
449
- # to Admin::PostsController:
455
+ # Used to scope a set of routes to particular constraints.
456
+ #
457
+ # Take the following route definition as an example:
458
+ #
459
+ # scope :path => ":account_id", :as => "account" do
460
+ # resources :projects
461
+ # end
462
+ #
463
+ # This generates helpers such as +account_projects_path+, just like +resources+ does.
464
+ # The difference here being that the routes generated are like /rails/projects/2,
465
+ # rather than /accounts/rails/projects/2.
466
+ #
450
467
  # === Supported options
451
468
  # [:module]
452
469
  # If you want to route /posts (without the prefix /admin) to
@@ -552,38 +569,38 @@ module ActionDispatch
552
569
  #
553
570
  # This generates the following routes:
554
571
  #
555
- # admin_posts GET /admin/posts(.:format) {:action=>"index", :controller=>"admin/posts"}
556
- # admin_posts POST /admin/posts(.:format) {:action=>"create", :controller=>"admin/posts"}
557
- # new_admin_post GET /admin/posts/new(.:format) {:action=>"new", :controller=>"admin/posts"}
558
- # edit_admin_post GET /admin/posts/:id/edit(.:format) {:action=>"edit", :controller=>"admin/posts"}
559
- # admin_post GET /admin/posts/:id(.:format) {:action=>"show", :controller=>"admin/posts"}
560
- # admin_post PUT /admin/posts/:id(.:format) {:action=>"update", :controller=>"admin/posts"}
561
- # admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"}
572
+ # admin_posts GET /admin/posts(.:format) {:action=>"index", :controller=>"admin/posts"}
573
+ # admin_posts POST /admin/posts(.:format) {:action=>"create", :controller=>"admin/posts"}
574
+ # new_admin_post GET /admin/posts/new(.:format) {:action=>"new", :controller=>"admin/posts"}
575
+ # edit_admin_post GET /admin/posts/:id/edit(.:format) {:action=>"edit", :controller=>"admin/posts"}
576
+ # admin_post GET /admin/posts/:id(.:format) {:action=>"show", :controller=>"admin/posts"}
577
+ # admin_post PUT /admin/posts/:id(.:format) {:action=>"update", :controller=>"admin/posts"}
578
+ # admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"}
562
579
  # === Supported options
563
580
  #
564
- # The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+ all default to the name of the namespace.
581
+ # The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+ options all default to the name of the namespace.
565
582
  #
566
583
  # [:path]
567
584
  # The path prefix for the routes.
568
585
  #
569
- # namespace :admin, :path => "sekret" do
570
- # resources :posts
571
- # end
586
+ # namespace :admin, :path => "sekret" do
587
+ # resources :posts
588
+ # end
572
589
  #
573
590
  # All routes for the above +resources+ will be accessible through +/sekret/posts+, rather than +/admin/posts+
574
591
  #
575
592
  # [:module]
576
593
  # The namespace for the controllers.
577
594
  #
578
- # namespace :admin, :module => "sekret" do
579
- # resources :posts
580
- # end
595
+ # namespace :admin, :module => "sekret" do
596
+ # resources :posts
597
+ # end
581
598
  #
582
599
  # The +PostsController+ here should go in the +Sekret+ namespace and so it should be defined like this:
583
600
  #
584
- # class Sekret::PostsController < ApplicationController
585
- # # code go here
586
- # end
601
+ # class Sekret::PostsController < ApplicationController
602
+ # # code go here
603
+ # end
587
604
  #
588
605
  # [:as]
589
606
  # Changes the name used in routing helpers for this namespace.
@@ -932,6 +949,22 @@ module ActionDispatch
932
949
  # GET /photos/:id/edit
933
950
  # PUT /photos/:id
934
951
  # DELETE /photos/:id
952
+ #
953
+ # Resources can also be nested infinitely by using this block syntax:
954
+ #
955
+ # resources :photos do
956
+ # resources :comments
957
+ # end
958
+ #
959
+ # This generates the following comments routes:
960
+ #
961
+ # GET /photos/:id/comments/new
962
+ # POST /photos/:id/comments
963
+ # GET /photos/:id/comments/:id
964
+ # GET /photos/:id/comments/:id/edit
965
+ # PUT /photos/:id/comments/:id
966
+ # DELETE /photos/:id/comments/:id
967
+ #
935
968
  # === Supported options
936
969
  # [:path_names]
937
970
  # Allows you to change the paths of the seven default actions.
@@ -940,6 +973,21 @@ module ActionDispatch
940
973
  # resources :posts, :path_names => { :new => "brand_new" }
941
974
  #
942
975
  # The above example will now change /posts/new to /posts/brand_new
976
+ #
977
+ # [:module]
978
+ # Set the module where the controller can be found. Defaults to nothing.
979
+ #
980
+ # resources :posts, :module => "admin"
981
+ #
982
+ # All requests to the posts resources will now go to +Admin::PostsController+.
983
+ #
984
+ # [:path]
985
+ #
986
+ # Set a path prefix for this resource.
987
+ #
988
+ # resources :posts, :path => "admin"
989
+ #
990
+ # All actions for this resource will now be at +/admin/posts+.
943
991
  def resources(*resources, &block)
944
992
  options = resources.extract_options!
945
993
 
@@ -1051,6 +1099,7 @@ module ActionDispatch
1051
1099
  end
1052
1100
  end
1053
1101
 
1102
+ # See ActionDispatch::Routing::Mapper::Scoping#namespace
1054
1103
  def namespace(path, options = {})
1055
1104
  if resource_scope?
1056
1105
  nested { super }
@@ -1262,6 +1311,8 @@ module ActionDispatch
1262
1311
  name_prefix = @scope[:as]
1263
1312
 
1264
1313
  if parent_resource
1314
+ return nil if as.nil? && action.nil?
1315
+
1265
1316
  collection_name = parent_resource.collection_name
1266
1317
  member_name = parent_resource.member_name
1267
1318
  end
@@ -421,7 +421,7 @@ module ActionDispatch
421
421
  end
422
422
 
423
423
  def raise_routing_error
424
- raise ActionController::RoutingError.new("No route matches #{options.inspect}")
424
+ raise ActionController::RoutingError, "No route matches #{options.inspect}"
425
425
  end
426
426
 
427
427
  def different_controller?
@@ -2,8 +2,9 @@ module ActionPack
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 3
4
4
  MINOR = 0
5
- TINY = 3
6
-
7
- STRING = [MAJOR, MINOR, TINY].join('.')
5
+ TINY = 4
6
+ PRE = "rc1"
7
+
8
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
8
9
  end
9
10
  end
@@ -79,8 +79,8 @@ module ActionView #:nodoc:
79
79
  #
80
80
  # === Template caching
81
81
  #
82
- # By default, Rails will compile each template to a method in order to render it. When you alter a template, Rails will
83
- # check the file's modification time and recompile it.
82
+ # By default, Rails will compile each template to a method in order to render it. When you alter a template,
83
+ # Rails will check the file's modification time and recompile it in development mode.
84
84
  #
85
85
  # == Builder
86
86
  #
@@ -375,7 +375,9 @@ module ActionView
375
375
  # <script type="text/javascript" src="/javascripts/body.js"></script>
376
376
  # <script type="text/javascript" src="/javascripts/tail.js"></script>
377
377
  def self.register_javascript_expansion(expansions)
378
- @@javascript_expansions.merge!(expansions)
378
+ expansions.each do |key, values|
379
+ @@javascript_expansions[key] = (@@javascript_expansions[key] || []) | Array(values)
380
+ end
379
381
  end
380
382
 
381
383
  # Register one or more stylesheet files to be included when <tt>symbol</tt>
@@ -390,7 +392,9 @@ module ActionView
390
392
  # <link href="/stylesheets/body.css" media="screen" rel="stylesheet" type="text/css" />
391
393
  # <link href="/stylesheets/tail.css" media="screen" rel="stylesheet" type="text/css" />
392
394
  def self.register_stylesheet_expansion(expansions)
393
- @@stylesheet_expansions.merge!(expansions)
395
+ expansions.each do |key, values|
396
+ @@stylesheet_expansions[key] = (@@stylesheet_expansions[key] || []) | Array(values)
397
+ end
394
398
  end
395
399
 
396
400
  def self.reset_javascript_include_default
@@ -860,7 +864,7 @@ module ActionView
860
864
  def determine_source(source, collection)
861
865
  case source
862
866
  when Symbol
863
- collection[source] || raise(ArgumentError, "No expansion found for #{source.inspect}")
867
+ collection[source].present? ? collection[source] : raise(ArgumentError, "No expansion found for #{source.inspect}")
864
868
  else
865
869
  source
866
870
  end
@@ -1097,7 +1097,7 @@ module ActionView
1097
1097
  include InstanceTagMethods
1098
1098
  end
1099
1099
 
1100
- class FormBuilder #:nodoc:
1100
+ class FormBuilder
1101
1101
  # The methods which wrap a form helper call.
1102
1102
  class_inheritable_accessor :field_helpers
1103
1103
  self.field_helpers = (FormHelper.instance_method_names - ['form_for'])
@@ -534,7 +534,7 @@ module ActionView
534
534
  else
535
535
  selected = Array.wrap(selected)
536
536
  options = selected.extract_options!.symbolize_keys
537
- [ options[:selected] || selected , options[:disabled] ]
537
+ [ options.include?(:selected) ? options[:selected] : selected, options[:disabled] ]
538
538
  end
539
539
  end
540
540
 
@@ -38,7 +38,7 @@ module ActionView
38
38
  # form_tag('/upload', :multipart => true)
39
39
  # # => <form action="/upload" method="post" enctype="multipart/form-data">
40
40
  #
41
- # <%= form_tag('/posts')do -%>
41
+ # <%= form_tag('/posts') do -%>
42
42
  # <div><%= submit_tag 'Save' %></div>
43
43
  # <% end -%>
44
44
  # # => <form action="/posts" method="post"><div><input type="submit" name="submit" value="Save" /></div></form>
@@ -67,7 +67,7 @@ module ActionView
67
67
  # * Any other key creates standard HTML attributes for the tag.
68
68
  #
69
69
  # ==== Examples
70
- # select_tag "people", options_from_collection_for_select(@people, "name", "id")
70
+ # select_tag "people", options_from_collection_for_select(@people, "id", "name")
71
71
  # # <select id="people" name="people"><option value="1">David</option></select>
72
72
  #
73
73
  # select_tag "people", "<option>David</option>"
@@ -115,6 +115,7 @@ module ActionView
115
115
  # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
116
116
  # * <tt>:size</tt> - The number of visible characters that will fit in the input.
117
117
  # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
118
+ # * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
118
119
  # * Any other key creates standard HTML attributes for the tag.
119
120
  #
120
121
  # ==== Examples
@@ -124,6 +125,9 @@ module ActionView
124
125
  # text_field_tag 'query', 'Enter your search query here'
125
126
  # # => <input id="query" name="query" type="text" value="Enter your search query here" />
126
127
  #
128
+ # text_field_tag 'search', nil, :placeholder => 'Enter search term...'
129
+ # # => <input id="search" name="search" placeholder="Enter search term..." type="text" />
130
+ #
127
131
  # text_field_tag 'request', nil, :class => 'special_input'
128
132
  # # => <input class="special_input" id="request" name="request" type="text" />
129
133
  #
@@ -272,12 +272,13 @@ module ActionView
272
272
  digits, rounded_number = 1, 0
273
273
  else
274
274
  digits = (Math.log10(number.abs) + 1).floor
275
- rounded_number = BigDecimal.new((number / 10 ** (digits - precision)).to_s).round.to_f * 10 ** (digits - precision)
275
+ rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new((10 ** (digits - precision)).to_f.to_s)).round.to_f * 10 ** (digits - precision)
276
+ digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed
276
277
  end
277
278
  precision = precision - digits
278
279
  precision = precision > 0 ? precision : 0 #don't let it be negative
279
280
  else
280
- rounded_number = BigDecimal.new((number * (10 ** precision)).to_s).round.to_f / 10 ** precision
281
+ rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
281
282
  end
282
283
  formatted_number = number_with_delimiter("%01.#{precision}f" % rounded_number, options)
283
284
  if strip_insignificant_zeros
@@ -167,11 +167,11 @@ module ActionView
167
167
  end
168
168
 
169
169
  # Overload locale= to also set the I18n.locale. If the current I18n.config object responds
170
- # to i18n_config, it means that it's has a copy of the original I18n configuration and it's
170
+ # to original_config, it means that it's has a copy of the original I18n configuration and it's
171
171
  # acting as proxy, which we need to skip.
172
172
  def locale=(value)
173
173
  if value
174
- config = I18n.config.respond_to?(:i18n_config) ? I18n.config.i18n_config : I18n.config
174
+ config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
175
175
  config.locale = value
176
176
  end
177
177
 
@@ -226,4 +226,4 @@ module ActionView
226
226
  include Details
227
227
  include ViewPaths
228
228
  end
229
- end
229
+ end
@@ -153,10 +153,8 @@ module ActionView
153
153
  # The instance of ActionView::Base that is used by +render+.
154
154
  def view
155
155
  @view ||= begin
156
- view = ActionView::Base.new(ActionController::Base.view_paths, {}, @controller)
156
+ view = @controller.view_context
157
157
  view.singleton_class.send :include, _helpers
158
- view.singleton_class.send :include, @controller._routes.url_helpers
159
- view.singleton_class.send :delegate, :alert, :notice, :to => "request.flash"
160
158
  view.extend(Locals)
161
159
  view.locals = self.locals
162
160
  view.output_buffer = self.output_buffer
@@ -168,6 +166,7 @@ module ActionView
168
166
 
169
167
  INTERNAL_IVARS = %w{
170
168
  @__name__
169
+ @__io__
171
170
  @_assertion_wrapped
172
171
  @_assertions
173
172
  @_result
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actionpack
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
5
- prerelease: false
4
+ hash: 977940590
5
+ prerelease: true
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 3
10
- version: 3.0.3
9
+ - 4
10
+ - rc1
11
+ version: 3.0.4.rc1
11
12
  platform: ruby
12
13
  authors:
13
14
  - David Heinemeier Hansson
@@ -15,7 +16,7 @@ autorequire:
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2010-11-16 00:00:00 -06:00
19
+ date: 2011-01-31 00:00:00 +13:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
@@ -26,12 +27,13 @@ dependencies:
26
27
  requirements:
27
28
  - - "="
28
29
  - !ruby/object:Gem::Version
29
- hash: 1
30
+ hash: 977940590
30
31
  segments:
31
32
  - 3
32
33
  - 0
33
- - 3
34
- version: 3.0.3
34
+ - 4
35
+ - rc1
36
+ version: 3.0.4.rc1
35
37
  type: :runtime
36
38
  version_requirements: *id001
37
39
  - !ruby/object:Gem::Dependency
@@ -42,12 +44,13 @@ dependencies:
42
44
  requirements:
43
45
  - - "="
44
46
  - !ruby/object:Gem::Version
45
- hash: 1
47
+ hash: 977940590
46
48
  segments:
47
49
  - 3
48
50
  - 0
49
- - 3
50
- version: 3.0.3
51
+ - 4
52
+ - rc1
53
+ version: 3.0.4.rc1
51
54
  type: :runtime
52
55
  version_requirements: *id002
53
56
  - !ruby/object:Gem::Dependency
@@ -105,12 +108,12 @@ dependencies:
105
108
  requirements:
106
109
  - - ~>
107
110
  - !ruby/object:Gem::Version
108
- hash: 7
111
+ hash: 5
109
112
  segments:
110
113
  - 0
111
114
  - 5
112
- - 6
113
- version: 0.5.6
115
+ - 7
116
+ version: 0.5.7
114
117
  type: :runtime
115
118
  version_requirements: *id006
116
119
  - !ruby/object:Gem::Dependency
@@ -357,12 +360,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
357
360
  required_rubygems_version: !ruby/object:Gem::Requirement
358
361
  none: false
359
362
  requirements:
360
- - - ">="
363
+ - - ">"
361
364
  - !ruby/object:Gem::Version
362
- hash: 3
365
+ hash: 25
363
366
  segments:
364
- - 0
365
- version: "0"
367
+ - 1
368
+ - 3
369
+ - 1
370
+ version: 1.3.1
366
371
  requirements:
367
372
  - none
368
373
  rubyforge_project: actionpack