actionview 4.2.10 → 5.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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +141 -272
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/action_view/base.rb +33 -21
  6. data/lib/action_view/buffers.rb +1 -1
  7. data/lib/action_view/context.rb +1 -1
  8. data/lib/action_view/dependency_tracker.rb +52 -20
  9. data/lib/action_view/digestor.rb +86 -83
  10. data/lib/action_view/flows.rb +9 -11
  11. data/lib/action_view/gem_version.rb +3 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +8 -8
  13. data/lib/action_view/helpers/asset_tag_helper.rb +74 -38
  14. data/lib/action_view/helpers/asset_url_helper.rb +160 -59
  15. data/lib/action_view/helpers/atom_feed_helper.rb +16 -16
  16. data/lib/action_view/helpers/cache_helper.rb +90 -35
  17. data/lib/action_view/helpers/capture_helper.rb +7 -6
  18. data/lib/action_view/helpers/controller_helper.rb +3 -2
  19. data/lib/action_view/helpers/csrf_helper.rb +3 -3
  20. data/lib/action_view/helpers/date_helper.rb +156 -108
  21. data/lib/action_view/helpers/debug_helper.rb +3 -4
  22. data/lib/action_view/helpers/form_helper.rb +475 -94
  23. data/lib/action_view/helpers/form_options_helper.rb +87 -47
  24. data/lib/action_view/helpers/form_tag_helper.rb +88 -57
  25. data/lib/action_view/helpers/javascript_helper.rb +10 -10
  26. data/lib/action_view/helpers/number_helper.rb +76 -59
  27. data/lib/action_view/helpers/output_safety_helper.rb +34 -4
  28. data/lib/action_view/helpers/record_tag_helper.rb +12 -99
  29. data/lib/action_view/helpers/rendering_helper.rb +3 -3
  30. data/lib/action_view/helpers/sanitize_helper.rb +17 -14
  31. data/lib/action_view/helpers/tag_helper.rb +198 -73
  32. data/lib/action_view/helpers/tags/base.rb +132 -97
  33. data/lib/action_view/helpers/tags/check_box.rb +17 -17
  34. data/lib/action_view/helpers/tags/collection_check_boxes.rb +9 -33
  35. data/lib/action_view/helpers/tags/collection_helpers.rb +68 -36
  36. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +3 -11
  37. data/lib/action_view/helpers/tags/collection_select.rb +2 -2
  38. data/lib/action_view/helpers/tags/date_select.rb +36 -36
  39. data/lib/action_view/helpers/tags/datetime_field.rb +1 -1
  40. data/lib/action_view/helpers/tags/grouped_collection_select.rb +2 -2
  41. data/lib/action_view/helpers/tags/label.rb +5 -1
  42. data/lib/action_view/helpers/tags/password_field.rb +1 -1
  43. data/lib/action_view/helpers/tags/placeholderable.rb +1 -1
  44. data/lib/action_view/helpers/tags/radio_button.rb +4 -4
  45. data/lib/action_view/helpers/tags/search_field.rb +12 -9
  46. data/lib/action_view/helpers/tags/select.rb +9 -9
  47. data/lib/action_view/helpers/tags/text_area.rb +1 -1
  48. data/lib/action_view/helpers/tags/text_field.rb +5 -6
  49. data/lib/action_view/helpers/tags/translator.rb +15 -13
  50. data/lib/action_view/helpers/text_helper.rb +47 -30
  51. data/lib/action_view/helpers/translation_helper.rb +60 -30
  52. data/lib/action_view/helpers/url_helper.rb +132 -104
  53. data/lib/action_view/helpers.rb +1 -1
  54. data/lib/action_view/layouts.rb +59 -54
  55. data/lib/action_view/log_subscriber.rb +56 -7
  56. data/lib/action_view/lookup_context.rb +76 -61
  57. data/lib/action_view/model_naming.rb +1 -1
  58. data/lib/action_view/path_set.rb +28 -19
  59. data/lib/action_view/railtie.rb +30 -6
  60. data/lib/action_view/record_identifier.rb +51 -25
  61. data/lib/action_view/renderer/abstract_renderer.rb +19 -15
  62. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +55 -0
  63. data/lib/action_view/renderer/partial_renderer.rb +208 -206
  64. data/lib/action_view/renderer/renderer.rb +2 -6
  65. data/lib/action_view/renderer/streaming_template_renderer.rb +46 -48
  66. data/lib/action_view/renderer/template_renderer.rb +65 -66
  67. data/lib/action_view/rendering.rb +16 -9
  68. data/lib/action_view/routing_url_for.rb +25 -17
  69. data/lib/action_view/tasks/cache_digests.rake +23 -0
  70. data/lib/action_view/template/error.rb +14 -13
  71. data/lib/action_view/template/handlers/builder.rb +7 -7
  72. data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +9 -0
  73. data/lib/action_view/template/handlers/erb/erubi.rb +81 -0
  74. data/lib/action_view/template/handlers/erb/erubis.rb +81 -0
  75. data/lib/action_view/template/handlers/erb.rb +9 -76
  76. data/lib/action_view/template/handlers/html.rb +9 -0
  77. data/lib/action_view/template/handlers/raw.rb +1 -3
  78. data/lib/action_view/template/handlers.rb +8 -6
  79. data/lib/action_view/template/html.rb +2 -4
  80. data/lib/action_view/template/resolver.rb +133 -109
  81. data/lib/action_view/template/text.rb +5 -8
  82. data/lib/action_view/template/types.rb +15 -17
  83. data/lib/action_view/template.rb +51 -28
  84. data/lib/action_view/test_case.rb +32 -27
  85. data/lib/action_view/testing/resolvers.rb +29 -31
  86. data/lib/action_view/version.rb +1 -1
  87. data/lib/action_view/view_paths.rb +26 -32
  88. data/lib/action_view.rb +5 -5
  89. data/lib/assets/compiled/rails-ujs.js +685 -0
  90. metadata +23 -23
  91. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -39,13 +39,13 @@ module ActionView
