actionpack 1.11.2 → 1.12.0

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.

Files changed (149) hide show
  1. data/CHANGELOG +392 -5
  2. data/lib/action_controller.rb +8 -4
  3. data/lib/action_controller/assertions.rb +9 -10
  4. data/lib/action_controller/base.rb +177 -88
  5. data/lib/action_controller/benchmarking.rb +5 -5
  6. data/lib/action_controller/caching.rb +44 -36
  7. data/lib/action_controller/cgi_ext/cgi_methods.rb +71 -6
  8. data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +1 -1
  9. data/lib/action_controller/cgi_process.rb +36 -24
  10. data/lib/action_controller/components.rb +152 -52
  11. data/lib/action_controller/dependencies.rb +1 -1
  12. data/lib/action_controller/deprecated_redirects.rb +2 -2
  13. data/lib/action_controller/deprecated_request_methods.rb +34 -0
  14. data/lib/action_controller/filters.rb +59 -19
  15. data/lib/action_controller/flash.rb +53 -47
  16. data/lib/action_controller/helpers.rb +2 -2
  17. data/lib/action_controller/integration.rb +524 -0
  18. data/lib/action_controller/layout.rb +58 -23
  19. data/lib/action_controller/mime_responds.rb +163 -0
  20. data/lib/action_controller/mime_type.rb +142 -0
  21. data/lib/action_controller/pagination.rb +13 -7
  22. data/lib/action_controller/request.rb +59 -56
  23. data/lib/action_controller/rescue.rb +1 -1
  24. data/lib/action_controller/routing.rb +29 -10
  25. data/lib/action_controller/scaffolding.rb +8 -0
  26. data/lib/action_controller/session/active_record_store.rb +21 -10
  27. data/lib/action_controller/session/mem_cache_store.rb +18 -12
  28. data/lib/action_controller/session_management.rb +30 -11
  29. data/lib/action_controller/templates/rescues/_trace.rhtml +1 -1
  30. data/lib/action_controller/templates/scaffolds/layout.rhtml +4 -4
  31. data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
  32. data/lib/action_controller/test_process.rb +189 -118
  33. data/lib/action_controller/vendor/html-scanner/html/node.rb +20 -1
  34. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +3 -0
  35. data/lib/action_controller/vendor/html-scanner/html/version.rb +1 -1
  36. data/lib/action_controller/vendor/xml_node.rb +97 -0
  37. data/lib/action_controller/verification.rb +2 -0
  38. data/lib/action_pack/version.rb +3 -3
  39. data/lib/action_view.rb +0 -2
  40. data/lib/action_view/base.rb +109 -36
  41. data/lib/action_view/compiled_templates.rb +1 -1
  42. data/lib/action_view/helpers/active_record_helper.rb +4 -2
  43. data/lib/action_view/helpers/asset_tag_helper.rb +6 -7
  44. data/lib/action_view/helpers/capture_helper.rb +49 -12
  45. data/lib/action_view/helpers/date_helper.rb +14 -4
  46. data/lib/action_view/helpers/form_helper.rb +136 -20
  47. data/lib/action_view/helpers/form_options_helper.rb +29 -7
  48. data/lib/action_view/helpers/form_tag_helper.rb +22 -20
  49. data/lib/action_view/helpers/java_script_macros_helper.rb +29 -9
  50. data/lib/action_view/helpers/javascript_helper.rb +50 -446
  51. data/lib/action_view/helpers/javascripts/controls.js +95 -30
  52. data/lib/action_view/helpers/javascripts/dragdrop.js +161 -21
  53. data/lib/action_view/helpers/javascripts/effects.js +310 -211
  54. data/lib/action_view/helpers/javascripts/prototype.js +228 -28
  55. data/lib/action_view/helpers/number_helper.rb +9 -9
  56. data/lib/action_view/helpers/pagination_helper.rb +1 -1
  57. data/lib/action_view/helpers/prototype_helper.rb +900 -0
  58. data/lib/action_view/helpers/scriptaculous_helper.rb +135 -0
  59. data/lib/action_view/helpers/text_helper.rb +7 -6
  60. data/lib/action_view/helpers/url_helper.rb +23 -14
  61. data/lib/action_view/partials.rb +12 -4
  62. data/rakefile +13 -5
  63. data/test/abstract_unit.rb +4 -3
  64. data/test/active_record_unit.rb +88 -0
  65. data/test/{controller → activerecord}/active_record_assertions_test.rb +7 -50
  66. data/test/{controller → activerecord}/active_record_store_test.rb +27 -4
  67. data/test/activerecord/pagination_test.rb +161 -0
  68. data/test/controller/action_pack_assertions_test.rb +18 -15
  69. data/test/controller/base_test.rb +31 -42
  70. data/test/controller/benchmark_test.rb +8 -11
  71. data/test/controller/capture_test.rb +33 -1
  72. data/test/controller/cgi_test.rb +33 -0
  73. data/test/controller/custom_handler_test.rb +8 -0
  74. data/test/controller/fake_controllers.rb +9 -17
  75. data/test/controller/filters_test.rb +32 -3
  76. data/test/controller/flash_test.rb +26 -41
  77. data/test/controller/fragment_store_setting_test.rb +1 -1
  78. data/test/controller/layout_test.rb +73 -0
  79. data/test/controller/mime_responds_test.rb +257 -0
  80. data/test/controller/mime_type_test.rb +24 -0
  81. data/test/controller/new_render_test.rb +157 -1
  82. data/test/controller/redirect_test.rb +23 -0
  83. data/test/controller/render_test.rb +54 -56
  84. data/test/controller/request_test.rb +25 -0
  85. data/test/controller/routing_test.rb +74 -66
  86. data/test/controller/test_test.rb +66 -1
  87. data/test/controller/verification_test.rb +3 -1
  88. data/test/controller/webservice_test.rb +255 -0
  89. data/test/fixtures/companies.yml +24 -0
  90. data/test/fixtures/company.rb +9 -0
  91. data/test/fixtures/db_definitions/sqlite.sql +42 -0
  92. data/test/fixtures/developer.rb +7 -0
  93. data/test/fixtures/developers.yml +21 -0
  94. data/test/fixtures/developers_projects.yml +13 -0
  95. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
  96. data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
  97. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
  98. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
  99. data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
  100. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  101. data/test/fixtures/project.rb +3 -0
  102. data/test/fixtures/projects.yml +7 -0
  103. data/test/fixtures/replies.yml +13 -0
  104. data/test/fixtures/reply.rb +5 -0
  105. data/test/fixtures/respond_to/all_types_with_layout.rhtml +1 -0
  106. data/test/fixtures/respond_to/all_types_with_layout.rjs +1 -0
  107. data/test/fixtures/respond_to/layouts/standard.rhtml +1 -0
  108. data/test/fixtures/respond_to/using_defaults.rhtml +1 -0
  109. data/test/fixtures/respond_to/using_defaults.rjs +1 -0
  110. data/test/fixtures/respond_to/using_defaults.rxml +1 -0
  111. data/test/fixtures/respond_to/using_defaults_with_type_list.rhtml +1 -0
  112. data/test/fixtures/respond_to/using_defaults_with_type_list.rjs +1 -0
  113. data/test/fixtures/respond_to/using_defaults_with_type_list.rxml +1 -0
  114. data/test/fixtures/test/block_content_for.rhtml +2 -0
  115. data/test/fixtures/test/delete_with_js.rjs +2 -0
  116. data/test/fixtures/test/dot.directory/render_file_with_ivar.rhtml +1 -0
  117. data/test/fixtures/test/enum_rjs_test.rjs +6 -0
  118. data/test/fixtures/test/erb_content_for.rhtml +2 -0
  119. data/test/fixtures/test/hello_world.rxml +3 -0
  120. data/test/fixtures/test/hello_world_with_layout_false.rhtml +1 -0
  121. data/test/fixtures/test/non_erb_block_content_for.rxml +4 -0
  122. data/test/fixtures/topic.rb +3 -0
  123. data/test/fixtures/topics.yml +22 -0
  124. data/test/template/active_record_helper_test.rb +4 -0
  125. data/test/template/asset_tag_helper_test.rb +7 -2
  126. data/test/template/date_helper_test.rb +39 -2
  127. data/test/template/form_helper_test.rb +238 -5
  128. data/test/template/form_options_helper_test.rb +78 -0
  129. data/test/template/form_tag_helper_test.rb +11 -0
  130. data/test/template/java_script_macros_helper_test.rb +51 -6
  131. data/test/template/javascript_helper_test.rb +7 -153
  132. data/test/template/number_helper_test.rb +14 -13
  133. data/test/template/prototype_helper_test.rb +423 -0
  134. data/test/template/scriptaculous_helper_test.rb +90 -0
  135. data/test/template/text_helper_test.rb +12 -9
  136. data/test/template/url_helper_test.rb +31 -15
  137. metadata +291 -246
  138. data/lib/action_controller/cgi_ext/multipart_progress.rb +0 -169
  139. data/lib/action_controller/upload_progress.rb +0 -473
  140. data/lib/action_controller/vendor/html-scanner/html/node.rb.rej +0 -17
  141. data/lib/action_view/helpers/upload_progress_helper.rb +0 -433
  142. data/lib/action_view/vendor/builder.rb +0 -13
  143. data/lib/action_view/vendor/builder/blankslate.rb +0 -53
  144. data/lib/action_view/vendor/builder/xmlbase.rb +0 -143
  145. data/lib/action_view/vendor/builder/xmlevents.rb +0 -63
  146. data/lib/action_view/vendor/builder/xmlmarkup.rb +0 -308
  147. data/test/controller/multipart_progress_testx.rb +0 -365
  148. data/test/controller/upload_progress_testx.rb +0 -89
  149. data/test/template/upload_progress_helper_testx.rb +0 -136
