actionpack 3.2.19 → 4.0.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 (263) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +850 -401
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +39 -37
  7. data/lib/abstract_controller/callbacks.rb +101 -82
  8. data/lib/abstract_controller/collector.rb +7 -3
  9. data/lib/abstract_controller/helpers.rb +25 -13
  10. data/lib/abstract_controller/layouts.rb +74 -74
  11. data/lib/abstract_controller/logger.rb +1 -2
  12. data/lib/abstract_controller/rendering.rb +30 -13
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +6 -6
  15. data/lib/abstract_controller/view_paths.rb +1 -1
  16. data/lib/abstract_controller.rb +1 -8
  17. data/lib/action_controller/base.rb +46 -22
  18. data/lib/action_controller/caching/fragments.rb +23 -53
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/log_subscriber.rb +16 -8
  23. data/lib/action_controller/metal/conditional_get.rb +76 -32
  24. data/lib/action_controller/metal/data_streaming.rb +20 -26
  25. data/lib/action_controller/metal/exceptions.rb +19 -6
  26. data/lib/action_controller/metal/flash.rb +24 -9
  27. data/lib/action_controller/metal/force_ssl.rb +70 -12
  28. data/lib/action_controller/metal/head.rb +25 -4
  29. data/lib/action_controller/metal/helpers.rb +5 -9
  30. data/lib/action_controller/metal/hide_actions.rb +0 -1
  31. data/lib/action_controller/metal/http_authentication.rb +107 -83
  32. data/lib/action_controller/metal/implicit_render.rb +1 -1
  33. data/lib/action_controller/metal/instrumentation.rb +2 -1
  34. data/lib/action_controller/metal/live.rb +175 -0
  35. data/lib/action_controller/metal/mime_responds.rb +161 -47
  36. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  37. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  38. data/lib/action_controller/metal/redirecting.rb +15 -20
  39. data/lib/action_controller/metal/renderers.rb +11 -9
  40. data/lib/action_controller/metal/rendering.rb +9 -1
  41. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  42. data/lib/action_controller/metal/responder.rb +20 -19
  43. data/lib/action_controller/metal/streaming.rb +12 -18
  44. data/lib/action_controller/metal/strong_parameters.rb +520 -0
  45. data/lib/action_controller/metal/testing.rb +13 -18
  46. data/lib/action_controller/metal/url_for.rb +28 -25
  47. data/lib/action_controller/metal.rb +17 -32
  48. data/lib/action_controller/model_naming.rb +12 -0
  49. data/lib/action_controller/railtie.rb +33 -17
  50. data/lib/action_controller/railties/helpers.rb +22 -0
  51. data/lib/action_controller/record_identifier.rb +18 -72
  52. data/lib/action_controller/test_case.rb +251 -131
  53. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  54. data/lib/action_controller.rb +15 -6
  55. data/lib/action_dispatch/http/cache.rb +63 -11
  56. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  57. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  58. data/lib/action_dispatch/http/headers.rb +49 -17
  59. data/lib/action_dispatch/http/mime_negotiation.rb +24 -1
  60. data/lib/action_dispatch/http/mime_type.rb +154 -100
  61. data/lib/action_dispatch/http/mime_types.rb +1 -1
  62. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  63. data/lib/action_dispatch/http/parameters.rb +28 -28
  64. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  65. data/lib/action_dispatch/http/request.rb +64 -18
  66. data/lib/action_dispatch/http/response.rb +130 -35
  67. data/lib/action_dispatch/http/upload.rb +63 -20
  68. data/lib/action_dispatch/http/url.rb +98 -35
  69. data/lib/action_dispatch/journey/backwards.rb +5 -0
  70. data/lib/action_dispatch/journey/formatter.rb +146 -0
  71. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  72. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  73. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  74. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  75. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  76. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  77. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  78. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  79. data/lib/action_dispatch/journey/parser.rb +206 -0
  80. data/lib/action_dispatch/journey/parser.y +47 -0
  81. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  82. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  83. data/lib/action_dispatch/journey/route.rb +124 -0
  84. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  85. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  86. data/lib/action_dispatch/journey/router.rb +166 -0
  87. data/lib/action_dispatch/journey/routes.rb +75 -0
  88. data/lib/action_dispatch/journey/scanner.rb +61 -0
  89. data/lib/action_dispatch/journey/visitors.rb +197 -0
  90. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  91. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  92. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  93. data/lib/action_dispatch/journey.rb +5 -0
  94. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  95. data/lib/action_dispatch/middleware/cookies.rb +259 -114
  96. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  97. data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -3
  98. data/lib/action_dispatch/middleware/flash.rb +58 -58
  99. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  100. data/lib/action_dispatch/middleware/public_exceptions.rb +30 -14
  101. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  102. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  103. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  104. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  105. data/lib/action_dispatch/middleware/session/cookie_store.rb +82 -28
  106. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  107. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  108. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  109. data/lib/action_dispatch/middleware/stack.rb +6 -1
  110. data/lib/action_dispatch/middleware/static.rb +2 -1
  111. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  112. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +7 -9
  114. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  115. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +127 -5
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  118. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  119. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  120. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  121. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  122. data/lib/action_dispatch/railtie.rb +16 -6
  123. data/lib/action_dispatch/request/session.rb +181 -0
  124. data/lib/action_dispatch/routing/inspector.rb +240 -0
  125. data/lib/action_dispatch/routing/mapper.rb +540 -291
  126. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  127. data/lib/action_dispatch/routing/redirection.rb +46 -29
  128. data/lib/action_dispatch/routing/route_set.rb +207 -164
  129. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  130. data/lib/action_dispatch/routing/url_for.rb +48 -33
  131. data/lib/action_dispatch/routing.rb +48 -83
  132. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  133. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  134. data/lib/action_dispatch/testing/assertions/routing.rb +42 -41
  135. data/lib/action_dispatch/testing/assertions/selector.rb +17 -22
  136. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  137. data/lib/action_dispatch/testing/integration.rb +65 -51
  138. data/lib/action_dispatch/testing/test_process.rb +9 -6
  139. data/lib/action_dispatch/testing/test_request.rb +7 -3
  140. data/lib/action_dispatch.rb +21 -15
  141. data/lib/action_pack/version.rb +7 -6
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_view/base.rb +15 -34
  144. data/lib/action_view/buffers.rb +7 -1
  145. data/lib/action_view/context.rb +4 -4
  146. data/lib/action_view/dependency_tracker.rb +93 -0
  147. data/lib/action_view/digestor.rb +85 -0
  148. data/lib/action_view/flows.rb +1 -4
  149. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  150. data/lib/action_view/helpers/asset_tag_helper.rb +215 -352
  151. data/lib/action_view/helpers/asset_url_helper.rb +355 -0
  152. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  153. data/lib/action_view/helpers/cache_helper.rb +150 -18
  154. data/lib/action_view/helpers/capture_helper.rb +44 -31
  155. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  156. data/lib/action_view/helpers/date_helper.rb +269 -248
  157. data/lib/action_view/helpers/debug_helper.rb +10 -11
  158. data/lib/action_view/helpers/form_helper.rb +931 -537
  159. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  160. data/lib/action_view/helpers/form_tag_helper.rb +190 -90
  161. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  162. data/lib/action_view/helpers/number_helper.rb +148 -329
  163. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  164. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  165. data/lib/action_view/helpers/rendering_helper.rb +2 -2
  166. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  167. data/lib/action_view/helpers/tag_helper.rb +46 -33
  168. data/lib/action_view/helpers/tags/base.rb +147 -0
  169. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  170. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  171. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  172. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  173. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  174. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  175. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  176. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  177. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  178. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  179. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  180. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  181. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  182. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  183. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  184. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  185. data/lib/action_view/helpers/tags/label.rb +65 -0
  186. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  187. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  188. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  189. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  190. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  191. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  192. data/lib/action_view/helpers/tags/select.rb +40 -0
  193. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  194. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  195. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  196. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  197. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  198. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  199. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  200. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  201. data/lib/action_view/helpers/tags.rb +39 -0
  202. data/lib/action_view/helpers/text_helper.rb +130 -114
  203. data/lib/action_view/helpers/translation_helper.rb +32 -16
  204. data/lib/action_view/helpers/url_helper.rb +211 -270
  205. data/lib/action_view/helpers.rb +2 -4
  206. data/lib/action_view/locale/en.yml +1 -105
  207. data/lib/action_view/log_subscriber.rb +6 -4
  208. data/lib/action_view/lookup_context.rb +15 -28
  209. data/lib/action_view/model_naming.rb +12 -0
  210. data/lib/action_view/path_set.rb +8 -20
  211. data/lib/action_view/railtie.rb +6 -22
  212. data/lib/action_view/record_identifier.rb +84 -0
  213. data/lib/action_view/renderer/abstract_renderer.rb +25 -19
  214. data/lib/action_view/renderer/partial_renderer.rb +158 -81
  215. data/lib/action_view/renderer/renderer.rb +8 -12
  216. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  217. data/lib/action_view/renderer/template_renderer.rb +12 -10
  218. data/lib/action_view/routing_url_for.rb +107 -0
  219. data/lib/action_view/template/error.rb +22 -12
  220. data/lib/action_view/template/handlers/builder.rb +1 -1
  221. data/lib/action_view/template/handlers/erb.rb +40 -19
  222. data/lib/action_view/template/handlers/raw.rb +11 -0
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/resolver.rb +107 -53
  225. data/lib/action_view/template/text.rb +12 -8
  226. data/lib/action_view/template/types.rb +57 -0
  227. data/lib/action_view/template.rb +25 -23
  228. data/lib/action_view/test_case.rb +67 -42
  229. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  230. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  231. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +13 -2
  232. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +9 -9
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  235. data/lib/action_view/vendor/html-scanner.rb +20 -0
  236. data/lib/action_view.rb +17 -8
  237. metadata +184 -214
  238. data/lib/action_controller/caching/actions.rb +0 -185
  239. data/lib/action_controller/caching/pages.rb +0 -187
  240. data/lib/action_controller/caching/sweeping.rb +0 -97
  241. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  242. data/lib/action_controller/metal/compatibility.rb +0 -65
  243. data/lib/action_controller/metal/session_management.rb +0 -14
  244. data/lib/action_controller/railties/paths.rb +0 -25
  245. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  246. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  247. data/lib/action_dispatch/middleware/head.rb +0 -18
  248. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  249. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  250. data/lib/action_view/asset_paths.rb +0 -142
  251. data/lib/action_view/helpers/asset_paths.rb +0 -7
  252. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  253. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  254. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  255. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  256. data/lib/sprockets/assets.rake +0 -99
  257. data/lib/sprockets/bootstrap.rb +0 -37
  258. data/lib/sprockets/compressors.rb +0 -83
  259. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  260. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/railtie.rb +0 -62
  263. data/lib/sprockets/static_compiler.rb +0 -56