39
39
  # This will include both records as part of the cache key and updating either of them will
40
40
  # expire the cache.
41
41
  #
42
- # ==== Template digest
42
+ # ==== \Template digest
43
43
  #
44
- # The template digest that's added to the cache key is computed by taking an md5 of the
44
+ # The template digest that's added to the cache key is computed by taking an MD5 of the
45
45
  # contents of the entire template file. This ensures that your caches will automatically
46
46
  # expire when you change the template file.
47
47
  #
48
- # Note that the md5 is taken of the entire template file, not just what's within the
48
+ # Note that the MD5 is taken of the entire template file, not just what's within the
49
49
  # cache do/end call. So it's possible that changing something outside of that call will
50
50
  # still expire the cache.
51
51
  #
@@ -69,13 +69,14 @@ module ActionView
69
69
  # render 'comments/comments'
70
70
  # render('comments/comments')
71
71
  #
72
- # render "header" => render("comments/header")
72
+ # render "header" translates to render("comments/header")
73
73
  #
74
- # render(@topic) => render("topics/topic")
75
- # render(topics) => render("topics/topic")
76
- # render(message.topics) => render("topics/topic")
74
+ # render(@topic) translates to render("topics/topic")
75
+ # render(topics) translates to render("topics/topic")
76
+ # render(message.topics) translates to render("topics/topic")
77
77
  #
78
- # It's not possible to derive all render calls like that, though. Here are a few examples of things that can't be derived:
78
+ # It's not possible to derive all render calls like that, though.
79
+ # Here are a few examples of things that can't be derived:
79
80
  #
80
81
  # render group_of_attachments
81
82
  # render @project.documents.where(published: true).order('created_at')
@@ -87,7 +88,7 @@ module ActionView
87
88
  #
88
89
  # === Explicit dependencies
89
90
  #
90
- # Some times you'll have template dependencies that can't be derived at all. This is typically
91
+ # Sometimes you'll have template dependencies that can't be derived at all. This is typically
91
92
  # the case when you have template rendering that happens in helpers. Here's an example:
92
93
  #
93
94
  # <%= render_sortable_todolists @project.todolists %>
@@ -97,22 +98,70 @@ module ActionView
97
98
  # <%# Template Dependency: todolists/todolist %>
98
99
  # <%= render_sortable_todolists @project.todolists %>
99
100
  #
100
- # The pattern used to match these is /# Template Dependency: ([^ ]+)/, so it's important that you type it out just so.
101
+ # In some cases, like a single table inheritance setup, you might have
102
+ # a bunch of explicit dependencies. Instead of writing every template out,
103
+ # you can use a wildcard to match any template in a directory:
104
+ #
105
+ # <%# Template Dependency: events/* %>
106
+ # <%= render_categorizable_events @person.events %>
107
+ #
108
+ # This marks every template in the directory as a dependency. To find those
109
+ # templates, the wildcard path must be absolutely defined from app/views or paths
110
+ # otherwise added with +prepend_view_path+ or +append_view_path+.
111
+ # This way the wildcard for `app/views/recordings/events` would be `recordings/events/*` etc.
112
+ #
113
+ # The pattern used to match explicit dependencies is <tt>/# Template Dependency: (\S+)/</tt>,
114
+ # so it's important that you type it out just so.
101
115
  # You can only declare one template dependency per line.
102
116
  #
103
117
  # === External dependencies
104
118
  #