@@ -71,6 +71,7 @@ module ActionController
71
71
  :order => nil,
72
72
  :join => nil,
73
73
  :joins => nil,
74
+ :count => nil,
74
75
  :include => nil,
75
76
  :select => nil,
76
77
  :parameter => 'page'
@@ -119,6 +120,10 @@ module ActionController
119
120
  # and Model.count
120
121
  # <tt>:include</tt>:: optional eager loading parameter passed to Model.find(:all, *params)
121
122
  # and Model.count
123
+ # <tt>:select</tt>:: :select parameter passed to Model.find(:all, *params)
124
+ #
125
+ # <tt>:count</tt>:: parameter passed as :select option to Model.count(*params)
126
+ #
122
127
  def paginate(collection_id, options={})
123
128
  Pagination.validate_options!(collection_id, options, true)
124
129
  paginator_and_collection_for(collection_id, options)
@@ -163,10 +168,13 @@ module ActionController
163
168
  # Returns the total number of items in the collection to be paginated for
164
169
  # the +model+ and given +conditions+. Override this method to implement a
165
170
  # custom counter.
166
- def count_collection_for_pagination(model, conditions, joins)
167
- model.count(conditions,joins)
171
+ def count_collection_for_pagination(model, options)
172
+ model.count(:conditions => options[:conditions],
173
+ :joins => options[:join] || options[:joins],
174
+ :include => options[:include],
175
+ :select => options[:count])
168
176
  end
