actionpack 2.0.5 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +149 -7
- data/MIT-LICENSE +1 -1
- data/README +1 -1
- data/Rakefile +5 -6
- data/lib/action_controller.rb +2 -2
- data/lib/action_controller/assertions/model_assertions.rb +2 -1
- data/lib/action_controller/assertions/response_assertions.rb +4 -2
- data/lib/action_controller/assertions/routing_assertions.rb +3 -3
- data/lib/action_controller/assertions/selector_assertions.rb +30 -27
- data/lib/action_controller/assertions/tag_assertions.rb +3 -3
- data/lib/action_controller/base.rb +103 -129
- data/lib/action_controller/benchmarking.rb +3 -3
- data/lib/action_controller/caching.rb +41 -652
- data/lib/action_controller/caching/actions.rb +144 -0
- data/lib/action_controller/caching/fragments.rb +138 -0
- data/lib/action_controller/caching/pages.rb +154 -0
- data/lib/action_controller/caching/sql_cache.rb +18 -0
- data/lib/action_controller/caching/sweeping.rb +97 -0
- data/lib/action_controller/cgi_ext/cookie.rb +27 -23
- data/lib/action_controller/cgi_ext/stdinput.rb +1 -0
- data/lib/action_controller/cgi_process.rb +6 -4
- data/lib/action_controller/components.rb +7 -6
- data/lib/action_controller/cookies.rb +31 -19
- data/lib/action_controller/dispatcher.rb +51 -84
- data/lib/action_controller/filters.rb +295 -421
- data/lib/action_controller/flash.rb +1 -6
- data/lib/action_controller/headers.rb +31 -0
- data/lib/action_controller/helpers.rb +26 -9
- data/lib/action_controller/http_authentication.rb +1 -1
- data/lib/action_controller/integration.rb +65 -13
- data/lib/action_controller/layout.rb +24 -39
- data/lib/action_controller/mime_responds.rb +7 -3
- data/lib/action_controller/mime_type.rb +25 -9
- data/lib/action_controller/mime_types.rb +1 -1
- data/lib/action_controller/polymorphic_routes.rb +32 -17
- data/lib/action_controller/record_identifier.rb +10 -4
- data/lib/action_controller/request.rb +46 -30
- data/lib/action_controller/request_forgery_protection.rb +10 -9
- data/lib/action_controller/request_profiler.rb +29 -8
- data/lib/action_controller/rescue.rb +24 -24
- data/lib/action_controller/resources.rb +66 -23
- data/lib/action_controller/response.rb +2 -2
- data/lib/action_controller/routing.rb +113 -1229
- data/lib/action_controller/routing/builder.rb +204 -0
- data/lib/action_controller/{routing_optimisation.rb → routing/optimisations.rb} +13 -12
- data/lib/action_controller/routing/recognition_optimisation.rb +158 -0
- data/lib/action_controller/routing/route.rb +240 -0
- data/lib/action_controller/routing/route_set.rb +435 -0
- data/lib/action_controller/routing/routing_ext.rb +46 -0
- data/lib/action_controller/routing/segments.rb +283 -0
- data/lib/action_controller/session/active_record_store.rb +13 -8
- data/lib/action_controller/session/cookie_store.rb +20 -17
- data/lib/action_controller/session_management.rb +10 -3
- data/lib/action_controller/streaming.rb +45 -31
- data/lib/action_controller/test_case.rb +33 -23
- data/lib/action_controller/test_process.rb +39 -35
- data/lib/action_controller/url_rewriter.rb +18 -12
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -1
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +11 -3
- data/lib/action_view/base.rb +73 -390
- data/lib/action_view/helpers/active_record_helper.rb +83 -62
- data/lib/action_view/helpers/asset_tag_helper.rb +101 -44
- data/lib/action_view/helpers/atom_feed_helper.rb +35 -7
- data/lib/action_view/helpers/benchmark_helper.rb +5 -3
- data/lib/action_view/helpers/cache_helper.rb +3 -2
- data/lib/action_view/helpers/capture_helper.rb +1 -2
- data/lib/action_view/helpers/date_helper.rb +104 -82
- data/lib/action_view/helpers/form_helper.rb +148 -75
- data/lib/action_view/helpers/form_options_helper.rb +44 -23
- data/lib/action_view/helpers/form_tag_helper.rb +22 -13
- data/lib/action_view/helpers/javascripts/controls.js +1 -1
- data/lib/action_view/helpers/javascripts/dragdrop.js +1 -1
- data/lib/action_view/helpers/javascripts/effects.js +1 -1
- data/lib/action_view/helpers/number_helper.rb +10 -3
- data/lib/action_view/helpers/prototype_helper.rb +61 -29
- data/lib/action_view/helpers/record_tag_helper.rb +3 -3
- data/lib/action_view/helpers/sanitize_helper.rb +23 -17
- data/lib/action_view/helpers/scriptaculous_helper.rb +86 -60
- data/lib/action_view/helpers/text_helper.rb +153 -125
- data/lib/action_view/helpers/url_helper.rb +83 -28
- data/lib/action_view/inline_template.rb +20 -0
- data/lib/action_view/partial_template.rb +70 -0
- data/lib/action_view/partials.rb +31 -73
- data/lib/action_view/template.rb +127 -0
- data/lib/action_view/template_error.rb +8 -7
- data/lib/action_view/template_finder.rb +177 -0
- data/lib/action_view/template_handler.rb +18 -1
- data/lib/action_view/template_handlers/builder.rb +10 -2
- data/lib/action_view/template_handlers/compilable.rb +128 -0
- data/lib/action_view/template_handlers/erb.rb +37 -2
- data/lib/action_view/template_handlers/rjs.rb +14 -1
- data/lib/action_view/test_case.rb +58 -0
- data/test/abstract_unit.rb +1 -1
- data/test/active_record_unit.rb +3 -6
- data/test/activerecord/active_record_store_test.rb +1 -2
- data/test/activerecord/render_partial_with_record_identification_test.rb +158 -41
- data/test/adv_attr_test.rb +20 -0
- data/test/controller/action_pack_assertions_test.rb +16 -19
- data/test/controller/addresses_render_test.rb +1 -1
- data/test/controller/assert_select_test.rb +13 -6
- data/test/controller/base_test.rb +48 -2
- data/test/controller/benchmark_test.rb +1 -2
- data/test/controller/caching_test.rb +282 -21
- data/test/controller/capture_test.rb +1 -1
- data/test/controller/cgi_test.rb +1 -1
- data/test/controller/components_test.rb +1 -1
- data/test/controller/content_type_test.rb +2 -2
- data/test/controller/cookie_test.rb +13 -2
- data/test/controller/custom_handler_test.rb +14 -10
- data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -1
- data/test/controller/dispatcher_test.rb +31 -49
- data/test/controller/fake_controllers.rb +17 -0
- data/test/controller/fake_models.rb +6 -0
- data/test/controller/filter_params_test.rb +14 -8
- data/test/controller/filters_test.rb +44 -16
- data/test/controller/flash_test.rb +2 -2
- data/test/controller/header_test.rb +14 -0
- data/test/controller/helper_test.rb +19 -15
- data/test/controller/html-scanner/document_test.rb +1 -2
- data/test/controller/html-scanner/node_test.rb +1 -2
- data/test/controller/html-scanner/sanitizer_test.rb +8 -5
- data/test/controller/html-scanner/tag_node_test.rb +1 -2
- data/test/controller/html-scanner/text_node_test.rb +2 -3
- data/test/controller/html-scanner/tokenizer_test.rb +8 -2
- data/test/controller/http_authentication_test.rb +1 -1
- data/test/controller/integration_test.rb +14 -16
- data/test/controller/integration_upload_test.rb +43 -0
- data/test/controller/layout_test.rb +26 -6
- data/test/controller/mime_responds_test.rb +39 -7
- data/test/controller/mime_type_test.rb +29 -5
- data/test/controller/new_render_test.rb +105 -34
- data/test/controller/polymorphic_routes_test.rb +32 -20
- data/test/controller/record_identifier_test.rb +38 -2
- data/test/controller/redirect_test.rb +21 -1
- data/test/controller/render_test.rb +59 -15
- data/test/controller/request_forgery_protection_test.rb +92 -5
- data/test/controller/request_test.rb +64 -6
- data/test/controller/rescue_test.rb +22 -6
- data/test/controller/resources_test.rb +102 -14
- data/test/controller/routing_test.rb +231 -19
- data/test/controller/selector_test.rb +2 -2
- data/test/controller/send_file_test.rb +14 -3
- data/test/controller/session/cookie_store_test.rb +16 -4
- data/test/controller/session/mem_cache_store_test.rb +3 -4
- data/test/controller/session_fixation_test.rb +1 -1
- data/test/controller/session_management_test.rb +23 -1
- data/test/controller/test_test.rb +39 -18
- data/test/controller/url_rewriter_test.rb +35 -1
- data/test/controller/verification_test.rb +1 -1
- data/test/controller/view_paths_test.rb +15 -12
- data/test/controller/webservice_test.rb +48 -3
- data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
- data/test/fixtures/company.rb +1 -0
- data/test/fixtures/customers/_customer.html.erb +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +6 -0
- data/test/fixtures/functional_caching/_partial.erb +3 -0
- data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
- data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
- data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
- data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
- data/test/fixtures/mascot.rb +3 -0
- data/test/fixtures/mascots.yml +4 -0
- data/test/fixtures/mascots/_mascot.html.erb +1 -0
- data/test/fixtures/multipart/boundary_problem_file +10 -0
- data/test/fixtures/public/javascripts/application.js +1 -0
- data/test/fixtures/public/javascripts/controls.js +1 -0
- data/test/fixtures/public/javascripts/dragdrop.js +1 -0
- data/test/fixtures/public/javascripts/effects.js +1 -0
- data/test/fixtures/public/javascripts/prototype.js +1 -0
- data/test/fixtures/public/javascripts/version.1.0.js +1 -0
- data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
- data/test/fixtures/reply.rb +1 -0
- data/test/fixtures/shared.html.erb +1 -0
- data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
- data/test/fixtures/test/_customer_counter.erb +1 -0
- data/test/fixtures/test/_form.erb +1 -0
- data/test/fixtures/test/_labelling_form.erb +1 -0
- data/test/fixtures/test/_raise.html.erb +1 -0
- data/test/fixtures/test/greeting.js.rjs +1 -0
- data/test/fixtures/topics/_topic.html.erb +1 -0
- data/test/template/active_record_helper_test.rb +25 -8
- data/test/template/asset_tag_helper_test.rb +100 -17
- data/test/template/atom_feed_helper_test.rb +29 -1
- data/test/template/benchmark_helper_test.rb +10 -22
- data/test/template/date_helper_test.rb +455 -153
- data/test/template/erb_util_test.rb +10 -42
- data/test/template/form_helper_test.rb +192 -66
- data/test/template/form_options_helper_test.rb +19 -8
- data/test/template/form_tag_helper_test.rb +11 -8
- data/test/template/javascript_helper_test.rb +3 -9
- data/test/template/number_helper_test.rb +6 -3
- data/test/template/prototype_helper_test.rb +27 -40
- data/test/template/record_tag_helper_test.rb +54 -0
- data/test/template/sanitize_helper_test.rb +5 -6
- data/test/template/scriptaculous_helper_test.rb +7 -13
- data/test/template/tag_helper_test.rb +3 -6
- data/test/template/template_finder_test.rb +73 -0
- data/test/template/template_object_test.rb +95 -0
- data/test/template/test_test.rb +56 -0
- data/test/template/text_helper_test.rb +46 -33
- data/test/template/url_helper_test.rb +8 -10
- metadata +65 -12
- data/lib/action_view/compiled_templates.rb +0 -69
- data/test/action_view_test.rb +0 -44
- data/test/activerecord/fixtures_test.rb +0 -24
- data/test/controller/fragment_store_setting_test.rb +0 -47
- data/test/template/compiled_templates_test.rb +0 -197
- data/test/template/deprecate_ivars_test.rb +0 -51
|
@@ -10,24 +10,24 @@ module ActionView
|
|
|
10
10
|
include JavaScriptHelper
|
|
11
11
|
|
|
12
12
|
# Returns the URL for the set of +options+ provided. This takes the
|
|
13
|
-
# same options as url_for in
|
|
13
|
+
# same options as +url_for+ in Action Controller (see the
|
|
14
14
|
# documentation for ActionController::Base#url_for). Note that by default
|
|
15
15
|
# <tt>:only_path</tt> is <tt>true</tt> so you'll get the relative /controller/action
|
|
16
16
|
# instead of the fully qualified URL like http://example.com/controller/action.
|
|
17
17
|
#
|
|
18
18
|
# When called from a view, url_for returns an HTML escaped url. If you
|
|
19
|
-
# need an unescaped url, pass
|
|
19
|
+
# need an unescaped url, pass <tt>:escape => false</tt> in the +options+.
|
|
20
20
|
#
|
|
21
21
|
# ==== Options
|
|
22
|
-
# * <tt>:anchor</tt>
|
|
23
|
-
# * <tt>:only_path</tt>
|
|
24
|
-
# * <tt>:trailing_slash</tt>
|
|
22
|
+
# * <tt>:anchor</tt> - Specifies the anchor name to be appended to the path.
|
|
23
|
+
# * <tt>:only_path</tt> - If true, returns the relative URL (omitting the protocol, host name, and port) (<tt>true</tt> by default unless <tt>:host</tt> is specified).
|
|
24
|
+
# * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2005/". Note that this
|
|
25
25
|
# is currently not recommended since it breaks caching.
|
|
26
|
-
# * <tt>:host</tt>
|
|
27
|
-
# * <tt>:protocol</tt>
|
|
28
|
-
# * <tt>:user</tt>
|
|
29
|
-
# * <tt>:password</tt>
|
|
30
|
-
# * <tt>:escape</tt>
|
|
26
|
+
# * <tt>:host</tt> - Overrides the default (current) host if provided.
|
|
27
|
+
# * <tt>:protocol</tt> - Overrides the default (current) protocol if provided.
|
|
28
|
+
# * <tt>:user</tt> - Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present).
|
|
29
|
+
# * <tt>:password</tt> - Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present).
|
|
30
|
+
# * <tt>:escape</tt> - Determines whether the returned URL will be HTML escaped or not (<tt>true</tt> by default).
|
|
31
31
|
#
|
|
32
32
|
# ==== Relying on named routes
|
|
33
33
|
#
|
|
@@ -86,51 +86,106 @@ module ActionView
|
|
|
86
86
|
# of +options+. See the valid options in the documentation for
|
|
87
87
|
# url_for. It's also possible to pass a string instead
|
|
88
88
|
# of an options hash to get a link tag that uses the value of the string as the
|
|
89
|
-
# href for the link, or use
|
|
89
|
+
# href for the link, or use <tt>:back</tt> to link to the referrer - a JavaScript back
|
|
90
90
|
# link will be used in place of a referrer if none exists. If nil is passed as
|
|
91
91
|
# a name, the link itself will become the name.
|
|
92
92
|
#
|
|
93
93
|
# ==== Options
|
|
94
|
-
# * <tt>:confirm => 'question?'</tt>
|
|
94
|
+
# * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
|
|
95
95
|
# prompt with the question specified. If the user accepts, the link is
|
|
96
96
|
# processed normally, otherwise no action is taken.
|
|
97
|
-
# * <tt>:popup => true || array of window options</tt>
|
|
97
|
+
# * <tt>:popup => true || array of window options</tt> - This will force the
|
|
98
98
|
# link to open in a popup window. By passing true, a default browser window
|
|
99
99
|
# will be opened with the URL. You can also specify an array of options
|
|
100
100
|
# that are passed-thru to JavaScripts window.open method.
|
|
101
|
-
# * <tt>:method => symbol of HTTP verb</tt>
|
|
101
|
+
# * <tt>:method => symbol of HTTP verb</tt> - This modifier will dynamically
|
|
102
102
|
# create an HTML form and immediately submit the form for processing using
|
|
103
103
|
# the HTTP verb specified. Useful for having links perform a POST operation
|
|
104
104
|
# in dangerous actions like deleting a record (which search bots can follow
|
|
105
|
-
# while spidering your site). Supported verbs are
|
|
105
|
+
# while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt> and <tt>:put</tt>.
|
|
106
106
|
# Note that if the user has JavaScript disabled, the request will fall back
|
|
107
107
|
# to using GET. If you are relying on the POST behavior, you should check
|
|
108
108
|
# for it in your controller's action by using the request object's methods
|
|
109
|
-
# for post
|
|
109
|
+
# for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
|
|
110
110
|
# * The +html_options+ will accept a hash of html attributes for the link tag.
|
|
111
111
|
#
|
|
112
112
|
# Note that if the user has JavaScript disabled, the request will fall back
|
|
113
|
-
# to using GET. If
|
|
113
|
+
# to using GET. If <tt>:href => '#'</tt> is used and the user has JavaScript disabled
|
|
114
114
|
# clicking the link will have no effect. If you are relying on the POST
|
|
115
115
|
# behavior, your should check for it in your controller's action by using the
|
|
116
|
-
# request object's methods for post
|
|
116
|
+
# request object's methods for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
|
|
117
117
|
#
|
|
118
118
|
# You can mix and match the +html_options+ with the exception of
|
|
119
|
-
#
|
|
119
|
+
# <tt>:popup</tt> and <tt>:method</tt> which will raise an ActionView::ActionViewError
|
|
120
120
|
# exception.
|
|
121
121
|
#
|
|
122
122
|
# ==== Examples
|
|
123
|
+
# Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
|
|
124
|
+
# and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
|
|
125
|
+
# your application on resources and use
|
|
126
|
+
#
|
|
127
|
+
# link_to "Profile", profile_path(@profile)
|
|
128
|
+
# # => <a href="/profiles/1">Profile</a>
|
|
129
|
+
#
|
|
130
|
+
# or the even pithier
|
|
131
|
+
#
|
|
132
|
+
# link_to "Profile", @profile
|
|
133
|
+
# # => <a href="/profiles/1">Profile</a>
|
|
134
|
+
#
|
|
135
|
+
# in place of the older more verbose, non-resource-oriented
|
|
136
|
+
#
|
|
137
|
+
# link_to "Profile", :controller => "profiles", :action => "show", :id => @profile
|
|
138
|
+
# # => <a href="/profiles/show/1">Profile</a>
|
|
139
|
+
#
|
|
140
|
+
# Similarly,
|
|
141
|
+
#
|
|
142
|
+
# link_to "Profiles", profiles_path
|
|
143
|
+
# # => <a href="/profiles">Profiles</a>
|
|
144
|
+
#
|
|
145
|
+
# is better than
|
|
146
|
+
#
|
|
147
|
+
# link_to "Profiles", :controller => "profiles"
|
|
148
|
+
# # => <a href="/profiles">Profiles</a>
|
|
149
|
+
#
|
|
150
|
+
# Classes and ids for CSS are easy to produce:
|
|
151
|
+
#
|
|
152
|
+
# link_to "Articles", articles_path, :id => "news", :class => "article"
|
|
153
|
+
# # => <a href="/articles" class="article" id="news">Articles</a>
|
|
154
|
+
#
|
|
155
|
+
# Be careful when using the older argument style, as an extra literal hash is needed:
|
|
156
|
+
#
|
|
157
|
+
# link_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"
|
|
158
|
+
# # => <a href="/articles" class="article" id="news">Articles</a>
|
|
159
|
+
#
|
|
160
|
+
# Leaving the hash off gives the wrong link:
|
|
161
|
+
#
|
|
162
|
+
# link_to "WRONG!", :controller => "articles", :id => "news", :class => "article"
|
|
163
|
+
# # => <a href="/articles/index/news?class=article">WRONG!</a>
|
|
164
|
+
#
|
|
165
|
+
# +link_to+ can also produce links with anchors or query strings:
|
|
166
|
+
#
|
|
167
|
+
# link_to "Comment wall", profile_path(@profile, :anchor => "wall")
|
|
168
|
+
# # => <a href="/profiles/1#wall">Comment wall</a>
|
|
169
|
+
#
|
|
170
|
+
# link_to "Ruby on Rails search", :controller => "searches", :query => "ruby on rails"
|
|
171
|
+
# # => <a href="/searches?query=ruby+on+rails">Ruby on Rails search</a>
|
|
172
|
+
#
|
|
173
|
+
# link_to "Nonsense search", searches_path(:foo => "bar", :baz => "quux")
|
|
174
|
+
# # => <a href="/searches?foo=bar&baz=quux">Nonsense search</a>
|
|
175
|
+
#
|
|
176
|
+
# The three options specfic to +link_to+ (<tt>:confirm</tt>, <tt>:popup</tt>, and <tt>:method</tt>) are used as follows:
|
|
177
|
+
#
|
|
123
178
|
# link_to "Visit Other Site", "http://www.rubyonrails.org/", :confirm => "Are you sure?"
|
|
124
179
|
# # => <a href="http://www.rubyonrails.org/" onclick="return confirm('Are you sure?');">Visit Other Site</a>
|
|
125
180
|
#
|
|
126
181
|
# link_to "Help", { :action => "help" }, :popup => true
|
|
127
182
|
# # => <a href="/testing/help/" onclick="window.open(this.href);return false;">Help</a>
|
|
128
183
|
#
|
|
129
|
-
# link_to "View Image",
|
|
130
|
-
# # => <a href="/
|
|
184
|
+
# link_to "View Image", @image, :popup => ['new_window_name', 'height=300,width=600']
|
|
185
|
+
# # => <a href="/images/9" onclick="window.open(this.href,'new_window_name','height=300,width=600');return false;">View Image</a>
|
|
131
186
|
#
|
|
132
|
-
# link_to "Delete Image",
|
|
133
|
-
# # => <a href="/
|
|
187
|
+
# link_to "Delete Image", @image, :confirm => "Are you sure?", :method => :delete
|
|
188
|
+
# # => <a href="/images/9" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form');
|
|
134
189
|
# f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;
|
|
135
190
|
# var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method');
|
|
136
191
|
# m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Delete Image</a>
|
|
@@ -178,9 +233,9 @@ module ActionView
|
|
|
178
233
|
# The +options+ hash accepts the same options at url_for.
|
|
179
234
|
#
|
|
180
235
|
# There are a few special +html_options+:
|
|
181
|
-
# * <tt>:method</tt>
|
|
182
|
-
# * <tt>:disabled</tt>
|
|
183
|
-
# * <tt>:confirm</tt>
|
|
236
|
+
# * <tt>:method</tt> - Specifies the anchor name to be appended to the path.
|
|
237
|
+
# * <tt>:disabled</tt> - Specifies the anchor name to be appended to the path.
|
|
238
|
+
# * <tt>:confirm</tt> - This will add a JavaScript confirm
|
|
184
239
|
# prompt with the question specified. If the user accepts, the link is
|
|
185
240
|
# processed normally, otherwise no action is taken.
|
|
186
241
|
#
|
|
@@ -251,10 +306,10 @@ module ActionView
|
|
|
251
306
|
# <li>About Us</li>
|
|
252
307
|
# </ul>
|
|
253
308
|
#
|
|
254
|
-
# ...but if in the "
|
|
309
|
+
# ...but if in the "index" action, it will render:
|
|
255
310
|
#
|
|
256
311
|
# <ul id="navbar">
|
|
257
|
-
# <li
|
|
312
|
+
# <li>Home</li>
|
|
258
313
|
# <li><a href="/controller/about">About Us</a></li>
|
|
259
314
|
# </ul>
|
|
260
315
|
#
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module ActionView #:nodoc:
|
|
2
|
+
class InlineTemplate < Template #:nodoc:
|
|
3
|
+
|
|
4
|
+
def initialize(view, source, locals = {}, type = nil)
|
|
5
|
+
@view = view
|
|
6
|
+
@finder = @view.finder
|
|
7
|
+
|
|
8
|
+
@source = source
|
|
9
|
+
@extension = type
|
|
10
|
+
@locals = locals || {}
|
|
11
|
+
|
|
12
|
+
@handler = self.class.handler_class_for_extension(@extension).new(@view)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def method_key
|
|
16
|
+
@source
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module ActionView #:nodoc:
|
|
2
|
+
class PartialTemplate < Template #:nodoc:
|
|
3
|
+
|
|
4
|
+
attr_reader :variable_name, :object
|
|
5
|
+
|
|
6
|
+
def initialize(view, partial_path, object = nil, locals = {})
|
|
7
|
+
@path, @variable_name = extract_partial_name_and_path(view, partial_path)
|
|
8
|
+
super(view, @path, true, locals)
|
|
9
|
+
add_object_to_local_assigns!(object)
|
|
10
|
+
|
|
11
|
+
# This is needed here in order to compile template with knowledge of 'counter'
|
|
12
|
+
initialize_counter
|
|
13
|
+
|
|
14
|
+
# Prepare early. This is a performance optimization for partial collections
|
|
15
|
+
prepare!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def render
|
|
19
|
+
ActionController::Base.benchmark("Rendered #{@path}", Logger::DEBUG, false) do
|
|
20
|
+
@handler.render(self)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def render_member(object)
|
|
25
|
+
@locals[@counter_name] += 1
|
|
26
|
+
@locals[:object] = @locals[@variable_name] = object
|
|
27
|
+
|
|
28
|
+
template = render_template
|
|
29
|
+
@locals.delete(@variable_name)
|
|
30
|
+
@locals.delete(:object)
|
|
31
|
+
|
|
32
|
+
template
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def counter=(num)
|
|
36
|
+
@locals[@counter_name] = num
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def add_object_to_local_assigns!(object)
|
|
42
|
+
@locals[:object] ||=
|
|
43
|
+
@locals[@variable_name] ||=
|
|
44
|
+
if object.is_a?(ActionView::Base::ObjectWrapper)
|
|
45
|
+
object.value
|
|
46
|
+
else
|
|
47
|
+
object
|
|
48
|
+
end || @view.controller.instance_variable_get("@#{variable_name}")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def extract_partial_name_and_path(view, partial_path)
|
|
52
|
+
path, partial_name = partial_pieces(view, partial_path)
|
|
53
|
+
[File.join(path, "_#{partial_name}"), partial_name.split('/').last.split('.').first.to_sym]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def partial_pieces(view, partial_path)
|
|
57
|
+
if partial_path.include?('/')
|
|
58
|
+
return File.dirname(partial_path), File.basename(partial_path)
|
|
59
|
+
else
|
|
60
|
+
return view.controller.class.controller_path, partial_path
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def initialize_counter
|
|
65
|
+
@counter_name ||= "#{@variable_name}_counter".to_sym
|
|
66
|
+
@locals[@counter_name] = 0
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
data/lib/action_view/partials.rb
CHANGED
|
@@ -100,101 +100,59 @@ module ActionView
|
|
|
100
100
|
# Title: <%= chief.name %>
|
|
101
101
|
# </div>
|
|
102
102
|
#
|
|
103
|
-
# As you can see, the
|
|
103
|
+
# As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
|
|
104
104
|
module Partials
|
|
105
105
|
private
|
|
106
|
-
def render_partial(partial_path, object_assigns = nil, local_assigns =
|
|
106
|
+
def render_partial(partial_path, object_assigns = nil, local_assigns = {}) #:nodoc:
|
|
107
107
|
case partial_path
|
|
108
108
|
when String, Symbol, NilClass
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if logger && logger.debug?
|
|
116
|
-
ActionController::Base.benchmark("Rendered #{path}/_#{partial_name}", Logger::DEBUG, false) do
|
|
117
|
-
render("#{path}/_#{partial_name}", local_assigns)
|
|
118
|
-
end
|
|
119
|
-
else
|
|
120
|
-
render("#{path}/_#{partial_name}", local_assigns)
|
|
121
|
-
end
|
|
122
|
-
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Associations::HasManyThroughAssociation
|
|
109
|
+
# Render the template
|
|
110
|
+
ActionView::PartialTemplate.new(self, partial_path, object_assigns, local_assigns).render_template
|
|
111
|
+
when ActionView::Helpers::FormBuilder
|
|
112
|
+
builder_partial_path = partial_path.class.to_s.demodulize.underscore.sub(/_builder$/, '')
|
|
113
|
+
render_partial(builder_partial_path, object_assigns, (local_assigns || {}).merge(builder_partial_path.to_sym => partial_path))
|
|
114
|
+
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope
|
|
123
115
|
if partial_path.any?
|
|
124
|
-
path = ActionController::RecordIdentifier.partial_path(partial_path.first)
|
|
125
116
|
collection = partial_path
|
|
126
|
-
render_partial_collection(
|
|
117
|
+
render_partial_collection(nil, collection, nil, local_assigns)
|
|
127
118
|
else
|
|
128
119
|
""
|
|
129
120
|
end
|
|
130
121
|
else
|
|
131
|
-
render_partial(
|
|
132
|
-
ActionController::RecordIdentifier.partial_path(partial_path),
|
|
133
|
-
object_assigns, local_assigns)
|
|
122
|
+
render_partial(ActionController::RecordIdentifier.partial_path(partial_path, controller.class.controller_path), partial_path, local_assigns)
|
|
134
123
|
end
|
|
135
124
|
end
|
|
136
125
|
|
|
137
|
-
def render_partial_collection(
|
|
138
|
-
|
|
139
|
-
counter_name = partial_counter_name(partial_name)
|
|
140
|
-
local_assigns = local_assigns ? local_assigns.clone : {}
|
|
141
|
-
collection.each_with_index do |element, counter|
|
|
142
|
-
local_assigns[counter_name] = counter
|
|
143
|
-
collection_of_partials.push(render_partial(partial_name, element, local_assigns))
|
|
144
|
-
end
|
|
126
|
+
def render_partial_collection(partial_path, collection, partial_spacer_template = nil, local_assigns = {}) #:nodoc:
|
|
127
|
+
return " " if collection.empty?
|
|
145
128
|
|
|
146
|
-
|
|
129
|
+
local_assigns = local_assigns ? local_assigns.clone : {}
|
|
130
|
+
spacer = partial_spacer_template ? render(:partial => partial_spacer_template) : ''
|
|
147
131
|
|
|
148
|
-
if
|
|
149
|
-
|
|
150
|
-
collection_of_partials.join(render("#{spacer_path}/_#{spacer_name}"))
|
|
132
|
+
if partial_path.nil?
|
|
133
|
+
render_partial_collection_with_unknown_partial_path(collection, local_assigns)
|
|
151
134
|
else
|
|
152
|
-
|
|
153
|
-
end
|
|
135
|
+
render_partial_collection_with_known_partial_path(collection, partial_path, local_assigns)
|
|
136
|
+
end.join(spacer)
|
|
154
137
|
end
|
|
155
138
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return File.dirname(partial_path), File.basename(partial_path)
|
|
161
|
-
else
|
|
162
|
-
return controller.class.controller_path, partial_path
|
|
139
|
+
def render_partial_collection_with_known_partial_path(collection, partial_path, local_assigns)
|
|
140
|
+
template = ActionView::PartialTemplate.new(self, partial_path, nil, local_assigns)
|
|
141
|
+
collection.map do |element|
|
|
142
|
+
template.render_member(element)
|
|
163
143
|
end
|
|
164
144
|
end
|
|
165
145
|
|
|
166
|
-
def
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
variable_name = partial_variable_name(partial_name)
|
|
176
|
-
if object_assigns.nil?
|
|
177
|
-
controller.instance_variable_get("@#{variable_name}")
|
|
178
|
-
else
|
|
179
|
-
object_assigns
|
|
146
|
+
def render_partial_collection_with_unknown_partial_path(collection, local_assigns)
|
|
147
|
+
templates = Hash.new
|
|
148
|
+
i = 0
|
|
149
|
+
collection.map do |element|
|
|
150
|
+
partial_path = ActionController::RecordIdentifier.partial_path(element, controller.class.controller_path)
|
|
151
|
+
template = templates[partial_path] ||= ActionView::PartialTemplate.new(self, partial_path, nil, local_assigns)
|
|
152
|
+
template.counter = i
|
|
153
|
+
i += 1
|
|
154
|
+
template.render_member(element)
|
|
180
155
|
end
|
|
181
156
|
end
|
|
182
|
-
|
|
183
|
-
def add_counter_to_local_assigns!(partial_name, local_assigns)
|
|
184
|
-
counter_name = partial_counter_name(partial_name)
|
|
185
|
-
local_assigns[counter_name] = 1 unless local_assigns.has_key?(counter_name)
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def add_object_to_local_assigns!(partial_name, local_assigns, object)
|
|
189
|
-
variable_name = partial_variable_name(partial_name)
|
|
190
|
-
|
|
191
|
-
local_assigns[:object] ||=
|
|
192
|
-
local_assigns[variable_name] ||=
|
|
193
|
-
if object.is_a?(ActionView::Base::ObjectWrapper)
|
|
194
|
-
object.value
|
|
195
|
-
else
|
|
196
|
-
object
|
|
197
|
-
end || controller.instance_variable_get("@#{variable_name}")
|
|
198
|
-
end
|
|
199
157
|
end
|
|
200
158
|
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
module ActionView #:nodoc:
|
|
2
|
+
class Template #:nodoc:
|
|
3
|
+
|
|
4
|
+
attr_accessor :locals
|
|
5
|
+
attr_reader :handler, :path, :extension, :filename, :path_without_extension, :method
|
|
6
|
+
|
|
7
|
+
def initialize(view, path, use_full_path, locals = {})
|
|
8
|
+
@view = view
|
|
9
|
+
@finder = @view.finder
|
|
10
|
+
|
|
11
|
+
# Clear the forward slash at the beginning if exists
|
|
12
|
+
@path = use_full_path ? path.sub(/^\//, '') : path
|
|
13
|
+
@view.first_render ||= @path
|
|
14
|
+
@source = nil # Don't read the source until we know that it is required
|
|
15
|
+
set_extension_and_file_name(use_full_path)
|
|
16
|
+
|
|
17
|
+
@locals = locals || {}
|
|
18
|
+
@handler = self.class.handler_class_for_extension(@extension).new(@view)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def render_template
|
|
22
|
+
render
|
|
23
|
+
rescue Exception => e
|
|
24
|
+
raise e unless filename
|
|
25
|
+
if TemplateError === e
|
|
26
|
+
e.sub_template_of(filename)
|
|
27
|
+
raise e
|
|
28
|
+
else
|
|
29
|
+
raise TemplateError.new(self, @view.assigns, e)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def render
|
|
34
|
+
prepare!
|
|
35
|
+
@handler.render(self)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def source
|
|
39
|
+
@source ||= File.read(self.filename)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def method_key
|
|
43
|
+
@filename
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def base_path_for_exception
|
|
47
|
+
@finder.find_base_path_for("#{@path_without_extension}.#{@extension}") || @finder.view_paths.first
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def prepare!
|
|
51
|
+
@view.send :evaluate_assigns
|
|
52
|
+
@view.current_render_extension = @extension
|
|
53
|
+
|
|
54
|
+
if @handler.compilable?
|
|
55
|
+
@handler.compile_template(self) # compile the given template, if necessary
|
|
56
|
+
@method = @view.method_names[method_key] # Set the method name for this template and run it
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def set_extension_and_file_name(use_full_path)
|
|
63
|
+
@path_without_extension, @extension = @finder.path_and_extension(@path)
|
|
64
|
+
if use_full_path
|
|
65
|
+
if @extension
|
|
66
|
+
@filename = @finder.pick_template(@path_without_extension, @extension)
|
|
67
|
+
else
|
|
68
|
+
@extension = @finder.pick_template_extension(@path).to_s
|
|
69
|
+
raise_missing_template_exception unless @extension
|
|
70
|
+
|
|
71
|
+
@filename = @finder.pick_template(@path, @extension)
|
|
72
|
+
@extension = @extension.gsub(/^.+\./, '') # strip off any formats
|
|
73
|
+
end
|
|
74
|
+
else
|
|
75
|
+
@filename = @path
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
raise_missing_template_exception if @filename.blank?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def raise_missing_template_exception
|
|
82
|
+
full_template_path = @path.include?('.') ? @path : "#{@path}.#{@view.template_format}.erb"
|
|
83
|
+
display_paths = @finder.view_paths.join(':')
|
|
84
|
+
template_type = (@path =~ /layouts/i) ? 'layout' : 'template'
|
|
85
|
+
raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Template Handlers
|
|
89
|
+
|
|
90
|
+
@@template_handlers = HashWithIndifferentAccess.new
|
|
91
|
+
@@default_template_handlers = nil
|
|
92
|
+
|
|
93
|
+
# Register a class that knows how to handle template files with the given
|
|
94
|
+
# extension. This can be used to implement new template types.
|
|
95
|
+
# The constructor for the class must take the ActiveView::Base instance
|
|
96
|
+
# as a parameter, and the class must implement a +render+ method that
|
|
97
|
+
# takes the contents of the template to render as well as the Hash of
|
|
98
|
+
# local assigns available to the template. The +render+ method ought to
|
|
99
|
+
# return the rendered template as a string.
|
|
100
|
+
def self.register_template_handler(extension, klass)
|
|
101
|
+
@@template_handlers[extension.to_sym] = klass
|
|
102
|
+
TemplateFinder.update_extension_cache_for(extension.to_s)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.template_handler_extensions
|
|
106
|
+
@@template_handlers.keys.map(&:to_s).sort
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def self.register_default_template_handler(extension, klass)
|
|
110
|
+
register_template_handler(extension, klass)
|
|
111
|
+
@@default_template_handlers = klass
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.handler_class_for_extension(extension)
|
|
115
|
+
(extension && @@template_handlers[extension.to_sym]) || @@default_template_handlers
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
register_default_template_handler :erb, TemplateHandlers::ERB
|
|
119
|
+
register_template_handler :rjs, TemplateHandlers::RJS
|
|
120
|
+
register_template_handler :builder, TemplateHandlers::Builder
|
|
121
|
+
|
|
122
|
+
# TODO: Depreciate old template extensions
|
|
123
|
+
register_template_handler :rhtml, TemplateHandlers::ERB
|
|
124
|
+
register_template_handler :rxml, TemplateHandlers::Builder
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
end
|