105
- # If you use a helper method, for example, inside of a cached block and you then update that helper,
106
- # you'll have to bump the cache as well. It doesn't really matter how you do it, but the md5 of the template file
119
+ # If you use a helper method, for example, inside a cached block and
120
+ # you then update that helper, you'll have to bump the cache as well.
121
+ # It doesn't really matter how you do it, but the MD5 of the template file
107
122
  # must change. One recommendation is to simply be explicit in a comment, like:
108
123
  #
109
124
  # <%# Helper Dependency Updated: May 6, 2012 at 6pm %>
110
125
  # <%= some_helper_method(person) %>
111
126
  #
112
- # Now all you'll have to do is change that timestamp when the helper method changes.
113
- def cache(name = {}, options = nil, &block)
127
+ # Now all you have to do is change that timestamp when the helper method changes.
128
+ #
129
+ # === Collection Caching
130
+ #
131
+ # When rendering a collection of objects that each use the same partial, a `cached`
132
+ # option can be passed.
133
+ #
134
+ # For collections rendered such:
135
+ #
136
+ # <%= render partial: 'projects/project', collection: @projects, cached: true %>
137
+ #
138
+ # The `cached: true` will make Action View's rendering read several templates
139
+ # from cache at once instead of one call per template.
140
+ #
141
+ # Templates in the collection not already cached are written to cache.
142
+ #
143
+ # Works great alongside individual template fragment caching.
144
+ # For instance if the template the collection renders is cached like:
145
+ #
146
+ # # projects/_project.html.erb
147
+ # <% cache project do %>
148
+ # <%# ... %>
149
+ # <% end %>
150
+ #
151
+ # Any collection renders will find those cached templates when attempting
152
+ # to read multiple templates at once.
153
+ #
154
+ # If your collection cache depends on multiple sources (try to avoid this to keep things simple),
155
+ # you can name all these dependencies as part of a block that returns an array:
156
+ #
157
+ # <%= render partial: 'projects/project', collection: @projects, cached: -> project { [ project, current_user ] } %>
158
+ #
159
+ # This will include both records as part of the cache key and updating either of them will
160
+ # expire the cache.
161
+ def cache(name = {}, options = {}, &block)
114
162
  if controller.respond_to?(:perform_caching) && controller.perform_caching
115
- safe_concat(fragment_for(cache_fragment_name(name, options), options, &block))
163
+ name_options = options.slice(:skip_digest, :virtual_path)
164
+ safe_concat(fragment_for(cache_fragment_name(name, name_options), options, &block))
116
165
  else
117
166
  yield
118
167
  end
@@ -126,7 +175,7 @@ module ActionView
126
175
  # <b>All the topics on this project</b>
127
176
  # <%= render project.topics %>
128
177
  # <% end %>
129
- def cache_if(condition, name = {}, options = nil, &block)
178
+ def cache_if(condition, name = {}, options = {}, &block)
130
179
  if condition
131
180
  cache(name, options, &block)
132
181
  else
@@ -142,50 +191,56 @@ module ActionView
142
191
  # <b>All the topics on this project</b>
143
192
  # <%= render project.topics %>
144
193
  # <% end %>
145
- def cache_unless(condition, name = {}, options = nil, &block)
194
+ def cache_unless(condition, name = {}, options = {}, &block)
146
195
  cache_if !condition, name, options, &block
147
196
  end
148
197
 
149
198
  # This helper returns the name of a cache key for a given fragment cache
150
- # call. By supplying skip_digest: true to cache, the digestion of cache
199
+ # call. By supplying +skip_digest:+ true to cache, the digestion of cache
151
200
  # fragments can be manually bypassed. This is useful when cache fragments
152
201
  # cannot be manually expired unless you know the exact key which is the
153
202
  # case when using memcached.
154
- def cache_fragment_name(name = {}, options = nil)
155
- skip_digest = options && options[:skip_digest]
156
-
203
+ #
204
+ # The digest will be generated using +virtual_path:+ if it is provided.
205
+ #
206
+ def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil)
157
207
  if skip_digest
158
208
  name
159
209
  else
160
- fragment_name_with_digest(name)
210
+ fragment_name_with_digest(name, virtual_path)
161
211
  end
162
212
  end
163
213
 
164
- private
214
+ attr_reader :cache_hit # :nodoc:
165
215
 
166
- def fragment_name_with_digest(name) #:nodoc:
167
- if @virtual_path
168
- names = Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name)
169
- digest = Digestor.digest name: @virtual_path, finder: lookup_context, dependencies: view_cache_dependencies
216
+ private
170
217
 
171
- [ *names, digest ]
218
+ def fragment_name_with_digest(name, virtual_path)
219
+ virtual_path ||= @virtual_path
220
+ if virtual_path
221
+ name = controller.url_for(name).split("://").last if name.is_a?(Hash)
222
+ digest = Digestor.digest name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies
223
+ [ name, digest ]
172
224
  else
