actionpack 1.8.1 → 1.9.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.
- data/CHANGELOG +309 -16
- data/README +1 -1
- data/lib/action_controller.rb +5 -0
- data/lib/action_controller/assertions.rb +57 -12
- data/lib/action_controller/auto_complete.rb +47 -0
- data/lib/action_controller/base.rb +288 -258
- data/lib/action_controller/benchmarking.rb +8 -3
- data/lib/action_controller/caching.rb +88 -42
- data/lib/action_controller/cgi_ext/cgi_ext.rb +1 -1
- data/lib/action_controller/cgi_ext/cgi_methods.rb +41 -11
- data/lib/action_controller/cgi_ext/multipart_progress.rb +169 -0
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +30 -12
- data/lib/action_controller/cgi_process.rb +39 -11
- data/lib/action_controller/code_generation.rb +235 -0
- data/lib/action_controller/cookies.rb +14 -8
- data/lib/action_controller/deprecated_renders_and_redirects.rb +76 -0
- data/lib/action_controller/filters.rb +8 -7
- data/lib/action_controller/helpers.rb +41 -6
- data/lib/action_controller/layout.rb +45 -16
- data/lib/action_controller/request.rb +86 -23
- data/lib/action_controller/rescue.rb +1 -0
- data/lib/action_controller/response.rb +1 -1
- data/lib/action_controller/routing.rb +536 -272
- data/lib/action_controller/scaffolding.rb +30 -25
- data/lib/action_controller/session/active_record_store.rb +251 -50
- data/lib/action_controller/streaming.rb +133 -0
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +0 -7
- data/lib/action_controller/templates/scaffolds/edit.rhtml +2 -2
- data/lib/action_controller/templates/scaffolds/layout.rhtml +22 -18
- data/lib/action_controller/templates/scaffolds/list.rhtml +3 -3
- data/lib/action_controller/templates/scaffolds/new.rhtml +2 -2
- data/lib/action_controller/templates/scaffolds/show.rhtml +1 -1
- data/lib/action_controller/test_process.rb +68 -47
- data/lib/action_controller/upload_progress.rb +421 -0
- data/lib/action_controller/url_rewriter.rb +8 -11
- data/lib/action_controller/vendor/html-scanner/html/document.rb +6 -5
- data/lib/action_controller/vendor/html-scanner/html/node.rb +70 -14
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +17 -10
- data/lib/action_controller/vendor/html-scanner/html/version.rb +3 -3
- data/lib/action_controller/vendor/xml_simple.rb +1019 -0
- data/lib/action_controller/verification.rb +36 -30
- data/lib/action_view/base.rb +21 -14
- data/lib/action_view/helpers/active_record_helper.rb +15 -13
- data/lib/action_view/helpers/asset_tag_helper.rb +26 -9
- data/lib/action_view/helpers/benchmark_helper.rb +24 -0
- data/lib/action_view/helpers/capture_helper.rb +7 -5
- data/lib/action_view/helpers/date_helper.rb +63 -46
- data/lib/action_view/helpers/form_helper.rb +7 -1
- data/lib/action_view/helpers/form_options_helper.rb +19 -11
- data/lib/action_view/helpers/form_tag_helper.rb +5 -1
- data/lib/action_view/helpers/javascript_helper.rb +403 -35
- data/lib/action_view/helpers/javascripts/controls.js +261 -0
- data/lib/action_view/helpers/javascripts/dragdrop.js +476 -0
- data/lib/action_view/helpers/javascripts/effects.js +570 -0
- data/lib/action_view/helpers/javascripts/prototype.js +633 -371
- data/lib/action_view/helpers/number_helper.rb +11 -13
- data/lib/action_view/helpers/tag_helper.rb +1 -2
- data/lib/action_view/helpers/text_helper.rb +69 -6
- data/lib/action_view/helpers/upload_progress_helper.rb +433 -0
- data/lib/action_view/helpers/url_helper.rb +98 -3
- data/lib/action_view/partials.rb +14 -8
- data/lib/action_view/vendor/builder/xmlmarkup.rb +11 -0
- data/rakefile +13 -5
- data/test/abstract_unit.rb +1 -1
- data/test/controller/action_pack_assertions_test.rb +52 -9
- data/test/controller/active_record_assertions_test.rb +119 -120
- data/test/controller/active_record_store_test.rb +111 -0
- data/test/controller/addresses_render_test.rb +45 -0
- data/test/controller/caching_filestore.rb +92 -0
- data/test/controller/capture_test.rb +39 -0
- data/test/controller/cgi_test.rb +40 -3
- data/test/controller/helper_test.rb +65 -13
- data/test/controller/multipart_progress_testx.rb +365 -0
- data/test/controller/new_render_test.rb +263 -0
- data/test/controller/redirect_test.rb +64 -0
- data/test/controller/render_test.rb +20 -21
- data/test/controller/request_test.rb +83 -3
- data/test/controller/routing_test.rb +702 -0
- data/test/controller/send_file_test.rb +2 -0
- data/test/controller/test_test.rb +44 -8
- data/test/controller/upload_progress_testx.rb +89 -0
- data/test/controller/verification_test.rb +94 -29
- data/test/fixtures/addresses/list.rhtml +1 -0
- data/test/fixtures/test/capturing.rhtml +4 -0
- data/test/fixtures/test/list.rhtml +1 -1
- data/test/fixtures/test/update_element_with_capture.rhtml +9 -0
- data/test/template/active_record_helper_test.rb +30 -15
- data/test/template/asset_tag_helper_test.rb +12 -5
- data/test/template/benchmark_helper_test.rb +72 -0
- data/test/template/date_helper_test.rb +69 -0
- data/test/template/form_helper_test.rb +18 -10
- data/test/template/form_options_helper_test.rb +40 -5
- data/test/template/javascript_helper.rb +149 -2
- data/test/template/number_helper_test.rb +2 -0
- data/test/template/tag_helper_test.rb +4 -0
- data/test/template/text_helper_test.rb +36 -0
- data/test/template/upload_progress_helper_testx.rb +272 -0
- data/test/template/url_helper_test.rb +30 -0
- metadata +30 -6
- data/test/controller/layout_test.rb +0 -49
- data/test/controller/routing_tests.rb +0 -543
@@ -6,6 +6,8 @@ class CGI #:nodoc:
|
|
6
6
|
# Handles multipart forms (in particular, forms that involve file uploads).
|
7
7
|
# Reads query parameters in the @params field, and cookies into @cookies.
|
8
8
|
def initialize_query()
|
9
|
+
@cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] || env_table['COOKIE']))
|
10
|
+
|
9
11
|
if boundary = multipart_form_boundary
|
10
12
|
@multipart = true
|
11
13
|
@params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
|
@@ -13,12 +15,12 @@ class CGI #:nodoc:
|
|
13
15
|
@multipart = false
|
14
16
|
@params = CGI::parse(read_query_params || "")
|
15
17
|
end
|
16
|
-
|
17
|
-
@cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] || env_table['COOKIE']))
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
21
|
-
|
21
|
+
unless defined?(MULTIPART_FORM_BOUNDARY_RE)
|
22
|
+
MULTIPART_FORM_BOUNDARY_RE = %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n #"
|
23
|
+
end
|
22
24
|
|
23
25
|
def multipart_form_boundary
|
24
26
|
if env_table['REQUEST_METHOD'] == 'POST'
|
@@ -26,17 +28,33 @@ class CGI #:nodoc:
|
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
31
|
+
def read_params_from_query
|
32
|
+
if defined? MOD_RUBY
|
33
|
+
Apache::request.args || ''
|
34
|
+
else
|
35
|
+
# fixes CGI querystring parsing for POSTs
|
36
|
+
if env_table['QUERY_STRING'].blank? && !env_table['REQUEST_URI'].blank?
|
37
|
+
env_table['QUERY_STRING'] = env_table['REQUEST_URI'].split('?', 2)[1] || ''
|
38
|
+
end
|
39
|
+
env_table['QUERY_STRING']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def read_params_from_post
|
44
|
+
stdinput.binmode if stdinput.respond_to?(:binmode)
|
45
|
+
content = stdinput.read(Integer(env_table['CONTENT_LENGTH'])) || ''
|
46
|
+
env_table['RAW_POST_DATA'] = content.split("&_").first.to_s.freeze # &_ is a fix for Safari Ajax postings that always append \000
|
47
|
+
end
|
48
|
+
|
29
49
|
def read_query_params
|
30
|
-
case env_table['REQUEST_METHOD']
|
31
|
-
when '
|
32
|
-
(defined?(MOD_RUBY) ? Apache::request.args : env_table['QUERY_STRING']) || ''
|
33
|
-
when 'POST', 'PUT'
|
34
|
-
stdinput.binmode if stdinput.respond_to?(:binmode)
|
35
|
-
content = stdinput.read(Integer(env_table['CONTENT_LENGTH'])) || ''
|
36
|
-
env_table['RAW_POST_DATA'] = content.split("&_").first.to_s.freeze # &_ is a fix for Safari Ajax postings that always append \000
|
37
|
-
else
|
50
|
+
case env_table['REQUEST_METHOD'].to_s.upcase
|
51
|
+
when 'CMD'
|
38
52
|
read_from_cmdline
|
39
|
-
|
53
|
+
when 'POST', 'PUT'
|
54
|
+
read_params_from_post
|
55
|
+
else # when 'GET', 'HEAD', 'DELETE', 'OPTIONS'
|
56
|
+
read_params_from_query
|
57
|
+
end
|
40
58
|
end
|
41
59
|
end # module QueryExtension
|
42
60
|
end
|
@@ -2,8 +2,10 @@ require 'action_controller/cgi_ext/cgi_ext'
|
|
2
2
|
require 'action_controller/cgi_ext/cookie_performance_fix'
|
3
3
|
require 'action_controller/cgi_ext/raw_post_data_fix'
|
4
4
|
require 'action_controller/session/drb_store'
|
5
|
-
require 'action_controller/session/active_record_store'
|
6
5
|
require 'action_controller/session/mem_cache_store'
|
6
|
+
if Object.const_defined?(:ActiveRecord)
|
7
|
+
require 'action_controller/session/active_record_store'
|
8
|
+
end
|
7
9
|
|
8
10
|
module ActionController #:nodoc:
|
9
11
|
class Base
|
@@ -37,8 +39,11 @@ module ActionController #:nodoc:
|
|
37
39
|
class CgiRequest < AbstractRequest #:nodoc:
|
38
40
|
attr_accessor :cgi
|
39
41
|
|
40
|
-
DEFAULT_SESSION_OPTIONS =
|
41
|
-
|
42
|
+
DEFAULT_SESSION_OPTIONS = {
|
43
|
+
:database_manager => CGI::Session::PStore,
|
44
|
+
:prefix => "ruby_sess.",
|
45
|
+
:session_path => "/"
|
46
|
+
} unless const_defined?(:DEFAULT_SESSION_OPTIONS)
|
42
47
|
|
43
48
|
def initialize(cgi, session_options = {})
|
44
49
|
@cgi = cgi
|
@@ -63,7 +68,11 @@ module ActionController #:nodoc:
|
|
63
68
|
end
|
64
69
|
|
65
70
|
def request_parameters
|
66
|
-
|
71
|
+
if formatted_post?
|
72
|
+
CGIMethods.parse_formatted_request_parameters(post_format, env['RAW_POST_DATA'])
|
73
|
+
else
|
74
|
+
CGIMethods.parse_request_parameters(@cgi.params)
|
75
|
+
end
|
67
76
|
end
|
68
77
|
|
69
78
|
def env
|
@@ -80,17 +89,34 @@ module ActionController #:nodoc:
|
|
80
89
|
|
81
90
|
def session
|
82
91
|
return @session unless @session.nil?
|
92
|
+
|
83
93
|
begin
|
84
94
|
@session = (@session_options == false ? {} : CGI::Session.new(@cgi, session_options_with_string_keys))
|
85
95
|
@session["__valid_session"]
|
86
96
|
return @session
|
87
97
|
rescue ArgumentError => e
|
88
|
-
|
98
|
+
# TODO: Uncomment this on 0.13.1
|
99
|
+
# if e.message =~ %r{undefined class/module (\w+)}
|
100
|
+
# begin
|
101
|
+
# Module.const_missing($1)
|
102
|
+
# rescue LoadError, NameError => e
|
103
|
+
# raise(
|
104
|
+
# ActionController::SessionRestoreError,
|
105
|
+
# "Session contained objects where the class definition wasn't available. " +
|
106
|
+
# "Remember to require classes for all objects kept in the session. " +
|
107
|
+
# "(Original exception: #{e.message} [#{e.class}])"
|
108
|
+
# )
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# retry
|
112
|
+
# else
|
113
|
+
# raise
|
114
|
+
# end
|
89
115
|
raise(
|
90
116
|
ActionController::SessionRestoreError,
|
91
117
|
"Session contained objects where the class definition wasn't available. " +
|
92
118
|
"Remember to require classes for all objects kept in the session. " +
|
93
|
-
"
|
119
|
+
"(Original exception: #{e.message} [#{e.class}])"
|
94
120
|
)
|
95
121
|
end
|
96
122
|
end
|
@@ -120,21 +146,23 @@ module ActionController #:nodoc:
|
|
120
146
|
super()
|
121
147
|
end
|
122
148
|
|
123
|
-
def out
|
149
|
+
def out(output = $stdout)
|
124
150
|
convert_content_type!(@headers)
|
125
|
-
|
126
|
-
|
151
|
+
output.binmode if output.respond_to?(:binmode)
|
152
|
+
output.sync = false if output.respond_to?(:sync=)
|
127
153
|
|
128
154
|
begin
|
129
|
-
|
155
|
+
output.write(@cgi.header(@headers))
|
130
156
|
|
131
157
|
if @cgi.send(:env_table)['REQUEST_METHOD'] == 'HEAD'
|
132
158
|
return
|
133
159
|
elsif @body.respond_to?(:call)
|
134
160
|
@body.call(self)
|
135
161
|
else
|
136
|
-
|
162
|
+
output.write(@body)
|
137
163
|
end
|
164
|
+
|
165
|
+
output.flush if output.respond_to?(:flush)
|
138
166
|
rescue Errno::EPIPE => e
|
139
167
|
# lost connection to the FCGI process -- ignore the output, then
|
140
168
|
end
|
@@ -0,0 +1,235 @@
|
|
1
|
+
module ActionController
|
2
|
+
module CodeGeneration #:nodoc:
|
3
|
+
class GenerationError < StandardError #:nodoc:
|
4
|
+
end
|
5
|
+
|
6
|
+
class Source #:nodoc:
|
7
|
+
attr_reader :lines, :indentation_level
|
8
|
+
IndentationString = ' '
|
9
|
+
def initialize
|
10
|
+
@lines, @indentation_level = [], 0
|
11
|
+
end
|
12
|
+
def line(line)
|
13
|
+
@lines << (IndentationString * @indentation_level + line)
|
14
|
+
end
|
15
|
+
alias :<< :line
|
16
|
+
|
17
|
+
def indent
|
18
|
+
@indentation_level += 1
|
19
|
+
yield
|
20
|
+
ensure
|
21
|
+
@indentation_level -= 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s() lines.join("\n") end
|
25
|
+
end
|
26
|
+
|
27
|
+
class CodeGenerator #:nodoc:
|
28
|
+
attr_accessor :source, :locals
|
29
|
+
def initialize(source = nil)
|
30
|
+
@locals = []
|
31
|
+
@source = source || Source.new
|
32
|
+
end
|
33
|
+
|
34
|
+
BeginKeywords = %w(if unless begin until while def).collect {|kw| kw.to_sym}
|
35
|
+
ResumeKeywords = %w(elsif else rescue).collect {|kw| kw.to_sym}
|
36
|
+
Keywords = BeginKeywords + ResumeKeywords
|
37
|
+
|
38
|
+
def method_missing(keyword, *text)
|
39
|
+
if Keywords.include? keyword
|
40
|
+
if ResumeKeywords.include? keyword
|
41
|
+
raise GenerationError, "Can only resume with #{keyword} immediately after an end" unless source.lines.last =~ /^\s*end\s*$/
|
42
|
+
source.lines.pop # Remove the 'end'
|
43
|
+
end
|
44
|
+
|
45
|
+
line "#{keyword} #{text.join ' '}"
|
46
|
+
begin source.indent { yield(self.dup) }
|
47
|
+
ensure line 'end'
|
48
|
+
end
|
49
|
+
else
|
50
|
+
super(keyword, *text)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def line(*args) self.source.line(*args) end
|
55
|
+
alias :<< :line
|
56
|
+
def indent(*args, &block) source(*args, &block) end
|
57
|
+
def to_s() source.to_s end
|
58
|
+
|
59
|
+
def share_locals_with(other)
|
60
|
+
other.locals = self.locals = (other.locals | locals)
|
61
|
+
end
|
62
|
+
|
63
|
+
FieldsToDuplicate = [:locals]
|
64
|
+
def dup
|
65
|
+
copy = self.class.new(source)
|
66
|
+
self.class::FieldsToDuplicate.each do |sym|
|
67
|
+
value = self.send(sym)
|
68
|
+
value = value.dup unless value.nil? || value.is_a?(Numeric)
|
69
|
+
copy.send("#{sym}=", value)
|
70
|
+
end
|
71
|
+
return copy
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class RecognitionGenerator < CodeGenerator #:nodoc:
|
76
|
+
Attributes = [:after, :before, :current, :results, :constants, :depth, :move_ahead, :finish_statement]
|
77
|
+
attr_accessor(*Attributes)
|
78
|
+
FieldsToDuplicate = CodeGenerator::FieldsToDuplicate + Attributes
|
79
|
+
|
80
|
+
def initialize(*args)
|
81
|
+
super(*args)
|
82
|
+
@after, @before = [], []
|
83
|
+
@current = nil
|
84
|
+
@results, @constants = {}, {}
|
85
|
+
@depth = 0
|
86
|
+
@move_ahead = nil
|
87
|
+
@finish_statement = Proc.new {|hash_expr| hash_expr}
|
88
|
+
end
|
89
|
+
|
90
|
+
def if_next_matches(string, &block)
|
91
|
+
test = Routing.test_condition(next_segment(true), string)
|
92
|
+
self.if(test, &block)
|
93
|
+
end
|
94
|
+
|
95
|
+
def move_forward(places = 1)
|
96
|
+
dup = self.dup
|
97
|
+
dup.depth += 1
|
98
|
+
dup.move_ahead = places
|
99
|
+
yield dup
|
100
|
+
end
|
101
|
+
|
102
|
+
def next_segment(assign_inline = false, default = nil)
|
103
|
+
if locals.include?(segment_name)
|
104
|
+
code = segment_name
|
105
|
+
else
|
106
|
+
code = "#{segment_name} = #{path_name}[#{index_name}]"
|
107
|
+
if assign_inline
|
108
|
+
code = "(#{code})"
|
109
|
+
else
|
110
|
+
line(code)
|
111
|
+
code = segment_name
|
112
|
+
end
|
113
|
+
|
114
|
+
locals << segment_name
|
115
|
+
end
|
116
|
+
code = "(#{code} || #{default.inspect})" if default
|
117
|
+
|
118
|
+
return code.to_s
|
119
|
+
end
|
120
|
+
|
121
|
+
def segment_name() "segment#{depth}".to_sym end
|
122
|
+
def path_name() :path end
|
123
|
+
def index_name
|
124
|
+
move_ahead, @move_ahead = @move_ahead, nil
|
125
|
+
move_ahead ? "index += #{move_ahead}" : 'index'
|
126
|
+
end
|
127
|
+
|
128
|
+
def continue
|
129
|
+
dup = self.dup
|
130
|
+
dup.before << dup.current
|
131
|
+
dup.current = dup.after.shift
|
132
|
+
dup.go
|
133
|
+
end
|
134
|
+
|
135
|
+
def go
|
136
|
+
if current then current.write_recognition(self)
|
137
|
+
else self.finish
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def result(key, expression, delay = false)
|
142
|
+
unless delay
|
143
|
+
line "#{key}_value = #{expression}"
|
144
|
+
expression = "#{key}_value"
|
145
|
+
end
|
146
|
+
results[key] = expression
|
147
|
+
end
|
148
|
+
def constant_result(key, object)
|
149
|
+
constants[key] = object
|
150
|
+
end
|
151
|
+
|
152
|
+
def finish(ensure_traversal_finished = true)
|
153
|
+
pairs = []
|
154
|
+
(results.keys + constants.keys).uniq.each do |key|
|
155
|
+
pairs << "#{key.to_s.inspect} => #{results[key] ? results[key] : constants[key].inspect}"
|
156
|
+
end
|
157
|
+
hash_expr = "{#{pairs.join(', ')}}"
|
158
|
+
|
159
|
+
statement = finish_statement.call(hash_expr)
|
160
|
+
if ensure_traversal_finished then self.if("! #{next_segment(true)}") {|gp| gp << statement}
|
161
|
+
else self << statement
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
class GenerationGenerator < CodeGenerator #:nodoc:
|
167
|
+
Attributes = [:after, :before, :current, :segments]
|
168
|
+
attr_accessor(*Attributes)
|
169
|
+
FieldsToDuplicate = CodeGenerator::FieldsToDuplicate + Attributes
|
170
|
+
|
171
|
+
def initialize(*args)
|
172
|
+
super(*args)
|
173
|
+
@after, @before = [], []
|
174
|
+
@current = nil
|
175
|
+
@segments = []
|
176
|
+
end
|
177
|
+
|
178
|
+
def hash_name() 'hash' end
|
179
|
+
def local_name(key) "#{key}_value" end
|
180
|
+
|
181
|
+
def hash_value(key, assign = true, default = nil)
|
182
|
+
if locals.include?(local_name(key)) then code = local_name(key)
|
183
|
+
else
|
184
|
+
code = "hash[#{key.to_sym.inspect}]"
|
185
|
+
if assign
|
186
|
+
code = "(#{local_name(key)} = #{code})"
|
187
|
+
locals << local_name(key)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
code = "(#{code} || (#{default.inspect}))" if default
|
191
|
+
return code
|
192
|
+
end
|
193
|
+
|
194
|
+
def expire_for_keys(*keys)
|
195
|
+
return if keys.empty?
|
196
|
+
conds = keys.collect {|key| "expire_on[#{key.to_sym.inspect}]"}
|
197
|
+
line "not_expired, #{hash_name} = false, options if not_expired && #{conds.join(' && ')}"
|
198
|
+
end
|
199
|
+
|
200
|
+
def add_segment(*segments)
|
201
|
+
d = dup
|
202
|
+
d.segments.concat segments
|
203
|
+
yield d
|
204
|
+
end
|
205
|
+
|
206
|
+
def go
|
207
|
+
if current then current.write_generation(self)
|
208
|
+
else self.finish
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def continue
|
213
|
+
d = dup
|
214
|
+
d.before << d.current
|
215
|
+
d.current = d.after.shift
|
216
|
+
d.go
|
217
|
+
end
|
218
|
+
|
219
|
+
def finish
|
220
|
+
line %("/#{segments.join('/')}")
|
221
|
+
end
|
222
|
+
|
223
|
+
def check_conditions(conditions)
|
224
|
+
tests = []
|
225
|
+
generator = nil
|
226
|
+
conditions.each do |key, condition|
|
227
|
+
tests << (generator || self).hash_value(key, true) if condition.is_a? Regexp
|
228
|
+
tests << Routing.test_condition((generator || self).hash_value(key, false), condition)
|
229
|
+
generator = self.dup unless generator
|
230
|
+
end
|
231
|
+
return tests.join(' && ')
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
@@ -3,17 +3,17 @@ module ActionController #:nodoc:
|
|
3
3
|
# the cookies being written is what will be sent out will the response. Cookies are read by value (so you won't get the cookie object
|
4
4
|
# itself back -- just the value it holds). Examples for writing:
|
5
5
|
#
|
6
|
-
# cookies[
|
7
|
-
# cookies[
|
6
|
+
# cookies[:user_name] = "david" # => Will set a simple session cookie
|
7
|
+
# cookies[:login] = { :value => "XJ-122", :expires => Time.now + 360} # => Will set a cookie that expires in 1 hour
|
8
8
|
#
|
9
9
|
# Examples for reading:
|
10
10
|
#
|
11
|
-
# cookies[
|
11
|
+
# cookies[:user_name] # => "david"
|
12
12
|
# cookies.size # => 2
|
13
13
|
#
|
14
14
|
# Example for deleting:
|
15
15
|
#
|
16
|
-
# cookies.delete
|
16
|
+
# cookies.delete :user_name
|
17
17
|
#
|
18
18
|
# All the option symbols for setting cookies are:
|
19
19
|
#
|
@@ -24,10 +24,16 @@ module ActionController #:nodoc:
|
|
24
24
|
# * <tt>secure</tt> - whether this cookie is a secure cookie or not (default to false).
|
25
25
|
# Secure cookies are only transmitted to HTTPS servers.
|
26
26
|
module Cookies
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
protected
|
28
|
+
# Returns the cookie container, which operates as described above.
|
29
|
+
def cookies
|
30
|
+
CookieJar.new(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Deprecated cookie writer method
|
34
|
+
def cookie(*options)
|
35
|
+
@response.headers["cookie"] << CGI::Cookie.new(*options)
|
36
|
+
end
|
31
37
|
end
|
32
38
|
|
33
39
|
class CookieJar < Hash #:nodoc:
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module ActionController
|
2
|
+
class Base
|
3
|
+
protected
|
4
|
+
# Works like render, but instead of requiring a full template name, you can get by with specifying the action name. So calling
|
5
|
+
# <tt>render_action "show_many"</tt> in WeblogController#display will render "#{template_root}/weblog/show_many.rhtml" or
|
6
|
+
# "#{template_root}/weblog/show_many.rxml".
|
7
|
+
def render_action(action_name, status = nil)
|
8
|
+
render :action => action_name, :status => status
|
9
|
+
end
|
10
|
+
|
11
|
+
# Works like render, but disregards the template_root and requires a full path to the template that needs to be rendered. Can be
|
12
|
+
# used like <tt>render_file "/Users/david/Code/Ruby/template"</tt> to render "/Users/david/Code/Ruby/template.rhtml" or
|
13
|
+
# "/Users/david/Code/Ruby/template.rxml".
|
14
|
+
def render_file(template_path, status = nil, use_full_path = false)
|
15
|
+
render :file => template_path, :status => status, :use_full_path => use_full_path
|
16
|
+
end
|
17
|
+
|
18
|
+
# Renders the +template+ string, which is useful for rendering short templates you don't want to bother having a file for. So
|
19
|
+
# you'd call <tt>render_template "Hello, <%= @user.name %>"</tt> to greet the current user. Or if you want to render as Builder
|
20
|
+
# template, you could do <tt>render_template "xml.h1 @user.name", nil, "rxml"</tt>.
|
21
|
+
def render_template(template, status = nil, type = "rhtml")
|
22
|
+
render :inline => template, :status => status, :type => type
|
23
|
+
end
|
24
|
+
|
25
|
+
# Renders the +text+ string without parsing it through any template engine. Useful for rendering static information as it's
|
26
|
+
# considerably faster than rendering through the template engine.
|
27
|
+
# Use block for response body if provided (useful for deferred rendering or streaming output).
|
28
|
+
def render_text(text = nil, status = nil)
|
29
|
+
render :text => text, :status => status
|
30
|
+
end
|
31
|
+
|
32
|
+
# Renders an empty response that can be used when the request is only interested in triggering an effect. Do note that good
|
33
|
+
# HTTP manners mandate that you don't use GET requests to trigger data changes.
|
34
|
+
def render_nothing(status = nil)
|
35
|
+
render :nothing => true, :status => status
|
36
|
+
end
|
37
|
+
|
38
|
+
# Renders the partial specified by <tt>partial_path</tt>, which by default is the name of the action itself. Example:
|
39
|
+
#
|
40
|
+
# class WeblogController < ActionController::Base
|
41
|
+
# def show
|
42
|
+
# render_partial # renders "weblog/_show.r(xml|html)"
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
def render_partial(partial_path = default_template_name, object = nil, local_assigns = {})
|
46
|
+
render :partial => partial_path, :object => object, :locals => local_assigns
|
47
|
+
end
|
48
|
+
|
49
|
+
# Renders a collection of partials using <tt>partial_name</tt> to iterate over the +collection+.
|
50
|
+
def render_partial_collection(partial_name, collection, partial_spacer_template = nil, local_assigns = {})
|
51
|
+
render :partial => partial_name, :collection => collection, :spacer_template => partial_spacer_template, :locals => local_assigns
|
52
|
+
end
|
53
|
+
|
54
|
+
def render_with_layout(template_name = default_template_name, status = nil, layout = nil)
|
55
|
+
render :template => template_name, :status => status, :layout => layout
|
56
|
+
end
|
57
|
+
|
58
|
+
def render_without_layout(template_name = default_template_name, status = nil)
|
59
|
+
render :template => template_name, :status => status, :layout => false
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# Deprecated in favor of calling redirect_to directly with the path.
|
64
|
+
def redirect_to_path(path)
|
65
|
+
redirect_to(path)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Deprecated in favor of calling redirect_to directly with the url. If the resource has moved permanently, it's possible to pass
|
69
|
+
# true as the second parameter and the browser will get "301 Moved Permanently" instead of "302 Found". This can also be done through
|
70
|
+
# just setting the headers["Status"] to "301 Moved Permanently" before using the redirect_to.
|
71
|
+
def redirect_to_url(url, permanently = false)
|
72
|
+
headers["Status"] = "301 Moved Permanently" if permanently
|
73
|
+
redirect_to(url)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|