@@ -2,7 +2,6 @@ require 'action_view/helpers/javascript_helper'
2
2
  require 'active_support/core_ext/array/access'
3
3
  require 'active_support/core_ext/hash/keys'
4
4
  require 'active_support/core_ext/string/output_safety'
5
- require 'action_dispatch'
6
5
 
7
6
  module ActionView
8
7
  # = Action View URL Helpers
@@ -20,98 +19,33 @@ module ActionView
20
19
 
21
20
  extend ActiveSupport::Concern
22
21
 
23
- include ActionDispatch::Routing::UrlFor
24
22
  include TagHelper
25
23
 
26
- def _routes_context
27
- controller
28
- end
29
-
30
- # Need to map default url options to controller one.
31
- # def default_url_options(*args) #:nodoc:
32
- # controller.send(:default_url_options, *args)
33
- # end
34
- #
35
- def url_options
36
- return super unless controller.respond_to?(:url_options)
37
- controller.url_options
24
+ module ClassMethods
25
+ def _url_for_modules
26
+ ActionView::RoutingUrlFor
27
+ end
38
28
  end
39
29
 
40
- # Returns the URL for the set of +options+ provided. This takes the
41
- # same options as +url_for+ in Action Controller (see the
42
- # documentation for <tt>ActionController::Base#url_for</tt>). Note that by default
43
- # <tt>:only_path</tt> is <tt>true</tt> so you'll get the relative "/controller/action"
44
- # instead of the fully qualified URL like "http://example.com/controller/action".
45
- #
46
- # ==== Options
47
- # * <tt>:anchor</tt> - Specifies the anchor name to be appended to the path.
48
- # * <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).
49
- # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2005/". Note that this
50
- # is currently not recommended since it breaks caching.
51
- # * <tt>:host</tt> - Overrides the default (current) host if provided.
52
- # * <tt>:protocol</tt> - Overrides the default (current) protocol if provided.
53
- # * <tt>:user</tt> - Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present).
54
- # * <tt>:password</tt> - Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present).
55
- #
56
- # ==== Relying on named routes
57
- #
58
- # Passing a record (like an Active Record or Active Resource) instead of a Hash as the options parameter will
59
- # trigger the named route for that record. The lookup will happen on the name of the class. So passing a
60
- # Workshop object will attempt to use the +workshop_path+ route. If you have a nested route, such as
61
- # +admin_workshop_path+ you'll have to call that explicitly (it's impossible for +url_for+ to guess that route).
62
- #
63
- # ==== Examples
64
- # <%= url_for(:action => 'index') %>
65
- # # => /blog/
66
- #
67
- # <%= url_for(:action => 'find', :controller => 'books') %>
68
- # # => /books/find
69
- #
70
- # <%= url_for(:action => 'login', :controller => 'members', :only_path => false, :protocol => 'https') %>
71
- # # => https://www.example.com/members/login/
72
- #
73
- # <%= url_for(:action => 'play', :anchor => 'player') %>
74
- # # => /messages/play/#player
75
- #
76
- # <%= url_for(:action => 'jump', :anchor => 'tax&ship') %>
77
- # # => /testing/jump/#tax&ship
78
- #
79
- # <%= url_for(Workshop.new) %>
80
- # # relies on Workshop answering a persisted? call (and in this case returning false)
81
- # # => /workshops
82
- #
83
- # <%= url_for(@workshop) %>
84
- # # calls @workshop.to_param which by default returns the id
85
- # # => /workshops/5
86
- #
87
- # # to_param can be re-defined in a model to provide different URL names:
88
- # # => /workshops/1-workshop-name
89
- #
90
- # <%= url_for("http://www.example.com") %>
91
- # # => http://www.example.com
92
- #
93
- # <%= url_for(:back) %>
94
- # # if request.env["HTTP_REFERER"] is set to "http://www.example.com"
95
- # # => http://www.example.com
96
- #
97
- # <%= url_for(:back) %>
98
- # # if request.env["HTTP_REFERER"] is not set or is blank
99
- # # => javascript:history.back()
100
- def url_for(options = {})
101
- options ||= {}
30
+ # Basic implementation of url_for to allow use helpers without routes existence
31
+ def url_for(options = nil) # :nodoc:
102
32
  case options
