actionpack 2.2.3 → 2.3.2

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 (264) hide show
  1. data/CHANGELOG +433 -375
  2. data/MIT-LICENSE +1 -1
  3. data/README +21 -75
  4. data/Rakefile +1 -1
  5. data/lib/action_controller.rb +80 -43
  6. data/lib/action_controller/assertions/model_assertions.rb +1 -0
  7. data/lib/action_controller/assertions/response_assertions.rb +43 -16
  8. data/lib/action_controller/assertions/routing_assertions.rb +1 -1
  9. data/lib/action_controller/assertions/selector_assertions.rb +17 -12
  10. data/lib/action_controller/assertions/tag_assertions.rb +1 -4
  11. data/lib/action_controller/base.rb +153 -82
  12. data/lib/action_controller/benchmarking.rb +9 -9
  13. data/lib/action_controller/caching.rb +9 -11
  14. data/lib/action_controller/caching/actions.rb +11 -18
  15. data/lib/action_controller/caching/fragments.rb +28 -20
  16. data/lib/action_controller/caching/pages.rb +13 -15
  17. data/lib/action_controller/caching/sweeping.rb +2 -2
  18. data/lib/action_controller/cgi_ext.rb +0 -1
  19. data/lib/action_controller/cgi_ext/cookie.rb +2 -0
  20. data/lib/action_controller/cgi_process.rb +54 -162
  21. data/lib/action_controller/cookies.rb +13 -25
  22. data/lib/action_controller/dispatcher.rb +43 -122
  23. data/lib/action_controller/failsafe.rb +52 -0
  24. data/lib/action_controller/flash.rb +38 -47
  25. data/lib/action_controller/helpers.rb +13 -9
  26. data/lib/action_controller/http_authentication.rb +203 -23
  27. data/lib/action_controller/integration.rb +126 -70
  28. data/lib/action_controller/layout.rb +36 -39
  29. data/lib/action_controller/middleware_stack.rb +119 -0
  30. data/lib/action_controller/middlewares.rb +13 -0
  31. data/lib/action_controller/mime_responds.rb +19 -4
  32. data/lib/action_controller/mime_type.rb +8 -0
  33. data/lib/action_controller/params_parser.rb +71 -0
  34. data/lib/action_controller/performance_test.rb +0 -1
  35. data/lib/action_controller/polymorphic_routes.rb +36 -30
  36. data/lib/action_controller/reloader.rb +14 -0
  37. data/lib/action_controller/request.rb +107 -499
  38. data/lib/action_controller/request_forgery_protection.rb +7 -39
  39. data/lib/action_controller/rescue.rb +55 -35
  40. data/lib/action_controller/resources.rb +34 -31
  41. data/lib/action_controller/response.rb +99 -57
  42. data/lib/action_controller/rewindable_input.rb +28 -0
  43. data/lib/action_controller/routing.rb +7 -7
  44. data/lib/action_controller/routing/builder.rb +4 -1
  45. data/lib/action_controller/routing/optimisations.rb +1 -1
  46. data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
  47. data/lib/action_controller/routing/route.rb +15 -5
  48. data/lib/action_controller/routing/route_set.rb +82 -35
  49. data/lib/action_controller/routing/segments.rb +35 -0
  50. data/lib/action_controller/session/abstract_store.rb +181 -0
  51. data/lib/action_controller/session/cookie_store.rb +197 -175
  52. data/lib/action_controller/session/mem_cache_store.rb +36 -83
  53. data/lib/action_controller/session_management.rb +26 -134
  54. data/lib/action_controller/streaming.rb +24 -7
  55. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  56. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  57. data/lib/action_controller/test_case.rb +87 -30
  58. data/lib/action_controller/test_process.rb +145 -104
  59. data/lib/action_controller/uploaded_file.rb +44 -0
  60. data/lib/action_controller/url_rewriter.rb +3 -6
  61. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  62. data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
  63. data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
  64. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
  65. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
  66. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
  67. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
  68. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
  69. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
  73. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
  74. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
  75. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
  76. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
  77. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
  78. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
  79. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
  80. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
  81. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
  82. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
  83. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
  84. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
  85. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
  86. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
  87. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
  93. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
  94. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
  95. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
  96. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
  97. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
  98. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
  99. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
  100. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
  101. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
  102. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
  103. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
  104. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
  105. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
  106. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
  107. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
  108. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
  109. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
  110. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
  111. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
  112. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
  113. data/lib/action_controller/verification.rb +1 -1
  114. data/lib/action_pack.rb +1 -1
  115. data/lib/action_pack/version.rb +2 -2
  116. data/lib/action_view.rb +22 -17
  117. data/lib/action_view/base.rb +53 -79
  118. data/lib/action_view/erb/util.rb +38 -0
  119. data/lib/action_view/helpers.rb +24 -5
  120. data/lib/action_view/helpers/active_record_helper.rb +2 -2
  121. data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
  122. data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
  123. data/lib/action_view/helpers/benchmark_helper.rb +26 -5
  124. data/lib/action_view/helpers/date_helper.rb +82 -7
  125. data/lib/action_view/helpers/form_helper.rb +295 -64
  126. data/lib/action_view/helpers/form_options_helper.rb +160 -18
  127. data/lib/action_view/helpers/form_tag_helper.rb +2 -2
  128. data/lib/action_view/helpers/number_helper.rb +31 -18
  129. data/lib/action_view/helpers/prototype_helper.rb +2 -12
  130. data/lib/action_view/helpers/sanitize_helper.rb +0 -10
  131. data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
  132. data/lib/action_view/helpers/tag_helper.rb +3 -4
  133. data/lib/action_view/helpers/text_helper.rb +99 -122
  134. data/lib/action_view/helpers/translation_helper.rb +19 -1
  135. data/lib/action_view/helpers/url_helper.rb +25 -2
  136. data/lib/action_view/inline_template.rb +1 -1
  137. data/lib/action_view/locale/en.yml +19 -1
  138. data/lib/action_view/partials.rb +46 -9
  139. data/lib/action_view/paths.rb +28 -84
  140. data/lib/action_view/reloadable_template.rb +117 -0
  141. data/lib/action_view/renderable.rb +28 -35
  142. data/lib/action_view/renderable_partial.rb +3 -4
  143. data/lib/action_view/template.rb +172 -31
  144. data/lib/action_view/template_error.rb +8 -9
  145. data/lib/action_view/template_handler.rb +1 -1
  146. data/lib/action_view/template_handlers.rb +9 -6
  147. data/lib/action_view/template_handlers/erb.rb +2 -39
  148. data/lib/action_view/template_handlers/rjs.rb +1 -0
  149. data/lib/action_view/test_case.rb +27 -1
  150. data/test/abstract_unit.rb +23 -17
  151. data/test/active_record_unit.rb +5 -4
  152. data/test/activerecord/active_record_store_test.rb +139 -106
  153. data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
  154. data/test/controller/action_pack_assertions_test.rb +25 -23
  155. data/test/controller/addresses_render_test.rb +3 -6
  156. data/test/controller/assert_select_test.rb +83 -70
  157. data/test/controller/base_test.rb +11 -13
  158. data/test/controller/benchmark_test.rb +3 -3
  159. data/test/controller/caching_test.rb +34 -24
  160. data/test/controller/capture_test.rb +3 -6
  161. data/test/controller/content_type_test.rb +3 -6
  162. data/test/controller/cookie_test.rb +31 -66
  163. data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
  164. data/test/controller/dispatcher_test.rb +23 -28
  165. data/test/controller/fake_models.rb +8 -0
  166. data/test/controller/filters_test.rb +6 -2
  167. data/test/controller/flash_test.rb +2 -6
  168. data/test/controller/helper_test.rb +15 -1
  169. data/test/controller/html-scanner/document_test.rb +1 -1
  170. data/test/controller/html-scanner/sanitizer_test.rb +1 -1
  171. data/test/controller/http_basic_authentication_test.rb +88 -0
  172. data/test/controller/http_digest_authentication_test.rb +178 -0
  173. data/test/controller/integration_test.rb +56 -52
  174. data/test/controller/layout_test.rb +46 -44
  175. data/test/controller/middleware_stack_test.rb +90 -0
  176. data/test/controller/mime_responds_test.rb +7 -11
  177. data/test/controller/mime_type_test.rb +9 -0
  178. data/test/controller/polymorphic_routes_test.rb +235 -151
  179. data/test/controller/rack_test.rb +52 -81
  180. data/test/controller/redirect_test.rb +6 -14
  181. data/test/controller/render_test.rb +273 -60
  182. data/test/controller/request/json_params_parsing_test.rb +45 -0
  183. data/test/controller/request/multipart_params_parsing_test.rb +223 -0
  184. data/test/controller/request/query_string_parsing_test.rb +120 -0
  185. data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
  186. data/test/controller/request/xml_params_parsing_test.rb +88 -0
  187. data/test/controller/request_forgery_protection_test.rb +17 -98
  188. data/test/controller/request_test.rb +45 -530
  189. data/test/controller/rescue_test.rb +45 -22
  190. data/test/controller/resources_test.rb +112 -37
  191. data/test/controller/routing_test.rb +1442 -1384
  192. data/test/controller/selector_test.rb +3 -3
  193. data/test/controller/send_file_test.rb +30 -3
  194. data/test/controller/session/cookie_store_test.rb +169 -240
  195. data/test/controller/session/mem_cache_store_test.rb +94 -148
  196. data/test/controller/session/test_session_test.rb +58 -0
  197. data/test/controller/test_test.rb +32 -13
  198. data/test/controller/url_rewriter_test.rb +54 -4
  199. data/test/controller/verification_test.rb +1 -1
  200. data/test/controller/view_paths_test.rb +15 -15
  201. data/test/controller/webservice_test.rb +178 -147
  202. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  203. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  204. data/test/fixtures/layouts/default_html.html.erb +1 -0
  205. data/test/fixtures/layouts/xhr.html.erb +2 -0
  206. data/test/fixtures/multipart/empty +10 -0
  207. data/test/fixtures/multipart/hello.txt +1 -0
  208. data/test/fixtures/multipart/none +9 -0
  209. data/test/fixtures/public/500.da.html +1 -0
  210. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  211. data/test/fixtures/replies.yml +1 -1
  212. data/test/fixtures/test/_one.html.erb +1 -0
  213. data/test/fixtures/test/_two.html.erb +1 -0
  214. data/test/fixtures/test/dont_pick_me +1 -0
  215. data/test/fixtures/test/hello.builder +1 -1
  216. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  217. data/test/fixtures/test/hello_world.erb~ +1 -0
  218. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  219. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  220. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  221. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  222. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  223. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  224. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  225. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  226. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  227. data/test/fixtures/test/utf8.html.erb +2 -0
  228. data/test/template/active_record_helper_i18n_test.rb +31 -33
  229. data/test/template/active_record_helper_test.rb +34 -0
  230. data/test/template/asset_tag_helper_test.rb +52 -14
  231. data/test/template/atom_feed_helper_test.rb +3 -5
  232. data/test/template/benchmark_helper_test.rb +50 -24
  233. data/test/template/compiled_templates_test.rb +177 -33
  234. data/test/template/date_helper_i18n_test.rb +88 -81
  235. data/test/template/date_helper_test.rb +427 -43
  236. data/test/template/form_helper_test.rb +243 -44
  237. data/test/template/form_options_helper_test.rb +631 -565
  238. data/test/template/form_tag_helper_test.rb +9 -2
  239. data/test/template/javascript_helper_test.rb +0 -5
  240. data/test/template/number_helper_i18n_test.rb +60 -48
  241. data/test/template/number_helper_test.rb +1 -0
  242. data/test/template/render_test.rb +117 -35
  243. data/test/template/test_test.rb +4 -6
  244. data/test/template/text_helper_test.rb +129 -50
  245. data/test/template/translation_helper_test.rb +23 -19
  246. data/test/template/url_helper_test.rb +35 -2
  247. data/test/view/test_case_test.rb +8 -0
  248. metadata +197 -23
  249. data/lib/action_controller/assertions.rb +0 -69
  250. data/lib/action_controller/caching/sql_cache.rb +0 -18
  251. data/lib/action_controller/cgi_ext/session.rb +0 -53
  252. data/lib/action_controller/components.rb +0 -169
  253. data/lib/action_controller/rack_process.rb +0 -297
  254. data/lib/action_controller/request_profiler.rb +0 -169
  255. data/lib/action_controller/session/active_record_store.rb +0 -340
  256. data/lib/action_controller/session/drb_server.rb +0 -32
  257. data/lib/action_controller/session/drb_store.rb +0 -35
  258. data/test/controller/cgi_test.rb +0 -269
  259. data/test/controller/components_test.rb +0 -156
  260. data/test/controller/http_authentication_test.rb +0 -54
  261. data/test/controller/integration_upload_test.rb +0 -43
  262. data/test/controller/session_fixation_test.rb +0 -89
  263. data/test/controller/session_management_test.rb +0 -178
  264. data/test/fixtures/test/hello_world.js +0 -1