169
-
177
+
170
178
  # Returns a collection of items for the given +model+ and +options[conditions]+,
171
179
  # ordered by +options[order]+, for the current page in the given +paginator+.
172
180
  # Override this method to implement a custom finder.
@@ -185,12 +193,10 @@ module ActionController
185
193
  def paginator_and_collection_for(collection_id, options) #:nodoc:
186
194
  klass = options[:class_name].constantize
187
195
  page = @params[options[:parameter]]
188
- count = count_collection_for_pagination(klass, options[:conditions],
189
- options[:join] || options[:joins])
190
-
196
+ count = count_collection_for_pagination(klass, options)
191
197
  paginator = Paginator.new(self, count, options[:per_page], page)
192
198
  collection = find_collection_for_pagination(klass, options, paginator)
193
-
199
+
194
200
  return paginator, collection
195
201
  end
196
202
 
@@ -3,14 +3,18 @@ module ActionController
3
3
  class AbstractRequest
4
4
  cattr_accessor :relative_url_root
5
5
 
6
+ # Returns the hash of environment variables for this request,
7
+ # such as { 'RAILS_ENV' => 'production' }.
8
+ attr_reader :env
9
+
6
10
  # Returns both GET and POST parameters in a single hash.
7
11
  def parameters
8
- @parameters ||= request_parameters.merge(query_parameters).merge(path_parameters).with_indifferent_access
12
+ @parameters ||= request_parameters.update(query_parameters).update(path_parameters).with_indifferent_access
9
13
  end