103
33
  when String
104
34
  options
105
- when Hash
106
- options = options.symbolize_keys.reverse_merge!(:only_path => options[:host].nil?)
107
- super
108
35
  when :back
109
- controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
36
+ _back_url
110
37
  else
111
- polymorphic_path(options)
38
+ raise ArgumentError, "arguments passed to url_for can't be handled. Please require " +
39
+ "routes or provide your own implementation"
112
40
  end
113
41
  end
114
42
 
43
+ def _back_url # :nodoc:
44
+ referrer = controller.respond_to?(:request) && controller.request.env["HTTP_REFERER"]
45
+ referrer || 'javascript:history.back()'
46
+ end
47
+ protected :_back_url
48
+
115
49
  # Creates a link tag of the given +name+ using a URL created by the set of +options+.
116
50
  # See the valid options in the documentation for +url_for+. It's also possible to
117
51
  # pass a String instead of an options hash, which generates a link tag that uses the
@@ -127,8 +61,7 @@ module ActionView
127
61
  # # posts_path
128
62
  #
129
63
  # link_to(body, url_options = {}, html_options = {})
130
- # # url_options, except :confirm or :method,
131
- # # is passed to url_for
64
+ # # url_options, except :method, is passed to url_for
132
65
  #
133
66
  # link_to(options = {}, html_options = {}) do
134
67
  # # name
@@ -139,25 +72,33 @@ module ActionView
139
72
  # end
140
73
  #
141
74
  # ==== Options
142
- # * <tt>:confirm => 'question?'</tt> - This will allow the unobtrusive JavaScript
143
- # driver to prompt with the question specified. If the user accepts, the link is
144
- # processed normally, otherwise no action is taken.
145
- # * <tt>:method => symbol of HTTP verb</tt> - This modifier will dynamically
75
+ # * <tt>:data</tt> - This option can be used to add custom data attributes.
76
+ # * <tt>method: symbol of HTTP verb</tt> - This modifier will dynamically
146
77
  # create an HTML form and immediately submit the form for processing using
147
78
  # the HTTP verb specified. Useful for having links perform a POST operation
148
79
  # in dangerous actions like deleting a record (which search bots can follow
149
- # while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt> and <tt>:put</tt>.
80
+ # while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>.
150
81
  # Note that if the user has JavaScript disabled, the request will fall back
151
- # to using GET. If <tt>:href => '#'</tt> is used and the user has JavaScript
82
+ # to using GET. If <tt>href: '#'</tt> is used and the user has JavaScript
152
83
  # disabled clicking the link will have no effect. If you are relying on the
