actionpack 1.9.1 → 1.10.1
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/CHANGELOG +237 -0
- data/README +12 -12
- data/lib/action_controller.rb +17 -12
- data/lib/action_controller/assertions.rb +119 -67
- data/lib/action_controller/base.rb +184 -102
- data/lib/action_controller/benchmarking.rb +35 -6
- data/lib/action_controller/caching.rb +115 -58
- data/lib/action_controller/cgi_ext/cgi_methods.rb +54 -21
- data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +39 -35
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +34 -21
- data/lib/action_controller/cgi_process.rb +23 -20
- data/lib/action_controller/components.rb +11 -2
- data/lib/action_controller/dependencies.rb +0 -5
- data/lib/action_controller/deprecated_redirects.rb +17 -0
- data/lib/action_controller/filters.rb +13 -9
- data/lib/action_controller/flash.rb +7 -7
- data/lib/action_controller/helpers.rb +1 -14
- data/lib/action_controller/layout.rb +40 -29
- data/lib/action_controller/macros/auto_complete.rb +52 -0
- data/lib/action_controller/macros/in_place_editing.rb +32 -0
- data/lib/action_controller/pagination.rb +44 -28
- data/lib/action_controller/request.rb +54 -40
- data/lib/action_controller/rescue.rb +8 -6
- data/lib/action_controller/routing.rb +77 -28
- data/lib/action_controller/scaffolding.rb +10 -14
- data/lib/action_controller/session/active_record_store.rb +36 -7
- data/lib/action_controller/session_management.rb +126 -0
- data/lib/action_controller/streaming.rb +14 -5
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +1 -1
- data/lib/action_controller/templates/rescues/_trace.rhtml +24 -0
- data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -13
- data/lib/action_controller/templates/rescues/template_error.rhtml +4 -2
- data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
- data/lib/action_controller/test_process.rb +35 -17
- data/lib/action_controller/upload_progress.rb +52 -0
- data/lib/action_controller/url_rewriter.rb +21 -16
- data/lib/action_controller/vendor/html-scanner/html/document.rb +2 -2
- data/lib/action_controller/vendor/html-scanner/html/node.rb +30 -3
- data/lib/action_pack/version.rb +9 -0
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +204 -60
- data/lib/action_view/compiled_templates.rb +70 -0
- data/lib/action_view/helpers/active_record_helper.rb +7 -3
- data/lib/action_view/helpers/asset_tag_helper.rb +22 -12
- data/lib/action_view/helpers/capture_helper.rb +2 -10
- data/lib/action_view/helpers/date_helper.rb +21 -13
- data/lib/action_view/helpers/form_helper.rb +14 -10
- data/lib/action_view/helpers/form_options_helper.rb +4 -4
- data/lib/action_view/helpers/form_tag_helper.rb +59 -25
- data/lib/action_view/helpers/java_script_macros_helper.rb +188 -0
- data/lib/action_view/helpers/javascript_helper.rb +68 -133
- data/lib/action_view/helpers/javascripts/controls.js +427 -165
- data/lib/action_view/helpers/javascripts/dragdrop.js +256 -277
- data/lib/action_view/helpers/javascripts/effects.js +766 -277
- data/lib/action_view/helpers/javascripts/prototype.js +906 -218
- data/lib/action_view/helpers/javascripts/slider.js +258 -0
- data/lib/action_view/helpers/number_helper.rb +4 -3
- data/lib/action_view/helpers/pagination_helper.rb +42 -27
- data/lib/action_view/helpers/tag_helper.rb +25 -11
- data/lib/action_view/helpers/text_helper.rb +119 -13
- data/lib/action_view/helpers/upload_progress_helper.rb +2 -2
- data/lib/action_view/helpers/url_helper.rb +68 -21
- data/lib/action_view/partials.rb +17 -6
- data/lib/action_view/template_error.rb +19 -24
- data/rakefile +4 -3
- data/test/abstract_unit.rb +2 -1
- data/test/controller/action_pack_assertions_test.rb +62 -2
- data/test/controller/active_record_assertions_test.rb +5 -6
- data/test/controller/active_record_store_test.rb +23 -1
- data/test/controller/addresses_render_test.rb +4 -0
- data/test/controller/{base_tests.rb → base_test.rb} +4 -3
- data/test/controller/benchmark_test.rb +36 -0
- data/test/controller/caching_filestore.rb +22 -40
- data/test/controller/capture_test.rb +10 -1
- data/test/controller/cgi_test.rb +145 -23
- data/test/controller/components_test.rb +50 -0
- data/test/controller/custom_handler_test.rb +3 -3
- data/test/controller/fake_controllers.rb +24 -0
- data/test/controller/filters_test.rb +6 -6
- data/test/controller/flash_test.rb +6 -6
- data/test/controller/fragment_store_setting_test.rb +45 -0
- data/test/controller/helper_test.rb +1 -3
- data/test/controller/new_render_test.rb +119 -7
- data/test/controller/redirect_test.rb +11 -1
- data/test/controller/render_test.rb +34 -1
- data/test/controller/request_test.rb +14 -5
- data/test/controller/routing_test.rb +238 -42
- data/test/controller/send_file_test.rb +11 -10
- data/test/controller/session_management_test.rb +94 -0
- data/test/controller/test_test.rb +194 -5
- data/test/controller/url_rewriter_test.rb +46 -0
- data/test/fixtures/layouts/talk_from_action.rhtml +2 -0
- data/test/fixtures/layouts/yield.rhtml +2 -0
- data/test/fixtures/multipart/binary_file +0 -0
- data/test/fixtures/multipart/large_text_file +10 -0
- data/test/fixtures/multipart/mixed_files +0 -0
- data/test/fixtures/multipart/single_parameter +5 -0
- data/test/fixtures/multipart/text_file +10 -0
- data/test/fixtures/test/_customer_greeting.rhtml +1 -0
- data/test/fixtures/test/_hash_object.rhtml +1 -0
- data/test/fixtures/test/_person.rhtml +2 -0
- data/test/fixtures/test/action_talk_to_layout.rhtml +2 -0
- data/test/fixtures/test/content_for.rhtml +2 -0
- data/test/fixtures/test/potential_conflicts.rhtml +4 -0
- data/test/template/active_record_helper_test.rb +15 -8
- data/test/template/asset_tag_helper_test.rb +40 -16
- data/test/template/compiled_templates_tests.rb +63 -0
- data/test/template/date_helper_test.rb +80 -4
- data/test/template/form_helper_test.rb +48 -42
- data/test/template/form_options_helper_test.rb +40 -40
- data/test/template/form_tag_helper_test.rb +21 -15
- data/test/template/java_script_macros_helper_test.rb +56 -0
- data/test/template/javascript_helper_test.rb +70 -47
- data/test/template/number_helper_test.rb +2 -0
- data/test/template/tag_helper_test.rb +9 -0
- data/test/template/text_helper_test.rb +146 -1
- data/test/template/upload_progress_helper_testx.rb +11 -147
- data/test/template/url_helper_test.rb +90 -22
- data/test/testing_sandbox.rb +26 -0
- metadata +37 -7
- data/lib/action_controller/auto_complete.rb +0 -47
- data/lib/action_controller/deprecated_renders_and_redirects.rb +0 -76
- data/lib/action_controller/session.rb +0 -14
@@ -24,8 +24,8 @@ module ActionController #:nodoc:
|
|
24
24
|
protected
|
25
25
|
# Exception handler called when the performance of an action raises an exception.
|
26
26
|
def rescue_action(exception)
|
27
|
-
log_error(exception)
|
28
|
-
|
27
|
+
log_error(exception) if logger
|
28
|
+
erase_results if performed?
|
29
29
|
|
30
30
|
if consider_all_requests_local || local_request?
|
31
31
|
rescue_action_locally(exception)
|
@@ -65,10 +65,12 @@ module ActionController #:nodoc:
|
|
65
65
|
|
66
66
|
# Renders a detailed diagnostics screen on action exceptions.
|
67
67
|
def rescue_action_locally(exception)
|
68
|
-
@exception = exception
|
69
|
-
@rescues_path = File.dirname(__FILE__) + "/templates/rescues/"
|
70
68
|
add_variables_to_assigns
|
71
|
-
@
|
69
|
+
@template.instance_variable_set("@exception", exception)
|
70
|
+
@template.instance_variable_set("@rescues_path", File.dirname(__FILE__) + "/templates/rescues/")
|
71
|
+
@template.send(:assign_variables_from_controller)
|
72
|
+
|
73
|
+
@template.instance_variable_set("@contents", @template.render_file(template_path_for_local_rescue(exception), false))
|
72
74
|
|
73
75
|
@headers["Content-Type"] = "text/html"
|
74
76
|
render_file(rescues_path("layout"), response_code_for_rescue(exception))
|
@@ -93,7 +95,7 @@ module ActionController #:nodoc:
|
|
93
95
|
callstack.slice!(0) if callstack.first["rescue.rb"]
|
94
96
|
file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
|
95
97
|
|
96
|
-
message = "Exception at #{file}:#{line}#{" in `#{method}'" if method}."
|
98
|
+
message = "Exception at #{file}:#{line}#{" in `#{method}'" if method}." # `� ( for ruby-mode)
|
97
99
|
|
98
100
|
Breakpoint.handle_breakpoint(context, message, file, line)
|
99
101
|
end
|
@@ -19,22 +19,30 @@ module ActionController
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def treat_hash(hash)
|
22
|
+
def treat_hash(hash, keys_to_delete = [])
|
23
23
|
k = v = nil
|
24
24
|
hash.each do |k, v|
|
25
|
-
hash[k] = (v.respond_to? :to_param) ? v.to_param.to_s : v.to_s
|
25
|
+
if v then hash[k] = (v.respond_to? :to_param) ? v.to_param.to_s : v.to_s
|
26
|
+
else
|
27
|
+
hash.delete k
|
28
|
+
keys_to_delete << k
|
29
|
+
end
|
26
30
|
end
|
27
31
|
hash
|
28
32
|
end
|
29
|
-
|
30
|
-
|
31
|
-
class << self
|
33
|
+
|
32
34
|
def test_condition(expression, condition)
|
33
35
|
case condition
|
34
36
|
when String then "(#{expression} == #{condition.inspect})"
|
35
37
|
when Regexp then
|
36
38
|
condition = Regexp.new("^#{condition.source}$") unless /^\^.*\$$/ =~ condition.source
|
37
39
|
"(#{condition.inspect} =~ #{expression})"
|
40
|
+
when Array then
|
41
|
+
conds = condition.collect do |condition|
|
42
|
+
cond = test_condition(expression, condition)
|
43
|
+
(cond[0, 1] == '(' && cond[-1, 1] == ')') ? cond : "(#{cond})"
|
44
|
+
end
|
45
|
+
"(#{conds.join(' || ')})"
|
38
46
|
when true then expression
|
39
47
|
when nil then "! #{expression}"
|
40
48
|
else
|
@@ -184,7 +192,14 @@ module ActionController
|
|
184
192
|
g << "controller_result = ::ActionController::Routing::ControllerComponent.traverse_to_controller(#{g.path_name}, #{g.index_name})"
|
185
193
|
g.if('controller_result') do |gp|
|
186
194
|
gp << 'controller_value, segments_to_controller = controller_result'
|
187
|
-
|
195
|
+
if condition
|
196
|
+
gp << "controller_path = #{gp.path_name}[#{gp.index_name},segments_to_controller].join('/')"
|
197
|
+
gp.if(Routing.test_condition("controller_path", condition)) do |gpp|
|
198
|
+
gpp.move_forward('segments_to_controller') {|gppp| yield gppp, :constraint}
|
199
|
+
end
|
200
|
+
else
|
201
|
+
gp.move_forward('segments_to_controller') {|gpp| yield gpp, :constraint}
|
202
|
+
end
|
188
203
|
end
|
189
204
|
end
|
190
205
|
|
@@ -253,7 +268,7 @@ module ActionController
|
|
253
268
|
g.finish(false)
|
254
269
|
end
|
255
270
|
|
256
|
-
class Result < ::Array
|
271
|
+
class Result < ::Array #:nodoc:
|
257
272
|
def to_s() join '/' end
|
258
273
|
def self.new_escaped(strings)
|
259
274
|
new strings.collect {|str| CGI.unescape str}
|
@@ -272,6 +287,7 @@ module ActionController
|
|
272
287
|
defaults, conditions = initialize_hashes options.dup
|
273
288
|
@defaults = defaults.dup
|
274
289
|
configure_components(defaults, conditions)
|
290
|
+
add_default_requirements
|
275
291
|
initialize_keys
|
276
292
|
end
|
277
293
|
|
@@ -283,9 +299,16 @@ module ActionController
|
|
283
299
|
generator.before, generator.current, generator.after = [], components.first, (components[1..-1] || [])
|
284
300
|
|
285
301
|
if known.empty? then generator.go
|
286
|
-
else
|
302
|
+
else
|
303
|
+
# Alter the conditions to allow :action => 'index' to also catch :action => nil
|
304
|
+
altered_known = known.collect do |k, v|
|
305
|
+
if k == :action && v== 'index' then [k, [nil, 'index']]
|
306
|
+
else [k, v]
|
307
|
+
end
|
308
|
+
end
|
309
|
+
generator.if(generator.check_conditions(altered_known)) {|gp| gp.go }
|
287
310
|
end
|
288
|
-
|
311
|
+
|
289
312
|
generator
|
290
313
|
end
|
291
314
|
|
@@ -324,7 +347,6 @@ module ActionController
|
|
324
347
|
end
|
325
348
|
|
326
349
|
protected
|
327
|
-
|
328
350
|
def initialize_components(path)
|
329
351
|
path = path.split('/') if path.is_a? String
|
330
352
|
path.shift if path.first.blank?
|
@@ -356,6 +378,11 @@ module ActionController
|
|
356
378
|
component.condition = conditions[component.key] if conditions.key?(component.key)
|
357
379
|
end
|
358
380
|
end
|
381
|
+
|
382
|
+
def add_default_requirements
|
383
|
+
component_keys = components.collect {|c| c.key}
|
384
|
+
known[:action] ||= 'index' unless component_keys.include? :action
|
385
|
+
end
|
359
386
|
end
|
360
387
|
|
361
388
|
class RouteSet #:nodoc:
|
@@ -377,17 +404,15 @@ module ActionController
|
|
377
404
|
options[:controller] = Routing.controller_relative_to(controller, recall_controller)
|
378
405
|
end
|
379
406
|
options = recall.dup if options.empty? # XXX move to url_rewriter?
|
380
|
-
|
407
|
+
|
408
|
+
keys_to_delete = []
|
409
|
+
Routing.treat_hash(options, keys_to_delete)
|
410
|
+
|
381
411
|
merged = recall.merge(options)
|
412
|
+
keys_to_delete.each {|key| merged.delete key}
|
382
413
|
expire_on = Routing.expiry_hash(options, recall)
|
383
414
|
|
384
|
-
|
385
|
-
|
386
|
-
# Factor out?
|
387
|
-
extras = {}
|
388
|
-
k = nil
|
389
|
-
keys.each {|k| extras[k] = options[k]}
|
390
|
-
[path, extras]
|
415
|
+
generate_path(merged, options, expire_on)
|
391
416
|
end
|
392
417
|
|
393
418
|
def generate_path(merged, options, expire_on)
|
@@ -557,16 +582,24 @@ module ActionController
|
|
557
582
|
|
558
583
|
def each(&block) @routes.each(&block) end
|
559
584
|
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
585
|
+
# Defines a new named route with the provided name and arguments.
|
586
|
+
# This method need only be used when you wish to use a name that a RouteSet instance
|
587
|
+
# method exists for, such as categories.
|
588
|
+
#
|
589
|
+
# For example, map.categories '/categories', :controller => 'categories' will not work
|
590
|
+
# due to RouteSet#categories.
|
591
|
+
def named_route(name, path, hash = {})
|
592
|
+
route = connect(path, hash)
|
564
593
|
NamedRoutes.name_route(route, name)
|
565
594
|
route
|
566
595
|
end
|
596
|
+
|
597
|
+
def method_missing(name, *args)
|
598
|
+
(1..2).include?(args.length) ? named_route(name, *args) : super(name, *args)
|
599
|
+
end
|
567
600
|
|
568
601
|
def extra_keys(options, recall = {})
|
569
|
-
generate(options.dup, recall).last
|
602
|
+
generate(options.dup, recall).last
|
570
603
|
end
|
571
604
|
end
|
572
605
|
|
@@ -582,12 +615,27 @@ module ActionController
|
|
582
615
|
def url_helper_name(name)
|
583
616
|
"#{name}_url"
|
584
617
|
end
|
585
|
-
|
586
|
-
def
|
587
|
-
hash = route.
|
618
|
+
|
619
|
+
def known_hash_for_route(route)
|
620
|
+
hash = route.known.symbolize_keys
|
621
|
+
route.defaults.each do |key, value|
|
622
|
+
hash[key.to_sym] ||= value if value
|
623
|
+
end
|
588
624
|
hash[:controller] = "/#{hash[:controller]}"
|
589
|
-
|
590
|
-
|
625
|
+
|
626
|
+
hash
|
627
|
+
end
|
628
|
+
|
629
|
+
def define_hash_access_method(route, name)
|
630
|
+
hash = known_hash_for_route(route)
|
631
|
+
define_method(hash_access_name(name)) do |*args|
|
632
|
+
args.first ? hash.merge(args.first) : hash
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
def name_route(route, name)
|
637
|
+
define_hash_access_method(route, name)
|
638
|
+
|
591
639
|
module_eval(%{def #{url_helper_name name}(options = {})
|
592
640
|
url_for(#{hash_access_name(name)}.merge(options))
|
593
641
|
end}, "generated/routing/named_routes/#{name}.rb")
|
@@ -595,6 +643,7 @@ module ActionController
|
|
595
643
|
protected url_helper_name(name), hash_access_name(name)
|
596
644
|
|
597
645
|
Helpers << url_helper_name(name).to_sym
|
646
|
+
Helpers << hash_access_name(name).to_sym
|
598
647
|
Helpers.uniq!
|
599
648
|
end
|
600
649
|
|
@@ -82,7 +82,7 @@ module ActionController
|
|
82
82
|
# make <tt>scaffold :post, :suffix => true</tt> use method names like list_post, show_post, and create_post
|
83
83
|
# instead of just list, show, and post. If suffix is used, then no index method is added.
|
84
84
|
def scaffold(model_id, options = {})
|
85
|
-
|
85
|
+
options.assert_valid_keys(:class_name, :suffix)
|
86
86
|
|
87
87
|
singular_name = model_id.to_s
|
88
88
|
class_name = options[:class_name] || singular_name.camelize
|
@@ -146,21 +146,24 @@ module ActionController
|
|
146
146
|
end
|
147
147
|
|
148
148
|
private
|
149
|
-
def render#{suffix}_scaffold(action
|
149
|
+
def render#{suffix}_scaffold(action=nil)
|
150
|
+
action ||= caller_method_name(caller)
|
151
|
+
# logger.info ("testing template:" + "\#{self.class.controller_path}/\#{action}") if logger
|
152
|
+
|
150
153
|
if template_exists?("\#{self.class.controller_path}/\#{action}")
|
151
|
-
|
154
|
+
render_action(action)
|
152
155
|
else
|
153
156
|
@scaffold_class = #{class_name}
|
154
157
|
@scaffold_singular_name, @scaffold_plural_name = "#{singular_name}", "#{plural_name}"
|
155
158
|
@scaffold_suffix = "#{suffix}"
|
156
159
|
add_instance_variables_to_assigns
|
157
160
|
|
158
|
-
@content_for_layout
|
161
|
+
@template.instance_variable_set("@content_for_layout", @template.render_file(scaffold_path(action.sub(/#{suffix}$/, "")), false))
|
159
162
|
|
160
163
|
if !active_layout.nil?
|
161
|
-
|
164
|
+
render_file(active_layout, nil, true)
|
162
165
|
else
|
163
|
-
|
166
|
+
render_file(scaffold_path("layout"))
|
164
167
|
end
|
165
168
|
end
|
166
169
|
end
|
@@ -173,14 +176,7 @@ module ActionController
|
|
173
176
|
caller.first.scan(/`(.*)'/).first.first # ' ruby-mode
|
174
177
|
end
|
175
178
|
end_eval
|
176
|
-
end
|
177
|
-
|
178
|
-
private
|
179
|
-
# Raises an exception if an invalid option has been specified to prevent misspellings from slipping through
|
180
|
-
def validate_options(valid_option_keys, supplied_option_keys)
|
181
|
-
unknown_option_keys = supplied_option_keys - valid_option_keys
|
182
|
-
raise(ActionController::ActionControllerError, "Unknown options: #{unknown_option_keys}") unless unknown_option_keys.empty?
|
183
|
-
end
|
179
|
+
end
|
184
180
|
end
|
185
181
|
end
|
186
182
|
end
|
@@ -12,8 +12,9 @@ class CGI
|
|
12
12
|
# may be used as the backing store.
|
13
13
|
#
|
14
14
|
# The default assumes a +sessions+ tables with columns +id+ (numeric
|
15
|
-
# primary key), +session_id+ (text
|
16
|
-
# marshaled to +data+. +session_id+ should be
|
15
|
+
# primary key), +session_id+ (text, or longtext if your session data exceeds 65K),
|
16
|
+
# and +data+ (text). Session data is marshaled to +data+. +session_id+ should be
|
17
|
+
# indexed for speedy lookups.
|
17
18
|
#
|
18
19
|
# Since the default class is a simple Active Record, you get timestamps
|
19
20
|
# for free if you add +created_at+ and +updated_at+ datetime columns to
|
@@ -32,13 +33,28 @@ class CGI
|
|
32
33
|
#
|
33
34
|
# The fast SqlBypass class is a generic SQL session store. You may
|
34
35
|
# use it as a basis for high-performance database-specific stores.
|
36
|
+
#
|
37
|
+
# If the data you are attempting to write to the +data+ column is larger
|
38
|
+
# than the column's size limit, ActionController::SessionOverflowError
|
39
|
+
# will be raised.
|
35
40
|
class ActiveRecordStore
|
36
41
|
# The default Active Record class.
|
37
42
|
class Session < ActiveRecord::Base
|
38
43
|
before_save :marshal_data!
|
44
|
+
before_save :ensure_data_not_too_big
|
39
45
|
before_update :data_changed?
|
40
46
|
|
41
47
|
class << self
|
48
|
+
|
49
|
+
# Don't try to reload ARStore::Session in dev mode.
|
50
|
+
def reloadable? #:nodoc:
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
def data_column_size_limit
|
55
|
+
columns_hash['data'].limit
|
56
|
+
end
|
57
|
+
|
42
58
|
# Hook to set up sessid compatibility.
|
43
59
|
def find_by_session_id(session_id)
|
44
60
|
setup_sessid_compatibility!
|
@@ -54,7 +70,7 @@ class CGI
|
|
54
70
|
CREATE TABLE #{table_name} (
|
55
71
|
id INTEGER PRIMARY KEY,
|
56
72
|
#{connection.quote_column_name('session_id')} TEXT UNIQUE,
|
57
|
-
#{connection.quote_column_name('data')} TEXT
|
73
|
+
#{connection.quote_column_name('data')} TEXT(255)
|
58
74
|
)
|
59
75
|
end_sql
|
60
76
|
end
|
@@ -108,6 +124,15 @@ class CGI
|
|
108
124
|
old_fingerprint, @fingerprint = @fingerprint, self.class.fingerprint(read_attribute('data'))
|
109
125
|
old_fingerprint != @fingerprint
|
110
126
|
end
|
127
|
+
|
128
|
+
# Ensures that the data about to be stored in the database is not
|
129
|
+
# larger than the data storage column. Raises
|
130
|
+
# ActionController::SessionOverflowError.
|
131
|
+
def ensure_data_not_too_big
|
132
|
+
return unless limit = self.class.data_column_size_limit
|
133
|
+
raise ActionController::SessionOverflowError, ActionController::SessionOverflowError::DEFAULT_MESSAGE if read_attribute('data').size > limit
|
134
|
+
end
|
135
|
+
|
111
136
|
end
|
112
137
|
|
113
138
|
# A barebones session store which duck-types with the default session
|
@@ -125,9 +150,6 @@ class CGI
|
|
125
150
|
class SqlBypass
|
126
151
|
# Use the ActiveRecord::Base.connection by default.
|
127
152
|
cattr_accessor :connection
|
128
|
-
def self.connection
|
129
|
-
@@connection ||= ActiveRecord::Base.connection
|
130
|
-
end
|
131
153
|
|
132
154
|
# The table name defaults to 'sessions'.
|
133
155
|
cattr_accessor :table_name
|
@@ -142,6 +164,11 @@ class CGI
|
|
142
164
|
@@data_column = 'data'
|
143
165
|
|
144
166
|
class << self
|
167
|
+
|
168
|
+
def connection
|
169
|
+
@@connection ||= ActiveRecord::Base.connection
|
170
|
+
end
|
171
|
+
|
145
172
|
# Look up a session by id and unmarshal its data if found.
|
146
173
|
def find_by_session_id(session_id)
|
147
174
|
if record = @@connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{@@connection.quote(session_id)}")
|
@@ -200,6 +227,7 @@ class CGI
|
|
200
227
|
|
201
228
|
def save
|
202
229
|
marshaled_data = self.class.marshal(data)
|
230
|
+
|
203
231
|
if @new_record
|
204
232
|
@new_record = false
|
205
233
|
@@connection.update <<-end_sql, 'Create session'
|
@@ -230,6 +258,7 @@ class CGI
|
|
230
258
|
end_sql
|
231
259
|
end
|
232
260
|
end
|
261
|
+
|
233
262
|
end
|
234
263
|
|
235
264
|
# The class used for session storage. Defaults to
|
@@ -277,7 +306,7 @@ class CGI
|
|
277
306
|
@session = nil
|
278
307
|
end
|
279
308
|
end
|
280
|
-
end
|
281
309
|
|
310
|
+
end
|
282
311
|
end
|
283
312
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'action_controller/session/drb_store'
|
2
|
+
require 'action_controller/session/mem_cache_store'
|
3
|
+
if Object.const_defined?(:ActiveRecord)
|
4
|
+
require 'action_controller/session/active_record_store'
|
5
|
+
end
|
6
|
+
|
7
|
+
module ActionController #:nodoc:
|
8
|
+
module SessionManagement #:nodoc:
|
9
|
+
def self.append_features(base)
|
10
|
+
super
|
11
|
+
base.extend(ClassMethods)
|
12
|
+
base.send(:alias_method, :process_without_session_management_support, :process)
|
13
|
+
base.send(:alias_method, :process, :process_with_session_management_support)
|
14
|
+
base.after_filter(:clear_persistant_model_associations)
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
# Set the session store to be used for keeping the session data between requests. The default is using the
|
19
|
+
# file system, but you can also specify one of the other included stores (:active_record_store, :drb_store,
|
20
|
+
# :mem_cache_store, or :memory_store) or use your own class.
|
21
|
+
def session_store=(store)
|
22
|
+
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager] =
|
23
|
+
store.is_a?(Symbol) ? CGI::Session.const_get(store == :drb_store ? "DRbStore" : store.to_s.camelize) : store
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the session store class currently used.
|
27
|
+
def session_store
|
28
|
+
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the hash used to configure the session. Example use:
|
32
|
+
#
|
33
|
+
# ActionController::Base.session_options[:session_secure] = true # session only available over HTTPS
|
34
|
+
def session_options
|
35
|
+
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS
|
36
|
+
end
|
37
|
+
|
38
|
+
# Specify how sessions ought to be managed for a subset of the actions on
|
39
|
+
# the controller. Like filters, you can specify <tt>:only</tt> and
|
40
|
+
# <tt>:except</tt> clauses to restrict the subset, otherwise options
|
41
|
+
# apply to all actions on this controller.
|
42
|
+
#
|
43
|
+
# The session options are inheritable, as well, so if you specify them in
|
44
|
+
# a parent controller, they apply to controllers that extend the parent.
|
45
|
+
#
|
46
|
+
# Usage:
|
47
|
+
#
|
48
|
+
# # turn off session management for all actions.
|
49
|
+
# session :off
|
50
|
+
#
|
51
|
+
# # turn off session management for all actions _except_ foo and bar.
|
52
|
+
# session :off, :except => %w(foo bar)
|
53
|
+
#
|
54
|
+
# # turn off session management for only the foo and bar actions.
|
55
|
+
# session :off, :only => %w(foo bar)
|
56
|
+
#
|
57
|
+
# # the session will only work over HTTPS, but only for the foo action
|
58
|
+
# session :only => :foo, :session_secure => true
|
59
|
+
#
|
60
|
+
# # the session will only be disabled for 'foo', and only if it is
|
61
|
+
# # requested as a web service
|
62
|
+
# session :off, :only => :foo,
|
63
|
+
# :if => Proc.new { |req| req.parameters[:ws] }
|
64
|
+
#
|
65
|
+
# All session options described for ActionController::Base.process_cgi
|
66
|
+
# are valid arguments.
|
67
|
+
def session(*args)
|
68
|
+
options = Hash === args.last ? args.pop : {}
|
69
|
+
|
70
|
+
options[:disabled] = true if !args.empty?
|
71
|
+
options[:only] = [*options[:only]].map { |o| o.to_s } if options[:only]
|
72
|
+
options[:except] = [*options[:except]].map { |o| o.to_s } if options[:except]
|
73
|
+
if options[:only] && options[:except]
|
74
|
+
raise ArgumentError, "only one of either :only or :except are allowed"
|
75
|
+
end
|
76
|
+
|
77
|
+
write_inheritable_array("session_options", [options])
|
78
|
+
end
|
79
|
+
|
80
|
+
def cached_session_options #:nodoc:
|
81
|
+
@session_options ||= read_inheritable_attribute("session_options") || []
|
82
|
+
end
|
83
|
+
|
84
|
+
def session_options_for(request, action) #:nodoc:
|
85
|
+
if (session_options = cached_session_options).empty?
|
86
|
+
{}
|
87
|
+
else
|
88
|
+
options = {}
|
89
|
+
|
90
|
+
action = action.to_s
|
91
|
+
session_options.each do |opts|
|
92
|
+
next if opts[:if] && !opts[:if].call(request)
|
93
|
+
if opts[:only] && opts[:only].include?(action)
|
94
|
+
options.merge!(opts)
|
95
|
+
elsif opts[:except] && !opts[:except].include?(action)
|
96
|
+
options.merge!(opts)
|
97
|
+
elsif !opts[:only] && !opts[:except]
|
98
|
+
options.merge!(opts)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
if options.empty? then options
|
103
|
+
else
|
104
|
+
options.delete :only
|
105
|
+
options.delete :except
|
106
|
+
options.delete :if
|
107
|
+
options[:disabled] ? false : options
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def process_with_session_management_support(request, response, method = :perform_action, *arguments) #:nodoc:
|
114
|
+
action = request.parameters["action"] || "index"
|
115
|
+
request.session_options = self.class.session_options_for(request, action)
|
116
|
+
process_without_session_management_support(request, response, method, *arguments)
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def clear_persistant_model_associations #:doc:
|
121
|
+
if session = @session.instance_variable_get("@data")
|
122
|
+
session.each { |key, obj| obj.clear_association_cache if obj.respond_to?(:clear_association_cache) }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|