@@ -1,169 +0,0 @@
1
- require 'optparse'
2
- require 'action_controller/integration'
3
-
4
- module ActionController
5
- class RequestProfiler
6
- # Wrap up the integration session runner.
7
- class Sandbox
8
- include Integration::Runner
9
-
10
- def self.benchmark(n, script)
11
- new(script).benchmark(n)
12
- end
13
-
14
- def initialize(script_path)
15
- @quiet = false
16
- define_run_method(script_path)
17
- reset!
18
- end
19
-
20
- def benchmark(n, profiling = false)
21
- @quiet = true
22
- print ' '
23
-
24
- result = Benchmark.realtime do
25
- n.times do |i|
26
- run(profiling)
27
- print_progress(i)
28
- end
29
- end
30
-
31
- puts
32
- result
33
- ensure
34
- @quiet = false
35
- end
36
-
37
- def say(message)
38
- puts " #{message}" unless @quiet
39
- end
40
-
41
- private
42
- def define_run_method(script_path)
43
- script = File.read(script_path)
44
-
45
- source = <<-end_source
46
- def run(profiling = false)
47
- if profiling
48
- RubyProf.resume do
49
- #{script}
50
- end
51
- else
52
- #{script}
53
- end
54
-
55
- old_request_count = request_count
56
- reset!
57
- self.request_count = old_request_count
58
- end
59
- end_source
60
-
61
- instance_eval source, script_path, 1
62
- end
63
-
64
- def print_progress(i)
65
- print "\n " if i % 60 == 0
66
- print ' ' if i % 10 == 0
67
- print '.'
68
- $stdout.flush
69
- end
70
- end
71
-
72
-
73
- attr_reader :options
74
-
75
- def initialize(options = {})
76
- @options = default_options.merge(options)
77
- end
78
-
79
-
80
- def self.run(args = nil, options = {})
81
- profiler = new(options)
82
- profiler.parse_options(args) if args
83
- profiler.run
84
- end
85
-
86
- def run
87
- sandbox = Sandbox.new(options[:script])
88
-
89
- puts 'Warming up once'
90
-
91
- elapsed = warmup(sandbox)
92
- puts '%.2f sec, %d requests, %d req/sec' % [elapsed, sandbox.request_count, sandbox.request_count / elapsed]
93
- puts "\n#{options[:benchmark] ? 'Benchmarking' : 'Profiling'} #{options[:n]}x"
94
-
95
- options[:benchmark] ? benchmark(sandbox) : profile(sandbox)
96
- end
97
-
98
- def profile(sandbox)
99
- load_ruby_prof
100
-
101
- benchmark(sandbox, true)
102
- results = RubyProf.stop
103
-
104
- show_profile_results results
105
- results
106
- end
107
-
108
- def benchmark(sandbox, profiling = false)
109
- sandbox.request_count = 0
110
- elapsed = sandbox.benchmark(options[:n], profiling).to_f
111
- count = sandbox.request_count.to_i
112
- puts '%.2f sec, %d requests, %d req/sec' % [elapsed, count, count / elapsed]
113
- end
114
-
115
- def warmup(sandbox)
116
- Benchmark.realtime { sandbox.run(false) }
117
- end
118
-
119
- def default_options
120
- { :n => 100, :open => 'open %s &' }
121
- end
122
-
123
- # Parse command-line options
124
- def parse_options(args)
125
- OptionParser.new do |opt|
126
- opt.banner = "USAGE: #{$0} [options] [session script path]"
127
-
128
- opt.on('-n', '--times [100]', 'How many requests to process. Defaults to 100.') { |v| options[:n] = v.to_i if v }
129
- opt.on('-b', '--benchmark', 'Benchmark instead of profiling') { |v| options[:benchmark] = v }
130
- opt.on('-m', '--measure [mode]', 'Which ruby-prof measure mode to use: process_time, wall_time, cpu_time, allocations, or memory. Defaults to process_time.') { |v| options[:measure] = v }
131
- opt.on('--open [CMD]', 'Command to open profile results. Defaults to "open %s &"') { |v| options[:open] = v }
132
- opt.on('-h', '--help', 'Show this help') { puts opt; exit }
133
-
134
- opt.parse args
135
-
136
- if args.empty?
137
- puts opt
138
- exit
139
- end
140
- options[:script] = args.pop
141
- end
142
- end
143
-
144
- protected
145
- def load_ruby_prof
146
- begin
147
- gem 'ruby-prof', '>= 0.6.1'
148
- require 'ruby-prof'
149
- if mode = options[:measure]
150
- RubyProf.measure_mode = RubyProf.const_get(mode.upcase)
151
- end
152
- rescue LoadError
153
- abort '`gem install ruby-prof` to use the profiler'
154
- end
155
- end
156
-
157
- def show_profile_results(results)
158
- File.open "#{RAILS_ROOT}/tmp/profile-graph.html", 'w' do |file|
159
- RubyProf::GraphHtmlPrinter.new(results).print(file)
160
- `#{options[:open] % file.path}` if options[:open]
161
- end
162
-
163
- File.open "#{RAILS_ROOT}/tmp/profile-flat.txt", 'w' do |file|
164
- RubyProf::FlatPrinter.new(results).print(file)
165
- `#{options[:open] % file.path}` if options[:open]
166
- end
167
- end
168
- end
169
- end
@@ -1,340 +0,0 @@
1
- require 'cgi'
2
- require 'cgi/session'
3
- require 'digest/md5'
4
-
5
- class CGI
6
- class Session
7
- attr_reader :data
8
-
9
- # Return this session's underlying Session instance. Useful for the DB-backed session stores.
10
- def model
11
- @dbman.model if @dbman
12
- end
13
-
14
-
15
- # A session store backed by an Active Record class. A default class is
16
- # provided, but any object duck-typing to an Active Record Session class
17
- # with text +session_id+ and +data+ attributes is sufficient.
18
- #
19
- # The default assumes a +sessions+ tables with columns:
20
- # +id+ (numeric primary key),
21
- # +session_id+ (text, or longtext if your session data exceeds 65K), and
22
- # +data+ (text or longtext; careful if your session data exceeds 65KB).
23
- # The +session_id+ column should always be indexed for speedy lookups.
24
- # Session data is marshaled to the +data+ column in Base64 format.
25
- # If the data you write is larger than the column's size limit,
26
- # ActionController::SessionOverflowError will be raised.
27
- #
28
- # You may configure the table name, primary key, and data column.
29
- # For example, at the end of <tt>config/environment.rb</tt>:
30
- # CGI::Session::ActiveRecordStore::Session.table_name = 'legacy_session_table'
31
- # CGI::Session::ActiveRecordStore::Session.primary_key = 'session_id'
32
- # CGI::Session::ActiveRecordStore::Session.data_column_name = 'legacy_session_data'
33
- # Note that setting the primary key to the +session_id+ frees you from
34
- # having a separate +id+ column if you don't want it. However, you must
35
- # set <tt>session.model.id = session.session_id</tt> by hand! A before filter
36
- # on ApplicationController is a good place.
37
- #
38
- # Since the default class is a simple Active Record, you get timestamps
39
- # for free if you add +created_at+ and +updated_at+ datetime columns to
40
- # the +sessions+ table, making periodic session expiration a snap.
41
- #
42
- # You may provide your own session class implementation, whether a
43
- # feature-packed Active Record or a bare-metal high-performance SQL
44
- # store, by setting
45
- # CGI::Session::ActiveRecordStore.session_class = MySessionClass
46
- # You must implement these methods:
47
- # self.find_by_session_id(session_id)
48
- # initialize(hash_of_session_id_and_data)
49
- # attr_reader :session_id
50
- # attr_accessor :data
51
- # save
52
- # destroy
53
- #
54
- # The example SqlBypass class is a generic SQL session store. You may
55
- # use it as a basis for high-performance database-specific stores.
56
- class ActiveRecordStore
57
- # The default Active Record class.
58
- class Session < ActiveRecord::Base
59
- # Customizable data column name. Defaults to 'data'.
60
- cattr_accessor :data_column_name
61
- self.data_column_name = 'data'
62
-
63
- before_save :marshal_data!
64
- before_save :raise_on_session_data_overflow!
65
-
66
- class << self
67
- # Don't try to reload ARStore::Session in dev mode.
68
- def reloadable? #:nodoc:
69
- false
70
- end
71
-
72
- def data_column_size_limit
73
- @data_column_size_limit ||= columns_hash[@@data_column_name].limit
74
- end
75
-
76
- # Hook to set up sessid compatibility.
77
- def find_by_session_id(session_id)
78
- setup_sessid_compatibility!
79
- find_by_session_id(session_id)
80
- end
81
-
82
- def marshal(data) ActiveSupport::Base64.encode64(Marshal.dump(data)) if data end
83
- def unmarshal(data) Marshal.load(ActiveSupport::Base64.decode64(data)) if data end
84
-
85
- def create_table!
86
- connection.execute <<-end_sql
87
- CREATE TABLE #{table_name} (
88
- id INTEGER PRIMARY KEY,
89
- #{connection.quote_column_name('session_id')} TEXT UNIQUE,
90
- #{connection.quote_column_name(@@data_column_name)} TEXT(255)
91
- )
92
- end_sql
93
- end
94
-
95
- def drop_table!
96
- connection.execute "DROP TABLE #{table_name}"
97
- end
98
-
99
- private
100
- # Compatibility with tables using sessid instead of session_id.
101
- def setup_sessid_compatibility!
102
- # Reset column info since it may be stale.
103
- reset_column_information
104
- if columns_hash['sessid']
105
- def self.find_by_session_id(*args)
106
- find_by_sessid(*args)
107
- end
108
-
109
- define_method(:session_id) { sessid }
110
- define_method(:session_id=) { |session_id| self.sessid = session_id }
111
- else
112
- def self.find_by_session_id(session_id)
113
- find :first, :conditions => ["session_id #{attribute_condition(session_id)}", session_id]
114
- end
115
- end
116
- end
117
- end
118
-
119
- # Lazy-unmarshal session state.
120
- def data
121
- @data ||= self.class.unmarshal(read_attribute(@@data_column_name)) || {}
122
- end
123
-
124
- attr_writer :data
125
-
126
- # Has the session been loaded yet?
127
- def loaded?
128
- !! @data
129
- end
130
-
131
- private
132
-
133
- def marshal_data!
134
- return false if !loaded?
135
- write_attribute(@@data_column_name, self.class.marshal(self.data))
136
- end
137
-
138
- # Ensures that the data about to be stored in the database is not
139
- # larger than the data storage column. Raises
140
- # ActionController::SessionOverflowError.
141
- def raise_on_session_data_overflow!
142
- return false if !loaded?
143
- limit = self.class.data_column_size_limit
144
- if loaded? and limit and read_attribute(@@data_column_name).size > limit
145
- raise ActionController::SessionOverflowError
146
- end
147
- end
148
- end
149
-
150
- # A barebones session store which duck-types with the default session
151
- # store but bypasses Active Record and issues SQL directly. This is
152
- # an example session model class meant as a basis for your own classes.
153
- #
154
- # The database connection, table name, and session id and data columns
155
- # are configurable class attributes. Marshaling and unmarshaling
156
- # are implemented as class methods that you may override. By default,
157
- # marshaling data is
158
- #
159
- # ActiveSupport::Base64.encode64(Marshal.dump(data))
160
- #
161
- # and unmarshaling data is
162
- #
163
- # Marshal.load(ActiveSupport::Base64.decode64(data))
164
- #
165
- # This marshaling behavior is intended to store the widest range of
166
- # binary session data in a +text+ column. For higher performance,
167
- # store in a +blob+ column instead and forgo the Base64 encoding.
168
- class SqlBypass
169
- # Use the ActiveRecord::Base.connection by default.
170
- cattr_accessor :connection
171
-
172
- # The table name defaults to 'sessions'.
173
- cattr_accessor :table_name
174
- @@table_name = 'sessions'
175
-
176
- # The session id field defaults to 'session_id'.
177
- cattr_accessor :session_id_column
178
- @@session_id_column = 'session_id'
179
-
180
- # The data field defaults to 'data'.
181
- cattr_accessor :data_column
182
- @@data_column = 'data'
183
-
184
- class << self
185
-
186
- def connection
187
- @@connection ||= ActiveRecord::Base.connection
188
- end
189
-
190
- # Look up a session by id and unmarshal its data if found.
191
- def find_by_session_id(session_id)
192
- if record = @@connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{@@connection.quote(session_id)}")
193
- new(:session_id => session_id, :marshaled_data => record['data'])
194
- end
195
- end
196
-
197
- def marshal(data) ActiveSupport::Base64.encode64(Marshal.dump(data)) if data end
198
- def unmarshal(data) Marshal.load(ActiveSupport::Base64.decode64(data)) if data end
199
-
200
- def create_table!
201
- @@connection.execute <<-end_sql
202
- CREATE TABLE #{table_name} (
203
- id INTEGER PRIMARY KEY,
204
- #{@@connection.quote_column_name(session_id_column)} TEXT UNIQUE,
205
- #{@@connection.quote_column_name(data_column)} TEXT
206
- )
207
- end_sql
208
- end
209
-
210
- def drop_table!
211
- @@connection.execute "DROP TABLE #{table_name}"
212
- end
213
- end
214
-
215
- attr_reader :session_id
216
- attr_writer :data
217
-
218
- # Look for normal and marshaled data, self.find_by_session_id's way of
219
- # telling us to postpone unmarshaling until the data is requested.
220
- # We need to handle a normal data attribute in case of a new record.
221
- def initialize(attributes)
222
- @session_id, @data, @marshaled_data = attributes[:session_id], attributes[:data], attributes[:marshaled_data]
223
- @new_record = @marshaled_data.nil?
224
- end
225
-
226
- def new_record?
227
- @new_record
228
- end
229
-
230
- # Lazy-unmarshal session state.
231
- def data
232
- unless @data
233
- if @marshaled_data
234
- @data, @marshaled_data = self.class.unmarshal(@marshaled_data) || {}, nil
235
- else
236
- @data = {}
237
- end
238
- end
239
- @data
240
- end
241
-
242
- def loaded?
243
- !! @data
244
- end
245
-
246
- def save
247
- return false if !loaded?
248
- marshaled_data = self.class.marshal(data)
249
-
250
- if @new_record
251
- @new_record = false
252
- @@connection.update <<-end_sql, 'Create session'
253
- INSERT INTO #{@@table_name} (
254
- #{@@connection.quote_column_name(@@session_id_column)},
255
- #{@@connection.quote_column_name(@@data_column)} )
256
- VALUES (
257
- #{@@connection.quote(session_id)},
258
- #{@@connection.quote(marshaled_data)} )
259
- end_sql
260
- else
261
- @@connection.update <<-end_sql, 'Update session'
262
- UPDATE #{@@table_name}
263
- SET #{@@connection.quote_column_name(@@data_column)}=#{@@connection.quote(marshaled_data)}
264
- WHERE #{@@connection.quote_column_name(@@session_id_column)}=#{@@connection.quote(session_id)}
265
- end_sql
266
- end
267
- end
268
-
269
- def destroy
270
- unless @new_record
271
- @@connection.delete <<-end_sql, 'Destroy session'
272
- DELETE FROM #{@@table_name}
273
- WHERE #{@@connection.quote_column_name(@@session_id_column)}=#{@@connection.quote(session_id)}
274
- end_sql
275
- end
276
- end
277
- end
278
-
279
-
280
- # The class used for session storage. Defaults to
281
- # CGI::Session::ActiveRecordStore::Session.
282
- cattr_accessor :session_class
283
- self.session_class = Session
284
-
285
- # Find or instantiate a session given a CGI::Session.
286
- def initialize(session, option = nil)
287
- session_id = session.session_id
288
- unless @session = ActiveRecord::Base.silence { @@session_class.find_by_session_id(session_id) }
289
- unless session.new_session
290
- raise CGI::Session::NoSession, 'uninitialized session'
291
- end
292
- @session = @@session_class.new(:session_id => session_id, :data => {})
293
- # session saving can be lazy again, because of improved component implementation
294
- # therefore next line gets commented out:
295
- # @session.save
296
- end
297
- end
298
-
299
- # Access the underlying session model.
300
- def model
301
- @session
302
- end
303
-
304
- # Restore session state. The session model handles unmarshaling.
305
- def restore
306
- if @session
307
- @session.data
308
- end
309
- end
310
-
311
- # Save session store.
312
- def update
313
- if @session
314
- ActiveRecord::Base.silence { @session.save }
315
- end
316
- end
317
-
318
- # Save and close the session store.
319
- def close
320
- if @session
321
- update
322
- @session = nil
323
- end
324
- end
325
-
326
- # Delete and close the session store.
327
- def delete
328
- if @session
329
- ActiveRecord::Base.silence { @session.destroy }
330
- @session = nil
331
- end
332
- end
333
-
334
- protected
335
- def logger
336
- ActionController::Base.logger rescue nil
337
- end
338
- end
339
- end
340
- end