153
84
  # POST behavior, you should check for it in your controller's action by using
154
- # the request object's methods for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
155
- # * <tt>:remote => true</tt> - This will allow the unobtrusive JavaScript
85
+ # the request object's methods for <tt>post?</tt>, <tt>delete?</tt>, <tt>:patch</tt>, or <tt>put?</tt>.
86
+ # * <tt>remote: true</tt> - This will allow the unobtrusive JavaScript
156
87
  # driver to make an Ajax request to the URL in question instead of following
157
88
  # the link. The drivers each provide mechanisms for listening for the
158
89
  # completion of the Ajax request and performing JavaScript operations once
159
90
  # they're complete
160
91
  #
92
+ # ==== Data attributes
93
+ #
94
+ # * <tt>confirm: 'question?'</tt> - This will allow the unobtrusive JavaScript
95
+ # driver to prompt with the question specified. If the user accepts, the link is
96
+ # processed normally, otherwise no action is taken.
97
+ # * <tt>:disable_with</tt> - Value of this parameter will be
98
+ # used as the value for a disabled version of the submit
99
+ # button when the form is submitted. This feature is provided
100
+ # by the unobtrusive JavaScript driver.
101
+ #
161
102
  # ==== Examples
162
103
  # Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
163
104
  # and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
@@ -173,7 +114,7 @@ module ActionView
173
114
  #
174
115
  # in place of the older more verbose, non-resource-oriented
175
116
  #
176
- # link_to "Profile", :controller => "profiles", :action => "show", :id => @profile
117
+ # link_to "Profile", controller: "profiles", action: "show", id: @profile
177
118
  # # => <a href="/profiles/show/1">Profile</a>
178
119
  #
179
120
  # Similarly,
@@ -183,7 +124,7 @@ module ActionView
183
124
  #
184
125
  # is better than
185
126
  #
186
- # link_to "Profiles", :controller => "profiles"
127
+ # link_to "Profiles", controller: "profiles"
187
128
  # # => <a href="/profiles">Profiles</a>
188
129
  #
189
130
  # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
@@ -197,56 +138,49 @@ module ActionView
197
138
  #
198
139
  # Classes and ids for CSS are easy to produce:
199
140
  #
200
- # link_to "Articles", articles_path, :id => "news", :class => "article"
141
+ # link_to "Articles", articles_path, id: "news", class: "article"
201
142
  # # => <a href="/articles" class="article" id="news">Articles</a>
202
143
  #
203
144
  # Be careful when using the older argument style, as an extra literal hash is needed:
204
145
  #
205
- # link_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"
146
+ # link_to "Articles", { controller: "articles" }, id: "news", class: "article"
206
147
  # # => <a href="/articles" class="article" id="news">Articles</a>
207
148
  #
208
149
  # Leaving the hash off gives the wrong link:
209
150
  #
210
- # link_to "WRONG!", :controller => "articles", :id => "news", :class => "article"
151
+ # link_to "WRONG!", controller: "articles", id: "news", class: "article"
211
152
  # # => <a href="/articles/index/news?class=article">WRONG!</a>
212
153
  #
213
154
  # +link_to+ can also produce links with anchors or query strings:
214
155
  #
215
- # link_to "Comment wall", profile_path(@profile, :anchor => "wall")
156
+ # link_to "Comment wall", profile_path(@profile, anchor: "wall")
216
157
  # # => <a href="/profiles/1#wall">Comment wall</a>
217
158
  #
218
- # link_to "Ruby on Rails search", :controller => "searches", :query => "ruby on rails"
159
+ # link_to "Ruby on Rails search", controller: "searches", query: "ruby on rails"
219
160
  # # => <a href="/searches?query=ruby+on+rails">Ruby on Rails search</a>
220
161
  #
221
- # link_to "Nonsense search", searches_path(:foo => "bar", :baz => "quux")
162
+ # link_to "Nonsense search", searches_path(foo: "bar", baz: "quux")
222
163
  # # => <a href="/searches?foo=bar&amp;baz=quux">Nonsense search</a>
223
164
  #
224
- # The two options specific to +link_to+ (<tt>:confirm</tt> and <tt>:method</tt>) are used as follows:
165
+ # The only option specific to +link_to+ (<tt>:method</tt>) is used as follows:
225
166
  #
226
- # link_to "Visit Other Site", "http://www.rubyonrails.org/", :confirm => "Are you sure?"
227
- # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?"">Visit Other Site</a>
167
+ # link_to("Destroy", "http://www.example.com", method: :delete)
168
+ # # => <a href='http://www.example.com' rel="nofollow" data-method="delete">Destroy</a>
228
169
  #
229
- # link_to("Destroy", "http://www.example.com", :method => :delete, :confirm => "Are you sure?")
230
- # # => <a href='http://www.example.com' rel="nofollow" data-method="delete" data-confirm="Are you sure?">Destroy</a>
231
- def link_to(*args, &block)
232
- if block_given?
233
- options = args.first || {}
234
- html_options = args.second
235
- link_to(capture(&block), options, html_options)
236
- else
237
- name = args[0]
238
- options = args[1] || {}
239
- html_options = args[2]
170
+ # You can also use custom data attributes using the <tt>:data</tt> option:
171
+ #
172
+ # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
173
+ # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
174
+ def link_to(name = nil, options = nil, html_options = nil, &block)
175
+ html_options, options = options, name if block_given?
176
+ options ||= {}
240
177
 
241
- html_options = convert_options_to_data_attributes(options, html_options)
242
- url = url_for(options)
178
+ html_options = convert_options_to_data_attributes(options, html_options)
243
179
 
244
- href = html_options['href']
245
- tag_options = tag_options(html_options)
180
+ url = url_for(options)
181
+ html_options['href'] ||= url
246
182
 
