halorgium-actionpack 3.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5179 -0
- data/MIT-LICENSE +21 -0
- data/README +409 -0
- data/lib/abstract_controller.rb +16 -0
- data/lib/abstract_controller/base.rb +158 -0
- data/lib/abstract_controller/callbacks.rb +113 -0
- data/lib/abstract_controller/exceptions.rb +12 -0
- data/lib/abstract_controller/helpers.rb +151 -0
- data/lib/abstract_controller/layouts.rb +250 -0
- data/lib/abstract_controller/localized_cache.rb +49 -0
- data/lib/abstract_controller/logger.rb +61 -0
- data/lib/abstract_controller/rendering_controller.rb +188 -0
- data/lib/action_controller.rb +72 -0
- data/lib/action_controller/base.rb +168 -0
- data/lib/action_controller/caching.rb +80 -0
- data/lib/action_controller/caching/actions.rb +163 -0
- data/lib/action_controller/caching/fragments.rb +116 -0
- data/lib/action_controller/caching/pages.rb +154 -0
- data/lib/action_controller/caching/sweeping.rb +97 -0
- data/lib/action_controller/deprecated.rb +4 -0
- data/lib/action_controller/deprecated/integration_test.rb +2 -0
- data/lib/action_controller/deprecated/performance_test.rb +1 -0
- data/lib/action_controller/dispatch/dispatcher.rb +57 -0
- data/lib/action_controller/metal.rb +129 -0
- data/lib/action_controller/metal/benchmarking.rb +73 -0
- data/lib/action_controller/metal/compatibility.rb +145 -0
- data/lib/action_controller/metal/conditional_get.rb +86 -0
- data/lib/action_controller/metal/configuration.rb +28 -0
- data/lib/action_controller/metal/cookies.rb +105 -0
- data/lib/action_controller/metal/exceptions.rb +55 -0
- data/lib/action_controller/metal/filter_parameter_logging.rb +77 -0
- data/lib/action_controller/metal/flash.rb +162 -0
- data/lib/action_controller/metal/head.rb +27 -0
- data/lib/action_controller/metal/helpers.rb +115 -0
- data/lib/action_controller/metal/hide_actions.rb +47 -0
- data/lib/action_controller/metal/http_authentication.rb +312 -0
- data/lib/action_controller/metal/layouts.rb +171 -0
- data/lib/action_controller/metal/mime_responds.rb +317 -0
- data/lib/action_controller/metal/rack_convenience.rb +27 -0
- data/lib/action_controller/metal/redirector.rb +22 -0
- data/lib/action_controller/metal/render_options.rb +103 -0
- data/lib/action_controller/metal/rendering_controller.rb +57 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +108 -0
- data/lib/action_controller/metal/rescuable.rb +13 -0
- data/lib/action_controller/metal/responder.rb +200 -0
- data/lib/action_controller/metal/session.rb +15 -0
- data/lib/action_controller/metal/session_management.rb +45 -0
- data/lib/action_controller/metal/streaming.rb +188 -0
- data/lib/action_controller/metal/testing.rb +39 -0
- data/lib/action_controller/metal/url_for.rb +41 -0
- data/lib/action_controller/metal/verification.rb +130 -0
- data/lib/action_controller/middleware.rb +38 -0
- data/lib/action_controller/notifications.rb +10 -0
- data/lib/action_controller/polymorphic_routes.rb +183 -0
- data/lib/action_controller/record_identifier.rb +91 -0
- data/lib/action_controller/testing/process.rb +111 -0
- data/lib/action_controller/testing/test_case.rb +345 -0
- data/lib/action_controller/translation.rb +13 -0
- data/lib/action_controller/url_rewriter.rb +204 -0
- data/lib/action_controller/vendor/html-scanner.rb +16 -0
- data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
- data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +176 -0
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
- data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
- data/lib/action_dispatch.rb +70 -0
- data/lib/action_dispatch/http/headers.rb +33 -0
- data/lib/action_dispatch/http/mime_type.rb +231 -0
- data/lib/action_dispatch/http/mime_types.rb +23 -0
- data/lib/action_dispatch/http/request.rb +539 -0
- data/lib/action_dispatch/http/response.rb +290 -0
- data/lib/action_dispatch/http/status_codes.rb +42 -0
- data/lib/action_dispatch/http/utils.rb +20 -0
- data/lib/action_dispatch/middleware/callbacks.rb +50 -0
- data/lib/action_dispatch/middleware/params_parser.rb +79 -0
- data/lib/action_dispatch/middleware/rescue.rb +26 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +208 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +235 -0
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +47 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +143 -0
- data/lib/action_dispatch/middleware/stack.rb +116 -0
- data/lib/action_dispatch/middleware/static.rb +44 -0
- data/lib/action_dispatch/middleware/string_coercion.rb +29 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +26 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +10 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +29 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +10 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +2 -0
- data/lib/action_dispatch/routing.rb +381 -0
- data/lib/action_dispatch/routing/deprecated_mapper.rb +878 -0
- data/lib/action_dispatch/routing/mapper.rb +327 -0
- data/lib/action_dispatch/routing/route.rb +49 -0
- data/lib/action_dispatch/routing/route_set.rb +497 -0
- data/lib/action_dispatch/testing/assertions.rb +8 -0
- data/lib/action_dispatch/testing/assertions/dom.rb +35 -0
- data/lib/action_dispatch/testing/assertions/model.rb +19 -0
- data/lib/action_dispatch/testing/assertions/response.rb +145 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +144 -0
- data/lib/action_dispatch/testing/assertions/selector.rb +639 -0
- data/lib/action_dispatch/testing/assertions/tag.rb +123 -0
- data/lib/action_dispatch/testing/integration.rb +504 -0
- data/lib/action_dispatch/testing/performance_test.rb +15 -0
- data/lib/action_dispatch/testing/test_request.rb +83 -0
- data/lib/action_dispatch/testing/test_response.rb +131 -0
- data/lib/action_pack.rb +24 -0
- data/lib/action_pack/version.rb +9 -0
- data/lib/action_view.rb +58 -0
- data/lib/action_view/base.rb +308 -0
- data/lib/action_view/context.rb +44 -0
- data/lib/action_view/erb/util.rb +48 -0
- data/lib/action_view/helpers.rb +62 -0
- data/lib/action_view/helpers/active_model_helper.rb +306 -0
- data/lib/action_view/helpers/ajax_helper.rb +68 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +830 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
- data/lib/action_view/helpers/cache_helper.rb +39 -0
- data/lib/action_view/helpers/capture_helper.rb +168 -0
- data/lib/action_view/helpers/date_helper.rb +988 -0
- data/lib/action_view/helpers/debug_helper.rb +38 -0
- data/lib/action_view/helpers/form_helper.rb +1102 -0
- data/lib/action_view/helpers/form_options_helper.rb +600 -0
- data/lib/action_view/helpers/form_tag_helper.rb +495 -0
- data/lib/action_view/helpers/javascript_helper.rb +208 -0
- data/lib/action_view/helpers/number_helper.rb +311 -0
- data/lib/action_view/helpers/prototype_helper.rb +1309 -0
- data/lib/action_view/helpers/raw_output_helper.rb +9 -0
- data/lib/action_view/helpers/record_identification_helper.rb +20 -0
- data/lib/action_view/helpers/record_tag_helper.rb +58 -0
- data/lib/action_view/helpers/sanitize_helper.rb +259 -0
- data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
- data/lib/action_view/helpers/tag_helper.rb +151 -0
- data/lib/action_view/helpers/text_helper.rb +594 -0
- data/lib/action_view/helpers/translation_helper.rb +39 -0
- data/lib/action_view/helpers/url_helper.rb +639 -0
- data/lib/action_view/locale/en.yml +117 -0
- data/lib/action_view/paths.rb +80 -0
- data/lib/action_view/render/partials.rb +342 -0
- data/lib/action_view/render/rendering.rb +134 -0
- data/lib/action_view/safe_buffer.rb +28 -0
- data/lib/action_view/template/error.rb +101 -0
- data/lib/action_view/template/handler.rb +36 -0
- data/lib/action_view/template/handlers.rb +52 -0
- data/lib/action_view/template/handlers/builder.rb +17 -0
- data/lib/action_view/template/handlers/erb.rb +53 -0
- data/lib/action_view/template/handlers/rjs.rb +18 -0
- data/lib/action_view/template/resolver.rb +165 -0
- data/lib/action_view/template/template.rb +131 -0
- data/lib/action_view/template/text.rb +38 -0
- data/lib/action_view/test_case.rb +163 -0
- metadata +236 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
"en":
|
2
|
+
number:
|
3
|
+
# Used in number_with_delimiter()
|
4
|
+
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
5
|
+
format:
|
6
|
+
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
7
|
+
separator: "."
|
8
|
+
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
9
|
+
delimiter: ","
|
10
|
+
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
11
|
+
precision: 3
|
12
|
+
|
13
|
+
# Used in number_to_currency()
|
14
|
+
currency:
|
15
|
+
format:
|
16
|
+
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
17
|
+
format: "%u%n"
|
18
|
+
unit: "$"
|
19
|
+
# These three are to override number.format and are optional
|
20
|
+
separator: "."
|
21
|
+
delimiter: ","
|
22
|
+
precision: 2
|
23
|
+
|
24
|
+
# Used in number_to_percentage()
|
25
|
+
percentage:
|
26
|
+
format:
|
27
|
+
# These three are to override number.format and are optional
|
28
|
+
# separator:
|
29
|
+
delimiter: ""
|
30
|
+
# precision:
|
31
|
+
|
32
|
+
# Used in number_to_precision()
|
33
|
+
precision:
|
34
|
+
format:
|
35
|
+
# These three are to override number.format and are optional
|
36
|
+
# separator:
|
37
|
+
delimiter: ""
|
38
|
+
# precision:
|
39
|
+
|
40
|
+
# Used in number_to_human_size()
|
41
|
+
human:
|
42
|
+
format:
|
43
|
+
# These three are to override number.format and are optional
|
44
|
+
# separator:
|
45
|
+
delimiter: ""
|
46
|
+
precision: 1
|
47
|
+
storage_units:
|
48
|
+
# Storage units output formatting.
|
49
|
+
# %u is the storage unit, %n is the number (default: 2 MB)
|
50
|
+
format: "%n %u"
|
51
|
+
units:
|
52
|
+
byte:
|
53
|
+
one: "Byte"
|
54
|
+
other: "Bytes"
|
55
|
+
kb: "KB"
|
56
|
+
mb: "MB"
|
57
|
+
gb: "GB"
|
58
|
+
tb: "TB"
|
59
|
+
|
60
|
+
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
61
|
+
datetime:
|
62
|
+
distance_in_words:
|
63
|
+
half_a_minute: "half a minute"
|
64
|
+
less_than_x_seconds:
|
65
|
+
one: "less than 1 second"
|
66
|
+
other: "less than {{count}} seconds"
|
67
|
+
x_seconds:
|
68
|
+
one: "1 second"
|
69
|
+
other: "{{count}} seconds"
|
70
|
+
less_than_x_minutes:
|
71
|
+
one: "less than a minute"
|
72
|
+
other: "less than {{count}} minutes"
|
73
|
+
x_minutes:
|
74
|
+
one: "1 minute"
|
75
|
+
other: "{{count}} minutes"
|
76
|
+
about_x_hours:
|
77
|
+
one: "about 1 hour"
|
78
|
+
other: "about {{count}} hours"
|
79
|
+
x_days:
|
80
|
+
one: "1 day"
|
81
|
+
other: "{{count}} days"
|
82
|
+
about_x_months:
|
83
|
+
one: "about 1 month"
|
84
|
+
other: "about {{count}} months"
|
85
|
+
x_months:
|
86
|
+
one: "1 month"
|
87
|
+
other: "{{count}} months"
|
88
|
+
about_x_years:
|
89
|
+
one: "about 1 year"
|
90
|
+
other: "about {{count}} years"
|
91
|
+
over_x_years:
|
92
|
+
one: "over 1 year"
|
93
|
+
other: "over {{count}} years"
|
94
|
+
almost_x_years:
|
95
|
+
one: "almost 1 year"
|
96
|
+
other: "almost {{count}} years"
|
97
|
+
prompts:
|
98
|
+
year: "Year"
|
99
|
+
month: "Month"
|
100
|
+
day: "Day"
|
101
|
+
hour: "Hour"
|
102
|
+
minute: "Minute"
|
103
|
+
second: "Seconds"
|
104
|
+
|
105
|
+
activemodel:
|
106
|
+
errors:
|
107
|
+
template:
|
108
|
+
header:
|
109
|
+
one: "1 error prohibited this {{model}} from being saved"
|
110
|
+
other: "{{count}} errors prohibited this {{model}} from being saved"
|
111
|
+
# The variable :count is also available
|
112
|
+
body: "There were problems with the following fields:"
|
113
|
+
|
114
|
+
support:
|
115
|
+
select:
|
116
|
+
# default value for :prompt => true in FormOptionsHelper
|
117
|
+
prompt: "Please select"
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ActionView #:nodoc:
|
2
|
+
class PathSet < Array #:nodoc:
|
3
|
+
def self.type_cast(obj, cache = nil)
|
4
|
+
# TODO: Clean this up
|
5
|
+
if obj.is_a?(String)
|
6
|
+
if cache.nil?
|
7
|
+
cache = !defined?(Rails) || Rails.application.config.cache_classes
|
8
|
+
end
|
9
|
+
FileSystemResolverWithFallback.new(obj, :cache => cache)
|
10
|
+
else
|
11
|
+
obj
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
super(*args).map! { |obj| self.class.type_cast(obj) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def <<(obj)
|
20
|
+
super(self.class.type_cast(obj))
|
21
|
+
end
|
22
|
+
|
23
|
+
def concat(array)
|
24
|
+
super(array.map! { |obj| self.class.type_cast(obj) })
|
25
|
+
end
|
26
|
+
|
27
|
+
def insert(index, obj)
|
28
|
+
super(index, self.class.type_cast(obj))
|
29
|
+
end
|
30
|
+
|
31
|
+
def push(*objs)
|
32
|
+
super(*objs.map { |obj| self.class.type_cast(obj) })
|
33
|
+
end
|
34
|
+
|
35
|
+
def unshift(*objs)
|
36
|
+
super(*objs.map { |obj| self.class.type_cast(obj) })
|
37
|
+
end
|
38
|
+
|
39
|
+
def find(path, details = {}, prefix = nil, partial = false)
|
40
|
+
template_path = path
|
41
|
+
|
42
|
+
each do |load_path|
|
43
|
+
if template = load_path.find(template_path, details, prefix, partial)
|
44
|
+
return template
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path} - #{details.inspect} - partial: #{!!partial}")
|
49
|
+
end
|
50
|
+
|
51
|
+
def exists?(path, extension = nil, prefix = nil, partial = false)
|
52
|
+
template_path = path.sub(/^\//, '')
|
53
|
+
|
54
|
+
each do |load_path|
|
55
|
+
return true if template = load_path.find(template_path, extension, prefix, partial)
|
56
|
+
end
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
def find_template(original_template_path, format = nil, html_fallback = true)
|
61
|
+
return original_template_path if original_template_path.respond_to?(:render)
|
62
|
+
template_path = original_template_path.sub(/^\//, '')
|
63
|
+
|
64
|
+
each do |load_path|
|
65
|
+
if template = load_path.find(template_path, format)
|
66
|
+
return template
|
67
|
+
# Try to find html version if the format is javascript
|
68
|
+
elsif format == :js && html_fallback && template = load_path["#{template_path}.#{I18n.locale}.html"]
|
69
|
+
return template
|
70
|
+
elsif format == :js && html_fallback && template = load_path["#{template_path}.html"]
|
71
|
+
return template
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
return Template.new(original_template_path, original_template_path.to_s =~ /\A\// ? "" : ".") if File.file?(original_template_path)
|
76
|
+
|
77
|
+
raise MissingTemplate.new(self, original_template_path, format)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,342 @@
|
|
1
|
+
module ActionView
|
2
|
+
# There's also a convenience method for rendering sub templates within the current controller that depends on a
|
3
|
+
# single object (we call this kind of sub templates for partials). It relies on the fact that partials should
|
4
|
+
# follow the naming convention of being prefixed with an underscore -- as to separate them from regular
|
5
|
+
# templates that could be rendered on their own.
|
6
|
+
#
|
7
|
+
# In a template for Advertiser#account:
|
8
|
+
#
|
9
|
+
# <%= render :partial => "account" %>
|
10
|
+
#
|
11
|
+
# This would render "advertiser/_account.erb" and pass the instance variable @account in as a local variable
|
12
|
+
# +account+ to the template for display.
|
13
|
+
#
|
14
|
+
# In another template for Advertiser#buy, we could have:
|
15
|
+
#
|
16
|
+
# <%= render :partial => "account", :locals => { :account => @buyer } %>
|
17
|
+
#
|
18
|
+
# <% for ad in @advertisements %>
|
19
|
+
# <%= render :partial => "ad", :locals => { :ad => ad } %>
|
20
|
+
# <% end %>
|
21
|
+
#
|
22
|
+
# This would first render "advertiser/_account.erb" with @buyer passed in as the local variable +account+, then
|
23
|
+
# render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display.
|
24
|
+
#
|
25
|
+
# == Rendering a collection of partials
|
26
|
+
#
|
27
|
+
# The example of partial use describes a familiar pattern where a template needs to iterate over an array and
|
28
|
+
# render a sub template for each of the elements. This pattern has been implemented as a single method that
|
29
|
+
# accepts an array and renders a partial by the same name as the elements contained within. So the three-lined
|
30
|
+
# example in "Using partials" can be rewritten with a single line:
|
31
|
+
#
|
32
|
+
# <%= render :partial => "ad", :collection => @advertisements %>
|
33
|
+
#
|
34
|
+
# This will render "advertiser/_ad.erb" and pass the local variable +ad+ to the template for display. An
|
35
|
+
# iteration counter will automatically be made available to the template with a name of the form
|
36
|
+
# +partial_name_counter+. In the case of the example above, the template would be fed +ad_counter+.
|
37
|
+
#
|
38
|
+
# NOTE: Due to backwards compatibility concerns, the collection can't be one of hashes. Normally you'd also
|
39
|
+
# just keep domain objects, like Active Records, in there.
|
40
|
+
#
|
41
|
+
# == Rendering shared partials
|
42
|
+
#
|
43
|
+
# Two controllers can share a set of partials and render them like this:
|
44
|
+
#
|
45
|
+
# <%= render :partial => "advertisement/ad", :locals => { :ad => @advertisement } %>
|
46
|
+
#
|
47
|
+
# This will render the partial "advertisement/_ad.erb" regardless of which controller this is being called from.
|
48
|
+
#
|
49
|
+
# == Rendering objects with the RecordIdentifier
|
50
|
+
#
|
51
|
+
# Instead of explicitly naming the location of a partial, you can also let the RecordIdentifier do the work if
|
52
|
+
# you're following its conventions for RecordIdentifier#partial_path. Examples:
|
53
|
+
#
|
54
|
+
# # @account is an Account instance, so it uses the RecordIdentifier to replace
|
55
|
+
# # <%= render :partial => "accounts/account", :locals => { :account => @buyer } %>
|
56
|
+
# <%= render :partial => @account %>
|
57
|
+
#
|
58
|
+
# # @posts is an array of Post instances, so it uses the RecordIdentifier to replace
|
59
|
+
# # <%= render :partial => "posts/post", :collection => @posts %>
|
60
|
+
# <%= render :partial => @posts %>
|
61
|
+
#
|
62
|
+
# == Rendering the default case
|
63
|
+
#
|
64
|
+
# If you're not going to be using any of the options like collections or layouts, you can also use the short-hand
|
65
|
+
# defaults of render to render partials. Examples:
|
66
|
+
#
|
67
|
+
# # Instead of <%= render :partial => "account" %>
|
68
|
+
# <%= render "account" %>
|
69
|
+
#
|
70
|
+
# # Instead of <%= render :partial => "account", :locals => { :account => @buyer } %>
|
71
|
+
# <%= render "account", :account => @buyer %>
|
72
|
+
#
|
73
|
+
# # @account is an Account instance, so it uses the RecordIdentifier to replace
|
74
|
+
# # <%= render :partial => "accounts/account", :locals => { :account => @account } %>
|
75
|
+
# <%= render(@account) %>
|
76
|
+
#
|
77
|
+
# # @posts is an array of Post instances, so it uses the RecordIdentifier to replace
|
78
|
+
# # <%= render :partial => "posts/post", :collection => @posts %>
|
79
|
+
# <%= render(@posts) %>
|
80
|
+
#
|
81
|
+
# == Rendering partials with layouts
|
82
|
+
#
|
83
|
+
# Partials can have their own layouts applied to them. These layouts are different than the ones that are
|
84
|
+
# specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types
|
85
|
+
# of users:
|
86
|
+
#
|
87
|
+
# <%# app/views/users/index.html.erb &>
|
88
|
+
# Here's the administrator:
|
89
|
+
# <%= render :partial => "user", :layout => "administrator", :locals => { :user => administrator } %>
|
90
|
+
#
|
91
|
+
# Here's the editor:
|
92
|
+
# <%= render :partial => "user", :layout => "editor", :locals => { :user => editor } %>
|
93
|
+
#
|
94
|
+
# <%# app/views/users/_user.html.erb &>
|
95
|
+
# Name: <%= user.name %>
|
96
|
+
#
|
97
|
+
# <%# app/views/users/_administrator.html.erb &>
|
98
|
+
# <div id="administrator">
|
99
|
+
# Budget: $<%= user.budget %>
|
100
|
+
# <%= yield %>
|
101
|
+
# </div>
|
102
|
+
#
|
103
|
+
# <%# app/views/users/_editor.html.erb &>
|
104
|
+
# <div id="editor">
|
105
|
+
# Deadline: <%= user.deadline %>
|
106
|
+
# <%= yield %>
|
107
|
+
# </div>
|
108
|
+
#
|
109
|
+
# ...this will return:
|
110
|
+
#
|
111
|
+
# Here's the administrator:
|
112
|
+
# <div id="administrator">
|
113
|
+
# Budget: $<%= user.budget %>
|
114
|
+
# Name: <%= user.name %>
|
115
|
+
# </div>
|
116
|
+
#
|
117
|
+
# Here's the editor:
|
118
|
+
# <div id="editor">
|
119
|
+
# Deadline: <%= user.deadline %>
|
120
|
+
# Name: <%= user.name %>
|
121
|
+
# </div>
|
122
|
+
#
|
123
|
+
# You can also apply a layout to a block within any template:
|
124
|
+
#
|
125
|
+
# <%# app/views/users/_chief.html.erb &>
|
126
|
+
# <% render(:layout => "administrator", :locals => { :user => chief }) do %>
|
127
|
+
# Title: <%= chief.title %>
|
128
|
+
# <% end %>
|
129
|
+
#
|
130
|
+
# ...this will return:
|
131
|
+
#
|
132
|
+
# <div id="administrator">
|
133
|
+
# Budget: $<%= user.budget %>
|
134
|
+
# Title: <%= chief.name %>
|
135
|
+
# </div>
|
136
|
+
#
|
137
|
+
# As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
|
138
|
+
#
|
139
|
+
# If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
|
140
|
+
# an array to layout and treat it as an enumerable.
|
141
|
+
#
|
142
|
+
# <%# app/views/users/_user.html.erb &>
|
143
|
+
# <div class="user">
|
144
|
+
# Budget: $<%= user.budget %>
|
145
|
+
# <%= yield user %>
|
146
|
+
# </div>
|
147
|
+
#
|
148
|
+
# <%# app/views/users/index.html.erb &>
|
149
|
+
# <% render :layout => @users do |user| %>
|
150
|
+
# Title: <%= user.title %>
|
151
|
+
# <% end %>
|
152
|
+
#
|
153
|
+
# This will render the layout for each user and yield to the block, passing the user, each time.
|
154
|
+
#
|
155
|
+
# You can also yield multiple times in one layout and use block arguments to differentiate the sections.
|
156
|
+
#
|
157
|
+
# <%# app/views/users/_user.html.erb &>
|
158
|
+
# <div class="user">
|
159
|
+
# <%= yield user, :header %>
|
160
|
+
# Budget: $<%= user.budget %>
|
161
|
+
# <%= yield user, :footer %>
|
162
|
+
# </div>
|
163
|
+
#
|
164
|
+
# <%# app/views/users/index.html.erb &>
|
165
|
+
# <% render :layout => @users do |user, section| %>
|
166
|
+
# <%- case section when :header -%>
|
167
|
+
# Title: <%= user.title %>
|
168
|
+
# <%- when :footer -%>
|
169
|
+
# Deadline: <%= user.deadline %>
|
170
|
+
# <%- end -%>
|
171
|
+
# <% end %>
|
172
|
+
module Partials
|
173
|
+
extend ActiveSupport::Concern
|
174
|
+
|
175
|
+
class PartialRenderer
|
176
|
+
PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} }
|
177
|
+
TEMPLATES = Hash.new {|h,k| h[k] = {} }
|
178
|
+
|
179
|
+
attr_reader :template
|
180
|
+
|
181
|
+
def initialize(view_context, options, block)
|
182
|
+
@view = view_context
|
183
|
+
@partial_names = PARTIAL_NAMES[@view.controller.class]
|
184
|
+
|
185
|
+
key = Thread.current[:format_locale_key]
|
186
|
+
@templates = TEMPLATES[key] if key
|
187
|
+
|
188
|
+
setup(options, block)
|
189
|
+
end
|
190
|
+
|
191
|
+
def setup(options, block)
|
192
|
+
partial = options[:partial]
|
193
|
+
|
194
|
+
@options = options
|
195
|
+
@locals = options[:locals] || {}
|
196
|
+
@block = block
|
197
|
+
|
198
|
+
if String === partial
|
199
|
+
@object = options[:object]
|
200
|
+
@path = partial
|
201
|
+
else
|
202
|
+
@object = partial
|
203
|
+
@path = partial_path(partial)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def render
|
208
|
+
if @collection = collection
|
209
|
+
render_collection
|
210
|
+
else
|
211
|
+
@template = template = find_template
|
212
|
+
render_template(template, @object || @locals[template.variable_name])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def render_collection
|
217
|
+
@template = template = find_template
|
218
|
+
|
219
|
+
return nil if @collection.blank?
|
220
|
+
|
221
|
+
if @options.key?(:spacer_template)
|
222
|
+
spacer = find_template(@options[:spacer_template]).render(@view, @locals)
|
223
|
+
end
|
224
|
+
|
225
|
+
result = template ? collection_with_template(template) : collection_without_template
|
226
|
+
result.join(spacer).html_safe!
|
227
|
+
end
|
228
|
+
|
229
|
+
def collection_with_template(template)
|
230
|
+
options = @options
|
231
|
+
|
232
|
+
segments, locals, as = [], @locals, options[:as] || template.variable_name
|
233
|
+
|
234
|
+
counter_name = template.counter_name
|
235
|
+
locals[counter_name] = -1
|
236
|
+
|
237
|
+
@collection.each do |object|
|
238
|
+
locals[counter_name] += 1
|
239
|
+
locals[as] = object
|
240
|
+
|
241
|
+
segments << template.render(@view, locals)
|
242
|
+
end
|
243
|
+
|
244
|
+
@template = template
|
245
|
+
segments
|
246
|
+
end
|
247
|
+
|
248
|
+
def collection_without_template
|
249
|
+
options = @options
|
250
|
+
|
251
|
+
segments, locals, as = [], @locals, options[:as]
|
252
|
+
index, template = -1, nil
|
253
|
+
|
254
|
+
@collection.each do |object|
|
255
|
+
template = find_template(partial_path(object))
|
256
|
+
locals[template.counter_name] = (index += 1)
|
257
|
+
locals[template.variable_name] = object
|
258
|
+
|
259
|
+
segments << template.render(@view, locals)
|
260
|
+
end
|
261
|
+
|
262
|
+
@template = template
|
263
|
+
segments
|
264
|
+
end
|
265
|
+
|
266
|
+
def render_template(template, object = @object)
|
267
|
+
options, locals, view = @options, @locals, @view
|
268
|
+
locals[options[:as] || template.variable_name] = object
|
269
|
+
|
270
|
+
content = template.render(view, locals) do |*name|
|
271
|
+
@view._layout_for(*name, &@block)
|
272
|
+
end
|
273
|
+
|
274
|
+
if @block || !options[:layout]
|
275
|
+
content
|
276
|
+
else
|
277
|
+
find_template(options[:layout]).render(@view, @locals) { content }
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
private
|
282
|
+
def collection
|
283
|
+
if @object.respond_to?(:to_ary)
|
284
|
+
@object
|
285
|
+
elsif @options.key?(:collection)
|
286
|
+
@options[:collection] || []
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def find_template(path = @path)
|
291
|
+
unless @templates
|
292
|
+
path && _find_template(path)
|
293
|
+
else
|
294
|
+
path && @templates[path] ||= _find_template(path)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def _find_template(path)
|
299
|
+
if controller = @view.controller
|
300
|
+
prefix = controller.controller_path unless path.include?(?/)
|
301
|
+
end
|
302
|
+
|
303
|
+
@view.find(path, {:formats => @view.formats}, prefix, true)
|
304
|
+
end
|
305
|
+
|
306
|
+
def partial_path(object = @object)
|
307
|
+
@partial_names[object.class] ||= begin
|
308
|
+
return nil unless object.respond_to?(:to_model)
|
309
|
+
|
310
|
+
object.to_model.class.model_name.partial_path.dup.tap do |partial|
|
311
|
+
path = @view.controller_path
|
312
|
+
partial.insert(0, "#{File.dirname(path)}/") if path.include?(?/)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def render_partial(options)
|
319
|
+
_evaluate_assigns_and_ivars
|
320
|
+
|
321
|
+
details = options[:_details]
|
322
|
+
|
323
|
+
# Is this needed
|
324
|
+
self.formats = details[:formats] if details
|
325
|
+
renderer = PartialRenderer.new(self, options, nil)
|
326
|
+
text = renderer.render
|
327
|
+
options[:_template] = renderer.template
|
328
|
+
text
|
329
|
+
end
|
330
|
+
|
331
|
+
def _render_partial(options, &block) #:nodoc:
|
332
|
+
if @renderer
|
333
|
+
@renderer.setup(options, block)
|
334
|
+
else
|
335
|
+
@renderer = PartialRenderer.new(self, options, block)
|
336
|
+
end
|
337
|
+
|
338
|
+
@renderer.render
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|
342
|
+
end
|