actionpack 1.4.0 → 1.5.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 +66 -0
- data/README +94 -64
- data/install.rb +1 -20
- data/lib/action_controller.rb +15 -7
- data/lib/action_controller/assertions/action_pack_assertions.rb +56 -3
- data/lib/action_controller/base.rb +137 -64
- data/lib/action_controller/caching.rb +11 -11
- data/lib/action_controller/cgi_ext/cgi_ext.rb +2 -2
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +4 -4
- data/lib/action_controller/cgi_process.rb +9 -1
- data/lib/action_controller/components.rb +73 -0
- data/lib/action_controller/cookies.rb +1 -1
- data/lib/action_controller/dependencies.rb +6 -1
- data/lib/action_controller/filters.rb +1 -1
- data/lib/action_controller/flash.rb +3 -3
- data/lib/action_controller/helpers.rb +17 -21
- data/lib/action_controller/layout.rb +2 -2
- data/lib/action_controller/request.rb +16 -6
- data/lib/action_controller/rescue.rb +15 -3
- data/lib/action_controller/routing.rb +304 -0
- data/lib/action_controller/scaffolding.rb +10 -12
- data/lib/action_controller/session/active_record_store.rb +4 -7
- data/lib/action_controller/session/mem_cache_store.rb +2 -2
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +9 -1
- data/lib/action_controller/templates/rescues/diagnostics.rhtml +1 -1
- data/lib/action_controller/templates/rescues/routing_error.rhtml +8 -0
- data/lib/action_controller/test_process.rb +29 -7
- data/lib/action_controller/url_rewriter.rb +28 -112
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +44 -17
- data/lib/action_view/helpers/active_record_helper.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +59 -0
- data/lib/action_view/helpers/date_helper.rb +24 -13
- data/lib/action_view/helpers/form_helper.rb +6 -1
- data/lib/action_view/helpers/form_options_helper.rb +87 -9
- data/lib/action_view/helpers/form_tag_helper.rb +80 -0
- data/lib/action_view/helpers/tag_helper.rb +0 -23
- data/lib/action_view/helpers/text_helper.rb +26 -1
- data/lib/action_view/helpers/url_helper.rb +29 -35
- data/lib/action_view/partials.rb +2 -2
- data/lib/action_view/vendor/builder/xmlbase.rb +3 -3
- data/rakefile +5 -2
- data/test/abstract_unit.rb +3 -1
- data/test/controller/action_pack_assertions_test.rb +29 -1
- data/test/controller/active_record_assertions_test.rb +109 -101
- data/test/controller/base_tests.rb +72 -0
- data/test/controller/components_test.rb +74 -0
- data/test/controller/cookie_test.rb +0 -9
- data/test/controller/custom_handler_test.rb +33 -0
- data/test/controller/filters_test.rb +36 -0
- data/test/controller/helper_test.rb +27 -10
- data/test/controller/redirect_test.rb +23 -31
- data/test/controller/render_test.rb +81 -66
- data/test/controller/request_test.rb +22 -0
- data/test/controller/routing_tests.rb +490 -0
- data/test/controller/{url_test.rb → url_obsolete.rb} +24 -14
- data/test/controller/url_obsolete.rb.rej +747 -0
- data/test/fixtures/fun/games/hello_world.rhtml +1 -0
- data/test/fixtures/helpers/fun/games_helper.rb +3 -0
- data/test/template/asset_tag_helper_test.rb +45 -0
- data/test/template/form_options_helper_test.rb +161 -1
- data/test/template/form_tag_helper_test.rb +22 -0
- data/test/template/text_helper_test.rb +7 -0
- data/test/template/url_helper_test.rb +5 -2
- data/test/template/url_helper_test.rb.rej +105 -0
- metadata +32 -27
- data/lib/action_controller/support/binding_of_caller.rb +0 -83
- data/lib/action_controller/support/breakpoint.rb +0 -518
- data/lib/action_controller/support/class_attribute_accessors.rb +0 -57
- data/lib/action_controller/support/class_inheritable_attributes.rb +0 -117
- data/lib/action_controller/support/clean_logger.rb +0 -10
- data/lib/action_controller/support/core_ext.rb +0 -1
- data/lib/action_controller/support/core_ext/hash.rb +0 -5
- data/lib/action_controller/support/core_ext/hash/keys.rb +0 -35
- data/lib/action_controller/support/core_ext/numeric.rb +0 -7
- data/lib/action_controller/support/core_ext/numeric/bytes.rb +0 -33
- data/lib/action_controller/support/core_ext/numeric/time.rb +0 -59
- data/lib/action_controller/support/core_ext/object_and_class.rb +0 -24
- data/lib/action_controller/support/core_ext/string.rb +0 -5
- data/lib/action_controller/support/core_ext/string/inflections.rb +0 -45
- data/lib/action_controller/support/dependencies.rb +0 -63
- data/lib/action_controller/support/inflector.rb +0 -84
- data/lib/action_controller/support/misc.rb +0 -8
- data/lib/action_controller/support/module_attribute_accessors.rb +0 -57
@@ -44,10 +44,10 @@ module ActionController
|
|
44
44
|
# def create
|
45
45
|
# @entry = Entry.new(@params["entry"])
|
46
46
|
# if @entry.save
|
47
|
-
# flash["notice"] = "Entry was
|
47
|
+
# flash["notice"] = "Entry was successfully created"
|
48
48
|
# redirect_to :action => "list"
|
49
49
|
# else
|
50
|
-
#
|
50
|
+
# render_scaffold('new')
|
51
51
|
# end
|
52
52
|
# end
|
53
53
|
#
|
@@ -61,10 +61,10 @@ module ActionController
|
|
61
61
|
# @entry.attributes = @params["entry"]
|
62
62
|
#
|
63
63
|
# if @entry.save
|
64
|
-
# flash["notice"] = "Entry was
|
64
|
+
# flash["notice"] = "Entry was successfully updated"
|
65
65
|
# redirect_to :action => "show/" + @entry.id.to_s
|
66
66
|
# else
|
67
|
-
#
|
67
|
+
# render_scaffold('edit')
|
68
68
|
# end
|
69
69
|
# end
|
70
70
|
# end
|
@@ -84,8 +84,6 @@ module ActionController
|
|
84
84
|
def scaffold(model_id, options = {})
|
85
85
|
validate_options([ :class_name, :suffix ], options.keys)
|
86
86
|
|
87
|
-
require "#{model_id.id2name}" rescue logger.warn "Couldn't auto-require #{model_id.id2name}.rb" unless logger.nil?
|
88
|
-
|
89
87
|
singular_name = model_id.id2name
|
90
88
|
class_name = options[:class_name] || Inflector.camelize(singular_name)
|
91
89
|
plural_name = Inflector.pluralize(singular_name)
|
@@ -123,10 +121,10 @@ module ActionController
|
|
123
121
|
def create#{suffix}
|
124
122
|
@#{singular_name} = #{class_name}.new(@params["#{singular_name}"])
|
125
123
|
if @#{singular_name}.save
|
126
|
-
flash["notice"] = "#{class_name} was
|
124
|
+
flash["notice"] = "#{class_name} was successfully created"
|
127
125
|
redirect_to :action => "list#{suffix}"
|
128
126
|
else
|
129
|
-
render
|
127
|
+
render#{suffix}_scaffold('new')
|
130
128
|
end
|
131
129
|
end
|
132
130
|
|
@@ -140,16 +138,16 @@ module ActionController
|
|
140
138
|
@#{singular_name}.attributes = @params["#{singular_name}"]
|
141
139
|
|
142
140
|
if @#{singular_name}.save
|
143
|
-
flash["notice"] = "#{class_name} was
|
144
|
-
redirect_to :action => "show#{suffix}
|
141
|
+
flash["notice"] = "#{class_name} was successfully updated"
|
142
|
+
redirect_to :action => "show#{suffix}", :id => @#{singular_name}.id.to_s
|
145
143
|
else
|
146
|
-
render
|
144
|
+
render#{suffix}_scaffold('edit')
|
147
145
|
end
|
148
146
|
end
|
149
147
|
|
150
148
|
private
|
151
149
|
def render#{suffix}_scaffold(action = caller_method_name(caller))
|
152
|
-
if template_exists?("\#{
|
150
|
+
if template_exists?("\#{self.class.controller_path}/\#{action}")
|
153
151
|
render_action(action)
|
154
152
|
else
|
155
153
|
@scaffold_class = #{class_name}
|
@@ -29,11 +29,9 @@ class CGI
|
|
29
29
|
#
|
30
30
|
# This session's ActiveRecord database row will be created if it does not exist, or opened if it does.
|
31
31
|
def initialize(session, option=nil)
|
32
|
-
|
33
|
-
|
34
|
-
@data
|
35
|
-
else
|
36
|
-
@session = Session.new("sessid" => session.session_id, "data" => {})
|
32
|
+
ActiveRecord::Base.silence do
|
33
|
+
@session = Session.find_by_sessid(session.session_id) || Session.new("sessid" => session.session_id, "data" => {})
|
34
|
+
@data = @session.data
|
37
35
|
end
|
38
36
|
end
|
39
37
|
|
@@ -60,8 +58,7 @@ class CGI
|
|
60
58
|
# Save session state in the session's ActiveRecord object.
|
61
59
|
def update
|
62
60
|
return unless @session
|
63
|
-
@session.data
|
64
|
-
@session.save
|
61
|
+
ActiveRecord::Base.silence { @session.update_attribute "data", @data }
|
65
62
|
end
|
66
63
|
end #ActiveRecordStore
|
67
64
|
end #Session
|
@@ -33,7 +33,7 @@ begin
|
|
33
33
|
# characters; automatically generated session ids observe
|
34
34
|
# this requirement.
|
35
35
|
#
|
36
|
-
# +option+ is a hash of options for the
|
36
|
+
# +option+ 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
|
@@ -92,4 +92,4 @@ begin
|
|
92
92
|
end
|
93
93
|
rescue LoadError
|
94
94
|
# MemCache wasn't available so neither can the store be
|
95
|
-
end
|
95
|
+
end
|
@@ -1,6 +1,11 @@
|
|
1
|
+
<% if @exception.blamed_files && !@exception.blamed_files.empty? %>
|
2
|
+
<a href="#" onclick="document.getElementById('blame_trace').style.display='block'; return false;">Show blamed files</a>
|
3
|
+
<pre id="blame_trace" style="display:none"><code><%=h @exception.describe_blame %></code></pre>
|
4
|
+
<% end %>
|
5
|
+
|
1
6
|
<% if defined?(Breakpoint) %>
|
2
7
|
<br /><br />
|
3
|
-
|
8
|
+
<% begin %><%= form_tag({:params => {}, :only_path => true}, "method" => @request.method) %>
|
4
9
|
<input type="hidden" name="BP-RETRY" value="1" />
|
5
10
|
|
6
11
|
<% for key, values in @params %>
|
@@ -12,6 +17,9 @@
|
|
12
17
|
|
13
18
|
<input type="submit" value="Retry with Breakpoint" />
|
14
19
|
</form>
|
20
|
+
<% rescue Exception => e %>
|
21
|
+
<%=h "Couldn't render breakpoint link due to #{e.class} #{e.message}" %>
|
22
|
+
<% end %>
|
15
23
|
<% end %>
|
16
24
|
|
17
25
|
<%
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
<h1>
|
8
8
|
<%=h @exception.class.to_s %> in
|
9
|
-
<%=h @request.parameters["controller"].capitalize %>#<%=h @request.parameters["action"] %>
|
9
|
+
<%=h (@request.parameters["controller"] || "<controller not set>").capitalize %>#<%=h @request.parameters["action"] || "<action not set>" %>
|
10
10
|
</h1>
|
11
11
|
<p><%=h Object.const_defined?(:RAILS_ROOT) ? @exception.message.gsub(RAILS_ROOT, "") : @exception.message %></p>
|
12
12
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<h1>Routing Error</h1>
|
2
|
+
<p><%=h @exception.message %></p>
|
3
|
+
<% unless @exception.failures.empty? %><p>
|
4
|
+
<h2>Failure reasons:</h2>
|
5
|
+
<% @exception.failures.each do |route, reason| %>
|
6
|
+
<%=h route.inspect.gsub('\\', '') %> failed because <%=h reason.downcase %><br />
|
7
|
+
<% end %>
|
8
|
+
</p><% end %>
|
@@ -30,9 +30,9 @@ module ActionController #:nodoc:
|
|
30
30
|
end
|
31
31
|
|
32
32
|
class TestRequest < AbstractRequest #:nodoc:
|
33
|
-
|
34
|
-
attr_accessor :query_parameters, :request_parameters, :session, :env
|
35
|
-
attr_accessor :host, :
|
33
|
+
attr_accessor :cookies
|
34
|
+
attr_accessor :query_parameters, :request_parameters, :path, :session, :env
|
35
|
+
attr_accessor :host, :remote_addr
|
36
36
|
|
37
37
|
def initialize(query_parameters = nil, request_parameters = nil, session = nil)
|
38
38
|
@query_parameters = query_parameters || {}
|
@@ -49,10 +49,6 @@ module ActionController #:nodoc:
|
|
49
49
|
@session = {}
|
50
50
|
end
|
51
51
|
|
52
|
-
def cookies
|
53
|
-
@cookies.freeze
|
54
|
-
end
|
55
|
-
|
56
52
|
def port=(number)
|
57
53
|
@env["SERVER_PORT"] = number.to_i
|
58
54
|
end
|
@@ -62,11 +58,28 @@ module ActionController #:nodoc:
|
|
62
58
|
@parameters = nil
|
63
59
|
end
|
64
60
|
|
61
|
+
# Used to check AbstractRequest's request_uri functionality.
|
62
|
+
# Disables the use of @path and @request_uri so superclass can handle those.
|
63
|
+
def set_REQUEST_URI(value)
|
64
|
+
@env["REQUEST_URI"] = value
|
65
|
+
@request_uri = nil
|
66
|
+
@path = nil
|
67
|
+
end
|
68
|
+
|
65
69
|
def request_uri=(uri)
|
66
70
|
@request_uri = uri
|
67
71
|
@path = uri.split("?").first
|
68
72
|
end
|
69
73
|
|
74
|
+
def request_uri
|
75
|
+
@request_uri || super()
|
76
|
+
end
|
77
|
+
|
78
|
+
def path
|
79
|
+
@path || super()
|
80
|
+
end
|
81
|
+
|
82
|
+
|
70
83
|
private
|
71
84
|
def initialize_containers
|
72
85
|
@env, @cookies = {}, {}
|
@@ -241,6 +254,7 @@ module Test
|
|
241
254
|
def process(action, parameters = nil, session = nil)
|
242
255
|
@request.env['REQUEST_METHOD'] ||= "GET"
|
243
256
|
@request.action = action.to_s
|
257
|
+
@request.path_parameters = { :controller => @controller.class.controller_path }
|
244
258
|
@request.parameters.update(parameters) unless parameters.nil?
|
245
259
|
@request.session = ActionController::TestSession.new(session) unless session.nil?
|
246
260
|
@controller.process(@request, @response)
|
@@ -255,6 +269,14 @@ module Test
|
|
255
269
|
end
|
256
270
|
EOV
|
257
271
|
end
|
272
|
+
|
273
|
+
def follow_redirect
|
274
|
+
if @response.redirected_to[:controller]
|
275
|
+
raise "Can't follow redirects outside of current controller (#{@response.redirected_to[:controller]})"
|
276
|
+
end
|
277
|
+
|
278
|
+
get(@response.redirected_to.delete(:action), @response.redirected_to.stringify_keys)
|
279
|
+
end
|
258
280
|
end
|
259
281
|
end
|
260
282
|
end
|
@@ -1,121 +1,46 @@
|
|
1
1
|
module ActionController
|
2
|
-
# Rewrites
|
2
|
+
# Rewrites URLs for Base.redirect_to and Base.url_for in the controller.
|
3
|
+
|
3
4
|
class UrlRewriter #:nodoc:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
@request, @controller, @action = request, controller, action
|
5
|
+
RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol]
|
6
|
+
def initialize(request, parameters)
|
7
|
+
@request, @parameters = request, parameters
|
8
8
|
@rewritten_path = @request.path ? @request.path.dup : ""
|
9
9
|
end
|
10
10
|
|
11
11
|
def rewrite(options = {})
|
12
|
-
|
13
|
-
|
14
|
-
rewrite_url(
|
15
|
-
rewrite_path(@rewritten_path, resolve_aliases(options)),
|
16
|
-
options
|
17
|
-
)
|
18
|
-
end
|
19
|
-
|
20
|
-
def to_s
|
21
|
-
to_str
|
12
|
+
rewrite_url(rewrite_path(options), options)
|
22
13
|
end
|
23
14
|
|
24
15
|
def to_str
|
25
|
-
|
16
|
+
"#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@parameters[:controller]}, #{@parameters[:action]}, #{@request.parameters.inspect}"
|
26
17
|
end
|
27
18
|
|
28
|
-
|
29
|
-
def validate_options(valid_option_keys, supplied_option_keys)
|
30
|
-
unknown_option_keys = supplied_option_keys - valid_option_keys
|
31
|
-
raise(ActionController::ActionControllerError, "Unknown options: #{unknown_option_keys}") unless unknown_option_keys.empty?
|
32
|
-
end
|
33
|
-
|
34
|
-
def resolve_aliases(options)
|
35
|
-
options[:controller_prefix] = options[:module] unless options[:module].nil?
|
36
|
-
options
|
37
|
-
end
|
19
|
+
alias_method :to_s, :to_str
|
38
20
|
|
21
|
+
private
|
39
22
|
def rewrite_url(path, options)
|
40
23
|
rewritten_url = ""
|
41
24
|
rewritten_url << (options[:protocol] || @request.protocol) unless options[:only_path]
|
42
25
|
rewritten_url << (options[:host] || @request.host_with_port) unless options[:only_path]
|
43
26
|
|
44
|
-
|
27
|
+
rewritten_url << options[:application_prefix] if options[:application_prefix]
|
45
28
|
rewritten_url << path
|
46
|
-
rewritten_url << build_query_string(new_parameters(options)) if options[:params] || options[:overwrite_params]
|
47
29
|
rewritten_url << "##{options[:anchor]}" if options[:anchor]
|
48
|
-
return rewritten_url
|
49
|
-
end
|
50
30
|
|
51
|
-
|
52
|
-
include_id_in_path_params(options)
|
53
|
-
|
54
|
-
path = rewrite_action(path, options) if options[:action] || options[:action_prefix]
|
55
|
-
path = rewrite_path_params(path, options) if options[:path_params]
|
56
|
-
path = rewrite_controller(path, options) if options[:controller] || options[:controller_prefix]
|
57
|
-
return path
|
58
|
-
end
|
59
|
-
|
60
|
-
def rewrite_path_params(path, options)
|
61
|
-
index_action = options[:action] == 'index' || options[:action].nil? && @action == 'index'
|
62
|
-
id_only = options[:path_params].size == 1 && options[:path_params]['id']
|
63
|
-
|
64
|
-
if index_action && id_only
|
65
|
-
path += '/' unless path[-1..-1] == '/'
|
66
|
-
path += "index/#{options[:path_params]['id']}"
|
67
|
-
path
|
68
|
-
else
|
69
|
-
options[:path_params].inject(path) do |path, pair|
|
70
|
-
if options[:action].nil? && @request.parameters[pair.first]
|
71
|
-
path.sub(/\b#{@request.parameters[pair.first]}\b/, pair.last.to_s)
|
72
|
-
else
|
73
|
-
path += "/#{pair.last}"
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
31
|
+
return rewritten_url
|
77
32
|
end
|
78
33
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
path = path.sub(action_prefix, action_name(options, nil))
|
89
|
-
elsif action_prefix && !action_prefix.empty?
|
90
|
-
path = path.sub(%r(/#{action_prefix}/?), "/" + action_name(options, action_prefix))
|
91
|
-
else
|
92
|
-
path = path.sub(%r(#{@controller}/?$), @controller + "/" + action_name(options)) # " ruby-mode
|
93
|
-
end
|
94
|
-
else
|
95
|
-
path = path.sub(
|
96
|
-
@controller + "/" + (action_prefix || "") + @action + (action_suffix || ""),
|
97
|
-
@controller + "/" + action_name(options, action_prefix)
|
98
|
-
)
|
99
|
-
end
|
100
|
-
|
101
|
-
if options[:controller_prefix] && !options[:controller]
|
102
|
-
ensure_slash_suffix(options, :controller_prefix)
|
103
|
-
if controller_prefix
|
104
|
-
path = path.sub(controller_prefix, options[:controller_prefix])
|
105
|
-
else
|
106
|
-
path = options[:controller_prefix] + path
|
107
|
-
end
|
108
|
-
end
|
34
|
+
def rewrite_path(options)
|
35
|
+
options = options.symbolize_keys
|
36
|
+
options.update((options[:params]).symbolize_keys) if options[:params]
|
37
|
+
RESERVED_OPTIONS.each {|k| options.delete k}
|
38
|
+
|
39
|
+
path, extras = Routing::Routes.generate(options, @request)
|
40
|
+
path = "/#{path.join('/')}".chomp '/'
|
41
|
+
path = '/' if path.empty?
|
42
|
+
path += build_query_string(extras)
|
109
43
|
|
110
|
-
return path
|
111
|
-
end
|
112
|
-
|
113
|
-
def rewrite_controller(path, options)
|
114
|
-
all, controller_prefix = /^\/(.*?)#{@controller}/.match(path).to_a
|
115
|
-
path = "/"
|
116
|
-
path << controller_name(options, controller_prefix)
|
117
|
-
path << action_name(options) if options[:action]
|
118
|
-
path << path_params_in_list(options) if options[:path_params]
|
119
44
|
return path
|
120
45
|
end
|
121
46
|
|
@@ -159,30 +84,21 @@ module ActionController
|
|
159
84
|
options[:path_params] = (options[:path_params] || {}).merge({"id" => options[:id]}) if options[:id]
|
160
85
|
end
|
161
86
|
|
162
|
-
def new_parameters(options)
|
163
|
-
parameters = options[:params] || existing_parameters
|
164
|
-
parameters.update(options[:overwrite_params]) if options[:overwrite_params]
|
165
|
-
parameters.reject { |key,value| value.nil? }
|
166
|
-
end
|
167
|
-
|
168
|
-
def existing_parameters
|
169
|
-
@request.parameters.reject { |key, value| %w( id action controller).include?(key) }
|
170
|
-
end
|
171
|
-
|
172
87
|
# Returns a query string with escaped keys and values from the passed hash. If the passed hash contains an "id" it'll
|
173
88
|
# be added as a path element instead of a regular parameter pair.
|
174
89
|
def build_query_string(hash)
|
175
90
|
elements = []
|
176
91
|
query_string = ""
|
177
|
-
|
92
|
+
|
178
93
|
hash.each do |key, value|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
94
|
+
key = key.to_s
|
95
|
+
key = CGI.escape key
|
96
|
+
key += '[]' if value.class == Array
|
97
|
+
value = [ value ] unless value.class == Array
|
98
|
+
value.each { |val| elements << "#{key}=#{CGI.escape(val.to_s)}" }
|
99
|
+
end
|
185
100
|
|
101
|
+
query_string << ("?" + elements.join("&")) unless elements.empty?
|
186
102
|
return query_string
|
187
103
|
end
|
188
104
|
end
|
data/lib/action_view.rb
CHANGED
data/lib/action_view/base.rb
CHANGED
@@ -61,12 +61,12 @@ module ActionView #:nodoc:
|
|
61
61
|
#
|
62
62
|
# The parsing of ERb templates are cached by default, but the reading of them are not. This means that the application by default
|
63
63
|
# will reflect changes to the templates immediatly. If you'd like to sacrifice that immediacy for the speed gain given by also
|
64
|
-
# caching the loading of templates (reading from the file
|
64
|
+
# caching the loading of templates (reading from the file system), you can turn that on with
|
65
65
|
# <tt>ActionView::Base.cache_template_loading = true</tt>.
|
66
66
|
#
|
67
67
|
# == Builder
|
68
68
|
#
|
69
|
-
# Builder templates are a more
|
69
|
+
# Builder templates are a more programmatic alternative to ERb. They are especially useful for generating XML content. An +XmlMarkup+ object
|
70
70
|
# named +xml+ is automatically made available to templates with a +.rxml+ extension.
|
71
71
|
#
|
72
72
|
# Here are some basic examples:
|
@@ -130,6 +130,7 @@ module ActionView #:nodoc:
|
|
130
130
|
|
131
131
|
@@compiled_erb_templates = {}
|
132
132
|
@@loaded_templates = {}
|
133
|
+
@@template_handlers = {}
|
133
134
|
|
134
135
|
def self.load_helpers(helper_dir)#:nodoc:
|
135
136
|
Dir.foreach(helper_dir) do |helper_file|
|
@@ -151,6 +152,10 @@ module ActionView #:nodoc:
|
|
151
152
|
end
|
152
153
|
end
|
153
154
|
|
155
|
+
def self.register_template_handler(extension, klass)
|
156
|
+
@@template_handlers[extension] = klass
|
157
|
+
end
|
158
|
+
|
154
159
|
def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)#:nodoc:
|
155
160
|
@base_path, @assigns = base_path, assigns_for_first_render
|
156
161
|
@controller = controller
|
@@ -193,26 +198,32 @@ module ActionView #:nodoc:
|
|
193
198
|
# Renders the +template+ which is given as a string as either rhtml or rxml depending on <tt>template_extension</tt>.
|
194
199
|
# The hash in <tt>local_assigns</tt> is made available as local variables.
|
195
200
|
def render_template(template_extension, template, local_assigns = {})
|
196
|
-
|
197
|
-
|
198
|
-
@assigns.each { |key, value| instance_variable_set "@#{key}", value }
|
199
|
-
xml = Builder::XmlMarkup.new(:indent => 2)
|
200
|
-
|
201
|
-
send(pick_rendering_method(template_extension), template, binding)
|
201
|
+
send(pick_rendering_method(template_extension), template_extension,
|
202
|
+
template, local_assigns)
|
202
203
|
end
|
203
204
|
|
204
205
|
def pick_template_extension(template_path)#:nodoc:
|
205
|
-
if
|
206
|
+
if match = delegate_template_exists?(template_path)
|
207
|
+
match.first
|
208
|
+
elsif erb_template_exists?(template_path)
|
206
209
|
"rhtml"
|
207
210
|
elsif builder_template_exists?(template_path)
|
208
211
|
"rxml"
|
209
212
|
else
|
210
|
-
raise ActionViewError, "No rhtml or
|
213
|
+
raise ActionViewError, "No rhtml, rxml, or delegate template found for #{template_path}"
|
211
214
|
end
|
212
215
|
end
|
213
216
|
|
214
217
|
def pick_rendering_method(template_extension)#:nodoc:
|
215
|
-
|
218
|
+
if @@template_handlers[template_extension]
|
219
|
+
"delegate_render"
|
220
|
+
else
|
221
|
+
(template_extension == "rxml" ? "rxml" : "rhtml") + "_render"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def delegate_template_exists?(template_path)#:nodoc:
|
226
|
+
@@template_handlers.find { |k,| template_exists?(template_path, k) }
|
216
227
|
end
|
217
228
|
|
218
229
|
def erb_template_exists?(template_path)#:nodoc:
|
@@ -224,7 +235,7 @@ module ActionView #:nodoc:
|
|
224
235
|
end
|
225
236
|
|
226
237
|
def file_exists?(template_path)#:nodoc:
|
227
|
-
erb_template_exists?(template_path) || builder_template_exists?(template_path)
|
238
|
+
erb_template_exists?(template_path) || builder_template_exists?(template_path) || delegate_template_exists?(template_path)
|
228
239
|
end
|
229
240
|
|
230
241
|
# Returns true is the file may be rendered implicitly.
|
@@ -250,16 +261,32 @@ module ActionView #:nodoc:
|
|
250
261
|
@@loaded_templates[template_path]
|
251
262
|
end
|
252
263
|
|
253
|
-
def
|
264
|
+
def evaluate_locals(local_assigns = {})
|
265
|
+
b = binding
|
266
|
+
|
267
|
+
local_assigns.each { |key, value| eval "#{key} = local_assigns[\"#{key}\"]", b }
|
268
|
+
@assigns.each { |key, value| instance_variable_set "@#{key}", value }
|
269
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
270
|
+
|
271
|
+
b
|
272
|
+
end
|
273
|
+
|
274
|
+
def rhtml_render(extension, template, local_assigns)
|
275
|
+
b = evaluate_locals(local_assigns)
|
254
276
|
@@compiled_erb_templates[template] ||= ERB.new(template, nil, '-')
|
255
|
-
@@compiled_erb_templates[template].result(
|
277
|
+
@@compiled_erb_templates[template].result(b)
|
256
278
|
end
|
257
279
|
|
258
|
-
def rxml_render(template,
|
280
|
+
def rxml_render(extension, template, local_assigns)
|
259
281
|
@controller.headers["Content-Type"] ||= 'text/xml'
|
260
|
-
eval(template,
|
282
|
+
eval(template, evaluate_locals(local_assigns))
|
283
|
+
end
|
284
|
+
|
285
|
+
def delegate_render(extension, template, local_assigns)
|
286
|
+
delegator = @@template_handlers[extension].new(self)
|
287
|
+
delegator.render(template, local_assigns)
|
261
288
|
end
|
262
289
|
end
|
263
290
|
end
|
264
291
|
|
265
|
-
require 'action_view/template_error'
|
292
|
+
require 'action_view/template_error'
|