247
- href_attr = "href=\"#{ERB::Util.html_escape(url)}\"" unless href
248
- "<a #{href_attr}#{tag_options}>#{ERB::Util.html_escape(name || url)}</a>".html_safe
249
- end
183
+ content_tag(:a, name || url, html_options, &block)
250
184
  end
251
185
 
252
186
  # Generates a form containing a single button that submits to the URL created
@@ -260,10 +194,9 @@ module ActionView
260
194
  # to allow styling of the form itself and its children. This can be changed
261
195
  # using the <tt>:form_class</tt> modifier within +html_options+. You can control
262
196
  # the form submission and input element behavior using +html_options+.
263
- # This method accepts the <tt>:method</tt> and <tt>:confirm</tt> modifiers
264
- # described in the +link_to+ documentation. If no <tt>:method</tt> modifier
265
- # is given, it will default to performing a POST operation. You can also
266
- # disable the button by passing <tt>:disabled => true</tt> in +html_options+.
197
+ # This method accepts the <tt>:method</tt> modifier described in the +link_to+ documentation.
198
+ # If no <tt>:method</tt> modifier is given, it will default to performing a POST operation.
199
+ # You can also disable the button by passing <tt>disabled: true</tt> in +html_options+.
267
200
  # If you are using RESTful routes, you can pass the <tt>:method</tt>
268
201
  # to change the HTTP verb used to submit the form.
269
202
  #
@@ -272,89 +205,114 @@ module ActionView
272
205
  #
273
206
  # There are a few special +html_options+:
274
207
  # * <tt>:method</tt> - Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
275
- # <tt>:delete</tt> and <tt>:put</tt>. By default it will be <tt>:post</tt>.
208
+ # <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>. By default it will be <tt>:post</tt>.
276
209
  # * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
277
- # * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
278
- # prompt with the question specified. If the user accepts, the link is
279
- # processed normally, otherwise no action is taken.
210
+ # * <tt>:data</tt> - This option can be used to add custom data attributes.
280
211
  # * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
281
212
  # submit behavior. By default this behavior is an ajax submit.
282
213
  # * <tt>:form</tt> - This hash will be form attributes
283
214
  # * <tt>:form_class</tt> - This controls the class of the form within which the submit button will
284
215
  # be placed
285
216
  #
217
+ # ==== Data attributes
218
+ #
219
+ # * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
220
+ # prompt with the question specified. If the user accepts, the link is
221
+ # processed normally, otherwise no action is taken.
222
+ # * <tt>:disable_with</tt> - Value of this parameter will be
223
+ # used as the value for a disabled version of the submit
224
+ # button when the form is submitted. This feature is provided
225
+ # by the unobtrusive JavaScript driver.
226
+ #
286
227
  # ==== Examples
287
- # <%= button_to "New", :action => "new" %>
228
+ # <%= button_to "New", action: "new" %>
288
229
  # # => "<form method="post" action="/controller/new" class="button_to">
289
230
  # # <div><input value="New" type="submit" /></div>
290
231
  # # </form>"
291
232
  #
233
+ # <%= button_to [:make_happy, @user] do %>
234
+ # Make happy <strong><%= @user.name %></strong>
235
+ # <% end %>
236
+ # # => "<form method="post" action="/users/1/make_happy" class="button_to">
237
+ # # <div>
238
+ # # <button type="submit">
239
+ # # Make happy <strong><%= @user.name %></strong>
240
+ # # </button>
241
+ # # </div>
242
+ # # </form>"
292
243
  #
293
- # <%= button_to "New", :action => "new", :form_class => "new-thing" %>
244
+ # <%= button_to "New", { action: "new" }, form_class: "new-thing" %>
294
245
  # # => "<form method="post" action="/controller/new" class="new-thing">
295
246
  # # <div><input value="New" type="submit" /></div>
296
247
  # # </form>"
297
248
  #
298
249
  #
299
- # <%= button_to "Create", :action => "create", :remote => true, :form => { "data-type" => "json" } %>
250
+ # <%= button_to "Create", { action: "create" }, remote: true, form: { "data-type" => "json" } %>
300
251
  # # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
301
- # # <div><input value="Create" type="submit" /></div>
252
+ # # <div>
253
+ # # <input value="Create" type="submit" />
254
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
255
+ # # </div>
302
256
  # # </form>"
303
257
  #
304
- #
305
- # <%= button_to "Delete Image", { :action => "delete", :id => @image.id },
306
- # :confirm => "Are you sure?", :method => :delete %>
258
+ #
259
+ # <%= button_to "Delete Image", { action: "delete", id: @image.id },
260
+ # method: :delete, data: { confirm: "Are you sure?" } %>
307
261
  # # => "<form method="post" action="/images/delete/1" class="button_to">
308
262
  # # <div>
309
263
  # # <input type="hidden" name="_method" value="delete" />
310
- # # <input data-confirm='Are you sure?' value="Delete" type="submit" />
264
+ # # <input data-confirm='Are you sure?' value="Delete Image" type="submit" />
265
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
311
266
  # # </div>
312
267
  # # </form>"
313
268
  #
314
269
  #
315
- # <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
316
- # :method => "delete", :remote => true, :disable_with => 'loading...') %>
270
+ # <%= button_to('Destroy', 'http://www.example.com',
271
+ # method: "delete", remote: true, data: { confirm: 'Are you sure?', disable_with: 'loading...' }) %>
317
272
  # # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
318
273
  # # <div>
319
274
  # # <input name='_method' value='delete' type='hidden' />
320
- # # <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' />
275
+ # # <input value='Destroy' type='submit' data-disable-with='loading...' data-confirm='Are you sure?' />
276
+ # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
321
277
  # # </div>
322
278
  # # </form>"
323
279
  # #
324
- def button_to(name, options = {}, html_options = {})
280
+ def button_to(name = nil, options = nil, html_options = nil, &block)
281
+ html_options, options = options, name if block_given?
282
+ options ||= {}
283
+ html_options ||= {}
284
+
325
285
  html_options = html_options.stringify_keys