10
14
 
11
15
  # Returns the HTTP request method as a lowercase symbol (:get, for example)
12
16
  def method
13
- env['REQUEST_METHOD'].downcase.to_sym
17
+ @request_method ||= @env['REQUEST_METHOD'].downcase.to_sym
14
18
  end
15
19
 
16
20
  # Is this a GET request? Equivalent to request.method == :get
@@ -38,51 +42,43 @@ module ActionController
38
42
  method == :head
39
43
  end
40
44
 
41
- # Determine whether the body of a POST request is URL-encoded (default),
42
- # XML, or YAML by checking the Content-Type HTTP header:
43
- #
44
- # Content-Type Post Format
45
- # application/xml :xml
46
- # text/xml :xml
47
- # application/x-yaml :yaml
48
- # text/x-yaml :yaml
49
- # * :url_encoded
45
+ # Determine whether the body of a HTTP call is URL-encoded (default)
46
+ # or matches one of the registered param_parsers.
50
47
  #
51
48
  # For backward compatibility, the post format is extracted from the
52
49
  # X-Post-Data-Format HTTP header if present.
53
- def post_format
54
- @post_format ||=
55
- if env['HTTP_X_POST_DATA_FORMAT']
56
- env['HTTP_X_POST_DATA_FORMAT'].downcase.to_sym
57
- else
58
- case env['CONTENT_TYPE'].to_s.downcase
59
- when 'application/xml', 'text/xml' then :xml
60
- when 'application/x-yaml', 'text/x-yaml' then :yaml
61
- else :url_encoded
62
- end
63
- end
64
- end
65
-
66
- # Is this a POST request formatted as XML or YAML?
67
- def formatted_post?
68
- post? && (post_format == :xml || post_format == :yaml)
69
- end
70
-
71
- # Is this a POST request formatted as XML?
72
- def xml_post?
73
- post? && post_format == :xml
50
+ def content_type
51
+ @content_type ||=
52
+ begin
53
+ content_type = @env['CONTENT_TYPE'].to_s.downcase
54
+
55
+ if x_post_format = @env['HTTP_X_POST_DATA_FORMAT']
56
+ case x_post_format.to_s.downcase
57
+ when 'yaml'
58
+ content_type = 'application/x-yaml'
59
+ when 'xml'
60
+ content_type = 'application/xml'
61
+ end
62
+ end
63
+
64
+ Mime::Type.lookup(content_type)
65
+ end
74
66
  end
75
67
 
76
- # Is this a POST request formatted as YAML?
77
- def yaml_post?
78
- post? && post_format == :yaml
68
+ def accepts
69
+ @accepts ||=
70
+ if @env['HTTP_ACCEPT'].to_s.strip.empty?
71
+ [ content_type, Mime::ALL ]
72
+ else
73
+ Mime::Type.parse(@env['HTTP_ACCEPT'])
74
+ end
79
75
  end
80
76
 
81
77
  # Returns true if the request's "X-Requested-With" header contains
