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.
- data/lib/abstract_controller/base.rb +3 -4
- data/lib/abstract_controller/callbacks.rb +1 -1
- data/lib/abstract_controller/layouts.rb +3 -6
- data/lib/abstract_controller/rendering.rb +5 -4
- data/lib/action_controller/caching/actions.rb +46 -32
- data/lib/action_controller/caching/pages.rb +14 -7
- data/lib/action_controller/metal/renderers.rb +1 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +7 -3
- data/lib/action_dispatch/http/mime_negotiation.rb +1 -1
- data/lib/action_dispatch/http/request.rb +1 -1
- data/lib/action_dispatch/http/upload.rb +8 -2
- data/lib/action_dispatch/middleware/cookies.rb +10 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +12 -12
- data/lib/action_dispatch/routing/mapper.rb +83 -32
- data/lib/action_dispatch/routing/route_set.rb +1 -1
- data/lib/action_pack/version.rb +4 -3
- data/lib/action_view/base.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +7 -3
- data/lib/action_view/helpers/form_helper.rb +1 -1
- data/lib/action_view/helpers/form_options_helper.rb +1 -1
- data/lib/action_view/helpers/form_tag_helper.rb +6 -2
- data/lib/action_view/helpers/number_helper.rb +3 -2
- data/lib/action_view/lookup_context.rb +3 -3
- data/lib/action_view/test_case.rb +2 -3
- metadata +23 -18
@@ -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
|
35
|
-
#
|
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
|
-
#
|
239
|
-
# by _default_layout
|
238
|
+
# Creates a _layout method to be called by _default_layout .
|
240
239
|
#
|
241
|
-
# If
|
242
|
-
#
|
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 :
|
17
|
+
attr_reader :original_config, :lookup_context
|
18
18
|
|
19
|
-
def initialize(
|
20
|
-
|
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
|
-
@
|
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
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
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
|
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
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
# Action caching
|
24
|
-
# filter to do the job. The fragment cache is named according to
|
25
|
-
# the
|
26
|
-
# http://david.
|
27
|
-
#
|
28
|
-
# differentiate between
|
29
|
-
#
|
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
|
-
#
|
42
|
-
# ActionCachePath.path_for
|
43
|
-
# possible routes that should be cached differently.
|
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
|
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
|
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
|
-
#
|
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 |
|
62
|
-
# if
|
63
|
-
#
|
64
|
-
#
|
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
|
-
#
|
71
|
+
# c.send(:list_url, c.params[:id])
|
67
72
|
# end
|
68
73
|
# end
|
69
74
|
# end
|
70
75
|
#
|
71
|
-
# If you pass
|
72
|
-
# content.
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
#
|
75
|
-
#
|
76
|
-
#
|
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
|
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
|
-
# #
|
26
|
-
#
|
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/
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
#
|
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
|
-
#
|
275
|
+
# mount SomeRackApp, :at => "some_route"
|
269
276
|
#
|
270
277
|
# Alternatively:
|
271
278
|
#
|
272
|
-
#
|
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
|
-
#
|
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
|
449
|
-
#
|
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
|
-
#
|
556
|
-
#
|
557
|
-
#
|
558
|
-
#
|
559
|
-
#
|
560
|
-
#
|
561
|
-
#
|
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
|
-
#
|
570
|
-
#
|
571
|
-
#
|
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
|
-
#
|
579
|
-
#
|
580
|
-
#
|
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
|
-
#
|
585
|
-
#
|
586
|
-
#
|
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
|
424
|
+
raise ActionController::RoutingError, "No route matches #{options.inspect}"
|
425
425
|
end
|
426
426
|
|
427
427
|
def different_controller?
|
data/lib/action_pack/version.rb
CHANGED
data/lib/action_view/base.rb
CHANGED
@@ -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,
|
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
|
-
|
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
|
-
|
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]
|
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
|
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]
|
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, "
|
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(
|
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(
|
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
|
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?(:
|
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 =
|
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:
|
5
|
-
prerelease:
|
4
|
+
hash: 977940590
|
5
|
+
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
|
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:
|
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:
|
30
|
+
hash: 977940590
|
30
31
|
segments:
|
31
32
|
- 3
|
32
33
|
- 0
|
33
|
-
-
|
34
|
-
|
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:
|
47
|
+
hash: 977940590
|
46
48
|
segments:
|
47
49
|
- 3
|
48
50
|
- 0
|
49
|
-
-
|
50
|
-
|
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:
|
111
|
+
hash: 5
|
109
112
|
segments:
|
110
113
|
- 0
|
111
114
|
- 5
|
112
|
-
-
|
113
|
-
version: 0.5.
|
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:
|
365
|
+
hash: 25
|
363
366
|
segments:
|
364
|
-
-
|
365
|
-
|
367
|
+
- 1
|
368
|
+
- 3
|
369
|
+
- 1
|
370
|
+
version: 1.3.1
|
366
371
|
requirements:
|
367
372
|
- none
|
368
373
|
rubyforge_project: actionpack
|