326
- convert_boolean_attributes!(html_options, %w( disabled ))
286
+ convert_boolean_attributes!(html_options, %w(disabled))
327
287
 
328
- method_tag = ''
329
- if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s)
330
- method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
331
- end
288
+ url = options.is_a?(String) ? options : url_for(options)
289
+ remote = html_options.delete('remote')
290
+
291
+ method = html_options.delete('method').to_s
292
+ method_tag = %w{patch put delete}.include?(method) ? method_tag(method) : ''.html_safe
332
293
 
333
- form_method = method.to_s == 'get' ? 'get' : 'post'
294
+ form_method = method == 'get' ? 'get' : 'post'
334
295
  form_options = html_options.delete('form') || {}
335
296
  form_options[:class] ||= html_options.delete('form_class') || 'button_to'
336
-
337
- remote = html_options.delete('remote')
338
-
339
- request_token_tag = ''
340
- if form_method == 'post' && protect_against_forgery?
341
- request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
342
- end
297
+ form_options.merge!(method: form_method, action: url)
298
+ form_options.merge!("data-remote" => "true") if remote
343
299
 
344
- url = options.is_a?(String) ? options : self.url_for(options)
345
- name ||= url
300
+ request_token_tag = form_method == 'post' ? token_tag : ''
346
301
 
347
302
  html_options = convert_options_to_data_attributes(options, html_options)
303
+ html_options['type'] = 'submit'
348
304
 
349
- html_options.merge!("type" => "submit", "value" => name)
305
+ button = if block_given?
306
+ content_tag('button', html_options, &block)
307
+ else
308
+ html_options['value'] = name || url
309
+ tag('input', html_options)
310
+ end
350
311
 
351
- form_options.merge!(:method => form_method, :action => url)
352
- form_options.merge!("data-remote" => "true") if remote
353
-
354
- "#{tag(:form, form_options, true)}<div>#{method_tag}#{tag("input", html_options)}#{request_token_tag}</div></form>".html_safe
312
+ inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag)
313
+ content_tag('form', content_tag('div', inner_tags), form_options)
355
314
  end
356
315
 
357
-
358
316
  # Creates a link tag of the given +name+ using a URL created by the set of
359
317
  # +options+ unless the current request URI is the same as the links, in
360
318
  # which case only the name is returned (or the given block is yielded, if
@@ -366,8 +324,8 @@ module ActionView
366
324
  # Let's say you have a navigation menu...
367
325
  #
368
326
  # <ul id="navbar">
369
- # <li><%= link_to_unless_current("Home", { :action => "index" }) %></li>
370
- # <li><%= link_to_unless_current("About Us", { :action => "about" }) %></li>
327
+ # <li><%= link_to_unless_current("Home", { action: "index" }) %></li>
328
+ # <li><%= link_to_unless_current("About Us", { action: "about" }) %></li>
371
329
  # </ul>
372
330
  #
373
331
  # If in the "about" action, it will render...
@@ -389,8 +347,8 @@ module ActionView
389
347
  # "Go Back" link instead of a link to the comments page, we could do something like this...
390
348
  #
391
349
  # <%=
392
- # link_to_unless_current("Comment", { :controller => "comments", :action => "new" }) do
393
- # link_to("Go back", { :controller => "posts", :action => "index" })
350
+ # link_to_unless_current("Comment", { controller: "comments", action: "new" }) do
351
+ # link_to("Go back", { controller: "posts", action: "index" })
394
352
  # end
395
353
  # %>
396
354
  def link_to_unless_current(name, options = {}, html_options = {}, &block)
@@ -404,13 +362,13 @@ module ActionView
404
362
  # accepts the name or the full argument list for +link_to_unless+.
405
363
  #
406
364
  # ==== Examples
407
- # <%= link_to_unless(@current_user.nil?, "Reply", { :action => "reply" }) %>
365
+ # <%= link_to_unless(@current_user.nil?, "Reply", { action: "reply" }) %>
408
366
  # # If the user is logged in...
409
367
  # # => <a href="/controller/reply/">Reply</a>
410
368
  #
411
369
  # <%=
412
- # link_to_unless(@current_user.nil?, "Reply", { :action => "reply" }) do |name|
413
- # link_to(name, { :controller => "accounts", :action => "signup" })
370
+ # link_to_unless(@current_user.nil?, "Reply", { action: "reply" }) do |name|
371
+ # link_to(name, { controller: "accounts", action: "signup" })
414
372
  # end
415
373
  # %>
416
374
  # # If the user is logged in...
@@ -422,7 +380,7 @@ module ActionView
422
380
  if block_given?
423
381
  block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
424
382
  else
425
- ERB::Util.html_escape(name)
383
+ name
426
384
  end
427
385
  else
428
386
  link_to(name, options, html_options)
@@ -436,13 +394,13 @@ module ActionView
436
394
  # in +link_to_unless+).
437
395
  #
438
396
  # ==== Examples
439
- # <%= link_to_if(@current_user.nil?, "Login", { :controller => "sessions", :action => "new" }) %>
397
+ # <%= link_to_if(@current_user.nil?, "Login", { controller: "sessions", action: "new" }) %>
440
398
  # # If the user isn't logged in...
441
399
  # # => <a href="/sessions/new/">Login</a>
442
400
  #
443
401
  # <%=
444
- # link_to_if(@current_user.nil?, "Login", { :controller => "sessions", :action => "new" }) do
445
- # link_to(@current_user.login, { :controller => "accounts", :action => "show", :id => @current_user })
402
+ # link_to_if(@current_user.nil?, "Login", { controller: "sessions", action: "new" }) do
403
+ # link_to(@current_user.login, { controller: "accounts", action: "show", id: @current_user })
446
404
  # end
447
405
  # %>
448
406
  # # If the user isn't logged in...
@@ -457,132 +415,108 @@ module ActionView
457
415
  # also used as the name of the link unless +name+ is specified. Additional
458
416
  # HTML attributes for the link can be passed in +html_options+.