82
78
  # "XMLHttpRequest". (The Prototype Javascript library sends this header with
83
79
  # every Ajax request.)
84
80
  def xml_http_request?
85
- not /XMLHttpRequest/i.match(env['HTTP_X_REQUESTED_WITH']).nil?
81
+ not /XMLHttpRequest/i.match(@env['HTTP_X_REQUESTED_WITH']).nil?
86
82
  end
87
83
  alias xhr? :xml_http_request?
88
84
 
@@ -93,17 +89,17 @@ module ActionController
93
89
  # delimited list in the case of multiple chained proxies; the first is
94
90
  # the originating IP.
95
91
  def remote_ip
96
- return env['HTTP_CLIENT_IP'] if env.include? 'HTTP_CLIENT_IP'
92
+ return @env['HTTP_CLIENT_IP'] if @env.include? 'HTTP_CLIENT_IP'
97
93
 
98
- if env.include? 'HTTP_X_FORWARDED_FOR' then
99
- remote_ips = env['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
94
+ if @env.include? 'HTTP_X_FORWARDED_FOR' then
95
+ remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
100
96
  ip =~ /^unknown$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
101
97
  end
102
98
 
103
99
  return remote_ips.first.strip unless remote_ips.empty?
104
100
  end
105
101
 
106
- env['REMOTE_ADDR']
102
+ @env['REMOTE_ADDR']
107
103
  end
108
104
 
109
105
  # Returns the domain part of a host, such as rubyonrails.org in "www.rubyonrails.org". You can specify
@@ -127,19 +123,19 @@ module ActionController
127
123
  # This is useful for services such as REST, XMLRPC and SOAP
128
124
  # which communicate over HTTP POST but don't use the traditional parameter format.
129
125
  def raw_post
130
- env['RAW_POST_DATA']
126
+ @env['RAW_POST_DATA']
131
127
  end
132
128
 
133
129
  # Returns the request URI correctly, taking into account the idiosyncracies
134
130
  # of the various servers.
135
131
  def request_uri
136
- if uri = env['REQUEST_URI']
132
+ if uri = @env['REQUEST_URI']
137
133
  (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri # Remove domain, which webrick puts into the request_uri.
138
134
  else # REQUEST_URI is blank under IIS - get this from PATH_INFO and SCRIPT_NAME
139
- script_filename = env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
140
- uri = env['PATH_INFO']
135
+ script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
136
+ uri = @env['PATH_INFO']
141
137
  uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil?
142
- unless (env_qs = env['QUERY_STRING']).nil? || env_qs.empty?
138
+ unless (env_qs = @env['QUERY_STRING']).nil? || env_qs.empty?
143
139
  uri << '?' << env_qs
144
140
  end
145
141
  uri
@@ -153,7 +149,7 @@ module ActionController
153
149
 
154
150
  # Is this an SSL request?
155
151
  def ssl?
156
- env['HTTPS'] == 'on'
152
+ @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
157
153
  end
158
154
 
159
155
  # Returns the interpreted path to requested resource after all the installation directory of this application was taken into account
@@ -167,15 +163,23 @@ module ActionController
167
163
  end
168
164
 
169
165
  # Returns the path minus the web server relative installation directory.
170
- # This method returns nil unless the web server is apache.
166
+ # This can be set with the environment variable RAILS_RELATIVE_URL_ROOT.
167
+ # It can be automatically extracted for Apache setups. If the server is not
168
+ # Apache, this method returns an empty string.
171
169
  def relative_url_root
172
- @@relative_url_root ||= server_software == 'apache' ? env["SCRIPT_NAME"].to_s.sub(/\/dispatch\.(fcgi|rb|cgi)$/, '') : ''
173
-
170
+ @@relative_url_root ||= case
171
+ when @env["RAILS_RELATIVE_URL_ROOT"]
172
+ @env["RAILS_RELATIVE_URL_ROOT"]
173
+ when server_software == 'apache'
174
+ @env["SCRIPT_NAME"].to_s.sub(/\/dispatch\.(fcgi|rb|cgi)$/, '')
175
+ else
176
+ ''
177
+ end
174
178
  end
175
179
 
176
180
  # Returns the port number of this request as an integer.
177
181
  def port
178
- @port_as_int ||= env['SERVER_PORT'].to_i
182
+ @port_as_int ||= @env['SERVER_PORT'].to_i
179
183
  end
180
184
 
181
185
  # Returns the standard port number for this request's protocol
@@ -213,7 +217,7 @@ module ActionController
213
217
 
214
218
  # Returns the lowercase name of the HTTP server software.
215
219
  def server_software
216
- (env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ env['SERVER_SOFTWARE']) ? $1.downcase : nil
220
+ (@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
217
221
  end
218
222
 
219
223
  #--
@@ -225,11 +229,6 @@ module ActionController
225
229
  def request_parameters #:nodoc:
226
230
  end
227
231
 
228
- # Returns the hash of environment variables for this request,
229
- # such as { 'RAILS_ENV' => 'production' }.
230
- def env
231
- end
232
-
233
232
  # Returns the host for this request, such as example.com.
234
233
  def host
235
234
  end
@@ -240,6 +239,10 @@ module ActionController
240
239
  def session #:nodoc:
241
240
  end
242
241
 
242
+ def session=(session) #:nodoc:
243
+ @session = session
244
+ end
245
+
243
246
  def reset_session #:nodoc:
244
247
  end
245
248
  end
@@ -60,7 +60,7 @@ module ActionController #:nodoc:
60
60
  # the remote IP being 127.0.0.1. For example, this could include the IP of the developer machine when debugging
61
61
  # remotely.
62
62
  def local_request? #:doc:
63
- @request.remote_addr == "127.0.0.1"
63
+ [@request.remote_addr, @request.remote_ip] == ["127.0.0.1"] * 2
64
64
  end
65
65
 
66
66
  # Renders a detailed diagnostics screen on action exceptions.
@@ -100,6 +100,7 @@ module ActionController
100
100
 
101
101
  def initialize(key, options = {})
102
102
  @key = key.to_sym
103
+ @optional = false
103
104
  default, @condition = options[:default], options[:condition]
104
105
  self.default = default if options.key?(:default)
105
106
  end
@@ -214,26 +215,45 @@ module ActionController
214
215
 
215
216
  class << self
216
217
  def assign_controller(g, controller)
217
- expr = "::Controllers::#{controller.split('/').collect {|c| c.camelize}.join('::')}Controller"
218
+ expr = "::#{controller.split('/').collect {|c| c.camelize}.join('::')}Controller"
218
219
  g.result :controller, expr, true
219
220
  end
220
221
 
221
222
  def traverse_to_controller(segments, start_at = 0)
222
- mod = ::Controllers
223
+ mod = ::Object
223
224
  length = segments.length
224
225
  index = start_at
225
226
  mod_name = controller_name = segment = nil
226
-
227
+
227
228
  while index < length
228
229
  return nil unless /^[A-Za-z][A-Za-z\d_]*$/ =~ (segment = segments[index])
229
230
  index += 1
230
-
231
+
231
232
  mod_name = segment.camelize
232
233
  controller_name = "#{mod_name}Controller"
233
-
234
- return eval("mod::#{controller_name}", nil, 'routing.rb', __LINE__), (index - start_at) if mod.const_available?(controller_name)
235
- return nil unless mod.const_available?(mod_name)
236
- mod = eval("mod::#{mod_name}", nil, 'routing.rb', __LINE__)
234
+
235
+ begin
236
+ # We use eval instead of const_get to avoid obtaining values from parent modules.
237
+ controller = eval("mod::#{controller_name}", nil, __FILE__, __LINE__)
238
+ expected_name = "#{mod.name}::#{controller_name}"
239
+
240
+ # Detect the case when const_get returns an object from a parent namespace.
241
+ if controller.is_a?(Class) && controller.ancestors.include?(ActionController::Base) && (mod == Object || controller.name == expected_name)
242
+ return controller, (index - start_at)
243
+ end
244
+ rescue NameError => e
245
+ raise unless /^uninitialized constant .*#{controller_name}$/ =~ e.message
246
+ end
247
+
248
+ begin
249
+ next_mod = eval("mod::#{mod_name}", nil, __FILE__, __LINE__)
250
+ # Check that we didn't get a module from a parent namespace
251
+ mod = (mod == Object || next_mod.name == "#{mod.name}::#{mod_name}") ? next_mod : nil
252
+ rescue NameError => e
253
+ raise unless /^uninitialized constant .*#{mod_name}$/ =~ e.message
254
+ end
255
+
256
+ return nil unless mod
237
257
  end
238
258
  end
239
259
  end
@@ -442,7 +462,6 @@ module ActionController
442
462
  @generation_methods[controller.to_sym] = method_name
443
463
  end
444
464
 
445
-
446
465
  code = generation_code_for('routes', 'generate_default_path').to_s
447
466
  eval(code, nil, 'generated_code/routing/generation.rb')
448
467
 
@@ -479,7 +498,7 @@ module ActionController
479
498
  route.write_recognition(g)
480
499
  end
481
500
  end
482
-
501
+
483
502
  eval g.to_s, nil, 'generated/routing/recognition.rb'
484
503
  return g.to_s
485
504
  end
@@ -17,6 +17,9 @@ module ActionController
17
17
  # This tiny piece of code will add all of the following methods to the controller:
18
18
  #
19
19
  # class WeblogController < ActionController::Base
20
+ # verify :method => :post, :only => [ :destroy, :create, :update ],
21
+ # :redirect_to => { :action => :list }
22
+ #
20
23
  # def index
21
24
  # list
22
25
  # end
@@ -98,6 +101,11 @@ module ActionController
98
101
  end
99
102
 
100
103
  module_eval <<-"end_eval", __FILE__, __LINE__
104
+
105
+ verify :method => :post, :only => [ :destroy#{suffix}, :create#{suffix}, :update#{suffix} ],
106
+ :redirect_to => { :action => :list#{suffix} }
107
+
108
+
101
109
  def list#{suffix}
102
110
  @#{singular_name}_pages, @#{plural_name} = paginate :#{plural_name}, :per_page => 10
103
111
  render#{suffix}_scaffold "list#{suffix}"
@@ -59,10 +59,8 @@ class CGI
59
59
  cattr_accessor :data_column_name
60
60
  self.data_column_name = 'data'
61
61
 
62
- # Don't try to save if we haven't loaded the session.
63
- before_update :loaded?
64
- before_save :marshal_data!
65
- before_save :raise_on_session_data_overflow!
62
+ before_save :marshal_data!
63
+ before_save :raise_on_session_data_overflow!
66
64
 
67
65
  class << self
68
66
  # Don't try to reload ARStore::Session in dev mode.
@@ -122,22 +120,24 @@ class CGI
122
120
  @data ||= self.class.unmarshal(read_attribute(@@data_column_name)) || {}
123
121
  end
124
122
 
123
+ # Has the session been loaded yet?
124
+ def loaded?
125
+ !! @data
126
+ end
127
+
125
128
  private
126
129
  attr_writer :data
127
130
 
128
131
  def marshal_data!
132
+ return false if !loaded?
129
133
  write_attribute(@@data_column_name, self.class.marshal(self.data))
130
134
  end
131
135
 
132
- # Has the session been loaded yet?
133
- def loaded?
134
- !! @data
135
- end
136
-
137
136
  # Ensures that the data about to be stored in the database is not
138
137
  # larger than the data storage column. Raises
139
138
  # ActionController::SessionOverflowError.
140
139
  def raise_on_session_data_overflow!
140
+ return false if !loaded?
141
141
  limit = self.class.data_column_size_limit
142
142
  if loaded? and limit and read_attribute(@@data_column_name).size > limit
143
143
  raise ActionController::SessionOverflowError
@@ -232,7 +232,12 @@ class CGI
232
232
  @data
233
233
  end
234
234
 
235
+ def loaded?
236
+ !! @data
237
+ end
238
+
235
239
  def save
240
+ return false if !loaded?
236
241
  marshaled_data = self.class.marshal(data)
237
242
 
238
243
  if @new_record
@@ -278,7 +283,9 @@ class CGI
278
283
  raise CGI::Session::NoSession, 'uninitialized session'
279
284
  end
280
285
  @session = @@session_class.new(:session_id => session_id, :data => {})
281
- @session.save
286
+ # session saving can be lazy again, because of improved component implementation
287
+ # therefore next line gets commented out:
288
+ # @session.save
282
289
  end
283
290
  end
284
291
 
@@ -317,6 +324,10 @@ class CGI
317
324
  end
318
325
  end
319
326
 
327
+ protected
328
+ def logger
329
+ ActionController::Base.logger rescue nil
330
+ end
320
331
  end
321
332
  end
322
333
  end
@@ -25,30 +25,38 @@ begin
25
25
 
26
26
  # Create a new CGI::Session::MemCache instance
27
27
  #
28
- # This constructor is used internally by CGI::Session. The
28
+ # This constructor is used internally by CGI::Session. The
29
29
  # user does not generally need to call it directly.
30
30
  #
31
31
  # +session+ is the session for which this instance is being
32
- # created. The session id must only contain alphanumeric
32
+ # created. The session id must only contain alphanumeric
33
33
  # characters; automatically generated session ids observe
34
34
  # this requirement.
35
35
  #
36
- # +option+ is a hash of options for the initializer. The
36
+ # +options+ is a hash of options for the initializer. The
37
37
  # following options are recognized:
38
38
  #
39
39
  # cache:: an instance of a MemCache client to use as the
40
40
  # session cache.
41
41
  #
42
+ # expires:: an expiry time value to use for session entries in
43
+ # the session cache. +expires+ is interpreted in seconds
44
+ # relative to the current time if it�s less than 60*60*24*30
45
+ # (30 days), or as an absolute Unix time (e.g., Time#to_i) if
46
+ # greater. If +expires+ is +0+, or not passed on +options+,
47
+ # the entry will never expire.
48
+ #
42
49
  # This session's memcache entry will be created if it does
43
50
  # not exist, or retrieved if it does.
44
51
  def initialize(session, options = {})
45
52
  id = session.session_id
46
53
  unless check_id(id)
47
54
  raise ArgumentError, "session_id '%s' is invalid" % id
48
- end
55
+ end
49
56
  @cache = options['cache'] || MemCache.new('localhost')
50
- @session_key = "session:#{id}"
51
- @hash = {}
57
+ @expires = options['expires'] || 0
58
+ @session_key = "session:#{id}"
59
+ @session_data = {}
52
60
  end
53
61
 
54
62
  # Restore session state from the session's memcache entry.
@@ -56,18 +64,16 @@ begin
56
64
  # Returns the session state as a hash.
57
65
  def restore
58
66
  begin
59
- @hash = @cache[@session_key]
67
+ @session_data = @cache[@session_key] || {}
60
68
  rescue
61
- # Ignore session get failures.
69
+ @session_data = {}
62
70
  end
63
- @hash = {} unless @hash
64
- @hash
65
71
  end
66
72
 
67
73
  # Save session state to the session's memcache entry.
68
74
  def update
69
75
  begin
70
- @cache[@session_key] = @hash
76
+ @cache.set(@session_key, @session_data, @expires)
71
77
  rescue
72
78
  # Ignore session update failures.
73
79
  end
@@ -85,7 +91,7 @@ begin
85
91
  rescue
86
92
  # Ignore session delete failures.
87
93
  end
88
- @hash = {}
94
+ @session_data = {}
89
95
  end
90
96
  end
91
97
  end