173
225
  name
174
226
  end
175
227
  end
176
228
 
177
- # TODO: Create an object that has caching read/write on it
178
- def fragment_for(name = {}, options = nil, &block) #:nodoc:
179
- read_fragment_for(name, options) || write_fragment_for(name, options, &block)
229
+ def fragment_for(name = {}, options = nil, &block)
230
+ if content = read_fragment_for(name, options)
231
+ @cache_hit = true
232
+ content
233
+ else
234
+ @cache_hit = false
235
+ write_fragment_for(name, options, &block)
236
+ end
180
237
  end
181
238
 
182
- def read_fragment_for(name, options) #:nodoc:
239
+ def read_fragment_for(name, options)
183
240
  controller.read_fragment(name, options)
184
241
  end
185
242
 
186
- def write_fragment_for(name, options) #:nodoc:
187
- # VIEW TODO: Make #capture usable outside of ERB
188
- # This dance is needed because Builder can't use capture
243
+ def write_fragment_for(name, options)
189
244
  pos = output_buffer.length
190
245
  yield
191
246
  output_safe = output_buffer.html_safe?
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/string/output_safety'
1
+ require "active_support/core_ext/string/output_safety"
2
2
 
3
3
  module ActionView
4
4
  # = Action View Capture Helper
@@ -9,8 +9,8 @@ module ActionView
9
9
  # It provides a method to capture blocks into variables through capture and
10
10
  # a way to capture a block of markup for use in a layout through content_for.
11
11
  module CaptureHelper
12
- # The capture method allows you to extract part of a template into a
13
- # variable. You can then use this variable anywhere in your templates or layout.
12
+ # The capture method extracts part of a template as a String object.
13
+ # You can then use this object anywhere in your templates, layout, or helpers.
14
14
  #
15
15
  # The capture method can be used in ERB templates...
16
16
  #
@@ -31,12 +31,13 @@ module ActionView
31
31
  # <head><title><%= @greeting %></title></head>
32
32
  # <body>
33
33
  # <b><%= @greeting %></b>
34
- # </body></html>
34
+ # </body>
35
+ # </html>
35
36
  #
36
37
  def capture(*args)
37
38
  value = nil
38
39
  buffer = with_output_buffer { value = yield(*args) }
39
- if string = buffer.presence || value and string.is_a?(String)
40
+ if (string = buffer.presence || value) && string.is_a?(String)
40
41
  ERB::Util.html_escape string
41
42
  end
42
43
  end
@@ -114,7 +115,7 @@ module ActionView
114
115
  # <li><%= link_to 'Home', action: 'index' %></li>
115
116
  # <% end %>
116
117
  #
117
- # And in other place:
118
+ # And in another place:
118
119
  #
119
120
  # <% content_for :navigation do %>
120
121
  # <li><%= link_to 'Login', action: 'login' %></li>
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/module/attr_internal'
1
+ require "active_support/core_ext/module/attr_internal"
2
2
 
3
3
  module ActionView
4
4
  module Helpers
@@ -8,12 +8,13 @@ module ActionView
8
8
  attr_internal :controller, :request
9
9
 
10
10
  delegate :request_forgery_protection_token, :params, :session, :cookies, :response, :headers,
11
- :flash, :action_name, :controller_name, :controller_path, :to => :controller
11
+ :flash, :action_name, :controller_name, :controller_path, to: :controller
12
12
 
13
13
  def assign_controller(controller)
14
14
  if @_controller = controller
15
15
  @_request = controller.request if controller.respond_to?(:request)
16
16
  @_config = controller.config.inheritable_copy if controller.respond_to?(:config)
17
+ @_default_form_builder = controller.default_form_builder if controller.respond_to?(:default_form_builder)
17
18
  end
18
19
  end
19
20
 
@@ -14,14 +14,14 @@ module ActionView
14
14
  #
15
15
  # You don't need to use these tags for regular forms as they generate their own hidden fields.
16
16
  #
17
- # For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag and send as the
17
+ # For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag and send as the
18
18
  # "X-CSRF-Token" HTTP header. If you are using jQuery with jquery-rails this happens automatically.
19
19
  #
20
20
  def csrf_meta_tags
21
21
  if protect_against_forgery?
22
22
  [
23
- tag('meta', :name => 'csrf-param', :content => request_forgery_protection_token),
24
- tag('meta', :name => 'csrf-token', :content => form_authenticity_token)
23
+ tag("meta", name: "csrf-param", content: request_forgery_protection_token),
24
+ tag("meta", name: "csrf-token", content: form_authenticity_token)
25
25
  ].join("\n").html_safe
26
26
  end
27
27
  end