459
417
  #
460
- # +mail_to+ has several methods for hindering email harvesters and customizing
461
- # the email itself by passing special keys to +html_options+.
418
+ # +mail_to+ has several methods for customizing the email itself by
419
+ # passing special keys to +html_options+.
462
420
  #
463
421
  # ==== Options
464
- # * <tt>:encode</tt> - This key will accept the strings "javascript" or "hex".
465
- # Passing "javascript" will dynamically create and encode the mailto link then
466
- # eval it into the DOM of the page. This method will not show the link on
467
- # the page if the user has JavaScript disabled. Passing "hex" will hex
468
- # encode the +email_address+ before outputting the mailto link.
469
- # * <tt>:replace_at</tt> - When the link +name+ isn't provided, the
470
- # +email_address+ is used for the link label. You can use this option to
471
- # obfuscate the +email_address+ by substituting the @ sign with the string
472
- # given as the value.
473
- # * <tt>:replace_dot</tt> - When the link +name+ isn't provided, the
474
- # +email_address+ is used for the link label. You can use this option to
475
- # obfuscate the +email_address+ by substituting the . in the email with the
476
- # string given as the value.
477
422
  # * <tt>:subject</tt> - Preset the subject line of the email.
478
423
  # * <tt>:body</tt> - Preset the body of the email.
479
424
  # * <tt>:cc</tt> - Carbon Copy additional recipients on the email.
480
425
  # * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
481
426
  #
427
+ # ==== Obfuscation
428
+ # Prior to Rails 4.0, +mail_to+ provided options for encoding the address
429
+ # in order to hinder email harvesters. To take advantage of these options,
430
+ # install the +actionview-encoded_mail_to+ gem.
431
+ #
482
432
  # ==== Examples
483
433
  # mail_to "me@domain.com"
484
434
  # # => <a href="mailto:me@domain.com">me@domain.com</a>
485
435
  #
486
- # mail_to "me@domain.com", "My email", :encode => "javascript"
487
- # # => <script type="text/javascript">eval(decodeURIComponent('%64%6f%63...%27%29%3b'))</script>
436
+ # mail_to "me@domain.com", "My email"
437
+ # # => <a href="mailto:me@domain.com">My email</a>
488
438
  #
489
- # mail_to "me@domain.com", "My email", :encode => "hex"
490
- # # => <a href="mailto:%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a>
439
+ # mail_to "me@domain.com", "My email", cc: "ccaddress@domain.com",
440
+ # subject: "This is an example email"
441
+ # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
491
442
  #
492
- # mail_to "me@domain.com", nil, :replace_at => "_at_", :replace_dot => "_dot_", :class => "email"
493
- # # => <a href="mailto:me@domain.com" class="email">me_at_domain_dot_com</a>
443
+ # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
494
444
  #
495
- # mail_to "me@domain.com", "My email", :cc => "ccaddress@domain.com",
496
- # :subject => "This is an example email"
497
- # # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
498
- def mail_to(email_address, name = nil, html_options = {})
445
+ # <%= mail_to "me@domain.com" do %>
446
+ # <strong>Email me:</strong> <span>me@domain.com</span>
447
+ # <% end %>
448
+ # # => <a href="mailto:me@domain.com">
449
+ # <strong>Email me:</strong> <span>me@domain.com</span>
450
+ # </a>
451
+ def mail_to(email_address, name = nil, html_options = {}, &block)
499
452
  email_address = ERB::Util.html_escape(email_address)
500
453
 
501
- html_options = html_options.stringify_keys
502
- encode = html_options.delete("encode").to_s
454
+ html_options, name = name, nil if block_given?
455
+ html_options = (html_options || {}).stringify_keys
503
456
 
504
457
  extras = %w{ cc bcc body subject }.map { |item|
505
458
  option = html_options.delete(item) || next
506
- "#{item}=#{Rack::Utils.escape(option).gsub("+", "%20")}"
459
+ "#{item}=#{Rack::Utils.escape_path(option)}"
507
460
  }.compact
508
461
  extras = extras.empty? ? '' : '?' + ERB::Util.html_escape(extras.join('&'))
509
462
 
510
- email_address_obfuscated = email_address.to_str
511
- email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.key?("replace_at")
512
- email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.key?("replace_dot")
513
- case encode
514
- when "javascript"
515
- string = ''
516
- html = content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe))
517
- html = escape_javascript(html.to_str)
518
- "document.write('#{html}');".each_byte do |c|
519
- string << sprintf("%%%x", c)
520
- end
521
- "<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>".html_safe
522
- when "hex"
523
- email_address_encoded = email_address_obfuscated.unpack('C*').map {|c|
524
- sprintf("&#%d;", c)
525
- }.join
526
-
527
- string = 'mailto:'.unpack('C*').map { |c|
528
- sprintf("&#%d;", c)
529
- }.join + email_address.unpack('C*').map { |c|
530
- char = c.chr
531
- char =~ /\w/ ? sprintf("%%%x", c) : char
532
- }.join
533
-
534
- content_tag "a", name || email_address_encoded.html_safe, html_options.merge("href" => "#{string}#{extras}".html_safe)
535
- else
536
- content_tag "a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe)
537
- end
463
+ html_options["href"] = "mailto:#{email_address}#{extras}".html_safe
464
+
465
+ content_tag(:a, name || email_address.html_safe, html_options, &block)
538
466
  end
539
467
 
540
468
  # True if the current request URI was generated by the given +options+.
541
469
  #
542
470
  # ==== Examples
543
- # Let's say we're in the <tt>/shop/checkout?order=desc</tt> action.
471
+ # Let's say we're in the <tt>http://www.example.com/shop/checkout?order=desc</tt> action.
544
472
  #
545
- # current_page?(:action => 'process')
473
+ # current_page?(action: 'process')
546
474
  # # => false
547
475
  #
548
- # current_page?(:controller => 'shop', :action => 'checkout')
476
+ # current_page?(controller: 'shop', action: 'checkout')
549
477
  # # => true
550
478
  #
551
- # current_page?(:controller => 'shop', :action => 'checkout', :order => 'asc')
479
+ # current_page?(controller: 'shop', action: 'checkout', order: 'asc')
552
480
  # # => false
553
481
  #
554
- # current_page?(:action => 'checkout')
482
+ # current_page?(action: 'checkout')
555
483
  # # => true
556
484
  #
557
- # current_page?(:controller => 'library', :action => 'checkout')
485
+ # current_page?(controller: 'library', action: 'checkout')
558
486
  # # => false
559
487
  #
560
- # Let's say we're in the <tt>/shop/checkout?order=desc&page=1</tt> action.
488
+ # current_page?('http://www.example.com/shop/checkout')
489
+ # # => true
490
+ #
491
+ # current_page?('/shop/checkout')
492
+ # # => true
561
493
  #
562
- # current_page?(:action => 'process')
494
+ # Let's say we're in the <tt>http://www.example.com/shop/checkout?order=desc&page=1</tt> action.
495
+ #
496
+ # current_page?(action: 'process')
563
497
  # # => false
564
498
  #
565
- # current_page?(:controller => 'shop', :action => 'checkout')
499
+ # current_page?(controller: 'shop', action: 'checkout')
566
500
  # # => true
567
501
  #
568
- # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page => '1')
502
+ # current_page?(controller: 'shop', action: 'checkout', order: 'desc', page: '1')
569
503
  # # => true
570
504
  #
571
- # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page => '2')
505
+ # current_page?(controller: 'shop', action: 'checkout', order: 'desc', page: '2')
572
506
  # # => false
573
507
  #
574
- # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc')
508
+ # current_page?(controller: 'shop', action: 'checkout', order: 'desc')
575
509
  # # => false
576
510
  #
577
- # current_page?(:action => 'checkout')
511
+ # current_page?(action: 'checkout')
578
512
  # # => true
579
513
  #
580
- # current_page?(:controller => 'library', :action => 'checkout')
514
+ # current_page?(controller: 'library', action: 'checkout')
581
515
  # # => false
582
516
  #
583
- # Let's say we're in the <tt>/products</tt> action with method POST in case of invalid product.
517
+ # Let's say we're in the <tt>http://www.example.com/products</tt> action with method POST in case of invalid product.
584
518
  #
585
- # current_page?(:controller => 'product', :action => 'index')
519
+ # current_page?(controller: 'product', action: 'index')
586
520
  # # => false
587
521
  #
588
522
  def current_page?(options)
@@ -592,18 +526,14 @@ module ActionView
592
526
  "in a #request method"
593
527
  end
594
528
 
595
- return false unless request.get?
529
+ return false unless request.get? || request.head?
596
530
 
597
531
  url_string = url_for(options)
598
532
 
599
533
  # We ignore any extra parameters in the request_uri if the
600
534
  # submitted url doesn't have any either. This lets the function
601
535
  # work with things like ?order=asc
602
- if url_string.index("?")
603
- request_uri = request.fullpath
604
- else
605
- request_uri = request.path
606
- end
536
+ request_uri = url_string.index("?") ? request.fullpath : request.path
607
537
 
608
538
  if url_string =~ /^\w+:\/\//
609
539
  url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
@@ -622,9 +552,23 @@ module ActionView
622
552
  confirm = html_options.delete('confirm')
623
553
  method = html_options.delete('method')
624
554
 
625
- html_options["data-disable-with"] = disable_with if disable_with
626
- html_options["data-confirm"] = confirm if confirm
627
- add_method_to_attributes!(html_options, method) if method
555
+ if confirm
556
+ message = ":confirm option is deprecated and will be removed from Rails 4.1. " \
557
+ "Use 'data: { confirm: \'Text\' }' instead."
558
+ ActiveSupport::Deprecation.warn message
559
+
560
+ html_options["data-confirm"] = confirm
561
+ end
562
+
563
+ add_method_to_attributes!(html_options, method) if method
564
+
565
+ if disable_with
566
+ message = ":disable_with option is deprecated and will be removed from Rails 4.1. " \
567
+ "Use 'data: { disable_with: \'Text\' }' instead."
568
+ ActiveSupport::Deprecation.warn message
569
+
570
+ html_options["data-disable-with"] = disable_with
571
+ end
628
572
 
629
573
  html_options
630
574
  else
@@ -640,27 +584,11 @@ module ActionView
640
584
 
641
585
  def add_method_to_attributes!(html_options, method)
642
586
  if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/
643
- html_options["rel"] = "#{html_options["rel"]} nofollow".strip
587
+ html_options["rel"] = "#{html_options["rel"]} nofollow".lstrip
644
588
  end
645
589
  html_options["data-method"] = method
646
590
  end
647
591
 
648
- def options_for_javascript(options)
649
- if options.empty?
650
- '{}'
651
- else
652
- "{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}"
653
- end
654
- end
655
-
656
- def array_or_string_for_javascript(option)
657
- if option.kind_of?(Array)
658
- "['#{option.join('\',\'')}']"
659
- elsif !option.nil?
660
- "'#{option}'"
661
- end
662
- end
663
-
664
592
  # Processes the +html_options+ hash, converting the boolean
665
593
  # attributes from true/false form into the form required by
666
594
  # HTML/XHTML. (An attribute is considered to be boolean if
@@ -688,6 +616,19 @@ module ActionView
688
616
  bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
689
617
  html_options
690
618
  end
619
+
620
+ def token_tag(token=nil)
621
+ if token != false && protect_against_forgery?
622
+ token ||= form_authenticity_token
623
+ tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
624
+ else
625
+ ''
626
+ end
627
+ end
628
+
629
+ def method_tag(method)
630
+ tag('input', type: 'hidden', name: '_method', value: method.to_s)
631
+ end
691
632
  end
692
633
  end
693
634
  end