actionpack 3.2.19 → 4.2.11.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +412 -503
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +11 -294
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +52 -18
  7. data/lib/abstract_controller/callbacks.rb +87 -89
  8. data/lib/abstract_controller/collector.rb +17 -3
  9. data/lib/abstract_controller/helpers.rb +41 -14
  10. data/lib/abstract_controller/logger.rb +1 -2
  11. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  12. data/lib/abstract_controller/rendering.rb +65 -118
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +7 -7
  15. data/lib/abstract_controller.rb +2 -10
  16. data/lib/action_controller/base.rb +61 -28
  17. data/lib/action_controller/caching/fragments.rb +30 -54
  18. data/lib/action_controller/caching.rb +38 -35
  19. data/lib/action_controller/log_subscriber.rb +35 -18
  20. data/lib/action_controller/metal/conditional_get.rb +103 -34
  21. data/lib/action_controller/metal/data_streaming.rb +20 -26
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  23. data/lib/action_controller/metal/exceptions.rb +19 -6
  24. data/lib/action_controller/metal/flash.rb +41 -9
  25. data/lib/action_controller/metal/force_ssl.rb +70 -12
  26. data/lib/action_controller/metal/head.rb +30 -7
  27. data/lib/action_controller/metal/helpers.rb +11 -11
  28. data/lib/action_controller/metal/hide_actions.rb +0 -1
  29. data/lib/action_controller/metal/http_authentication.rb +140 -94
  30. data/lib/action_controller/metal/implicit_render.rb +1 -1
  31. data/lib/action_controller/metal/instrumentation.rb +11 -7
  32. data/lib/action_controller/metal/live.rb +328 -0
  33. data/lib/action_controller/metal/mime_responds.rb +161 -152
  34. data/lib/action_controller/metal/params_wrapper.rb +126 -81
  35. data/lib/action_controller/metal/rack_delegation.rb +10 -4
  36. data/lib/action_controller/metal/redirecting.rb +44 -41
  37. data/lib/action_controller/metal/renderers.rb +48 -19
  38. data/lib/action_controller/metal/rendering.rb +46 -11
  39. data/lib/action_controller/metal/request_forgery_protection.rb +250 -29
  40. data/lib/action_controller/metal/streaming.rb +30 -38
  41. data/lib/action_controller/metal/strong_parameters.rb +669 -0
  42. data/lib/action_controller/metal/testing.rb +12 -18
  43. data/lib/action_controller/metal/url_for.rb +31 -29
  44. data/lib/action_controller/metal.rb +31 -40
  45. data/lib/action_controller/model_naming.rb +12 -0
  46. data/lib/action_controller/railtie.rb +38 -18
  47. data/lib/action_controller/railties/helpers.rb +22 -0
  48. data/lib/action_controller/test_case.rb +359 -173
  49. data/lib/action_controller.rb +9 -16
  50. data/lib/action_dispatch/http/cache.rb +64 -11
  51. data/lib/action_dispatch/http/filter_parameters.rb +20 -10
  52. data/lib/action_dispatch/http/filter_redirect.rb +38 -0
  53. data/lib/action_dispatch/http/headers.rb +85 -17
  54. data/lib/action_dispatch/http/mime_negotiation.rb +55 -5
  55. data/lib/action_dispatch/http/mime_type.rb +167 -114
  56. data/lib/action_dispatch/http/mime_types.rb +2 -1
  57. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  58. data/lib/action_dispatch/http/parameters.rb +30 -46
  59. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  60. data/lib/action_dispatch/http/request.rb +108 -45
  61. data/lib/action_dispatch/http/response.rb +247 -48
  62. data/lib/action_dispatch/http/upload.rb +60 -29
  63. data/lib/action_dispatch/http/url.rb +135 -45
  64. data/lib/action_dispatch/journey/backwards.rb +5 -0
  65. data/lib/action_dispatch/journey/formatter.rb +166 -0
  66. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  67. data/lib/action_dispatch/journey/gtg/simulator.rb +47 -0
  68. data/lib/action_dispatch/journey/gtg/transition_table.rb +157 -0
  69. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  70. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  71. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  72. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  73. data/lib/action_dispatch/journey/nodes/node.rb +128 -0
  74. data/lib/action_dispatch/journey/parser.rb +198 -0
  75. data/lib/action_dispatch/journey/parser.y +49 -0
  76. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  77. data/lib/action_dispatch/journey/path/pattern.rb +193 -0
  78. data/lib/action_dispatch/journey/route.rb +125 -0
  79. data/lib/action_dispatch/journey/router/strexp.rb +27 -0
  80. data/lib/action_dispatch/journey/router/utils.rb +93 -0
  81. data/lib/action_dispatch/journey/router.rb +144 -0
  82. data/lib/action_dispatch/journey/routes.rb +80 -0
  83. data/lib/action_dispatch/journey/scanner.rb +61 -0
  84. data/lib/action_dispatch/journey/visitors.rb +221 -0
  85. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  86. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  87. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  88. data/lib/action_dispatch/journey.rb +5 -0
  89. data/lib/action_dispatch/middleware/callbacks.rb +16 -11
  90. data/lib/action_dispatch/middleware/cookies.rb +346 -125
  91. data/lib/action_dispatch/middleware/debug_exceptions.rb +52 -24
  92. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -9
  93. data/lib/action_dispatch/middleware/flash.rb +85 -72
  94. data/lib/action_dispatch/middleware/params_parser.rb +16 -31
  95. data/lib/action_dispatch/middleware/public_exceptions.rb +39 -14
  96. data/lib/action_dispatch/middleware/reloader.rb +16 -7
  97. data/lib/action_dispatch/middleware/remote_ip.rb +132 -40
  98. data/lib/action_dispatch/middleware/request_id.rb +3 -7
  99. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  100. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  101. data/lib/action_dispatch/middleware/session/cookie_store.rb +84 -29
  102. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  103. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -44
  104. data/lib/action_dispatch/middleware/ssl.rb +72 -0
  105. data/lib/action_dispatch/middleware/stack.rb +6 -1
  106. data/lib/action_dispatch/middleware/static.rb +80 -23
  107. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +34 -0
  108. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +27 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +133 -5
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  125. data/lib/action_dispatch/railtie.rb +19 -6
  126. data/lib/action_dispatch/request/session.rb +193 -0
  127. data/lib/action_dispatch/request/utils.rb +35 -0
  128. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  129. data/lib/action_dispatch/routing/inspector.rb +234 -0
  130. data/lib/action_dispatch/routing/mapper.rb +897 -436
  131. data/lib/action_dispatch/routing/polymorphic_routes.rb +213 -92
  132. data/lib/action_dispatch/routing/redirection.rb +97 -37
  133. data/lib/action_dispatch/routing/route_set.rb +432 -239
  134. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  135. data/lib/action_dispatch/routing/url_for.rb +63 -34
  136. data/lib/action_dispatch/routing.rb +57 -89
  137. data/lib/action_dispatch/testing/assertions/dom.rb +2 -36
  138. data/lib/action_dispatch/testing/assertions/response.rb +24 -38
  139. data/lib/action_dispatch/testing/assertions/routing.rb +55 -54
  140. data/lib/action_dispatch/testing/assertions/selector.rb +2 -434
  141. data/lib/action_dispatch/testing/assertions/tag.rb +2 -137
  142. data/lib/action_dispatch/testing/assertions.rb +11 -7
  143. data/lib/action_dispatch/testing/integration.rb +88 -72
  144. data/lib/action_dispatch/testing/test_process.rb +9 -6
  145. data/lib/action_dispatch/testing/test_request.rb +13 -9
  146. data/lib/action_dispatch/testing/test_response.rb +1 -5
  147. data/lib/action_dispatch.rb +24 -21
  148. data/lib/action_pack/gem_version.rb +15 -0
  149. data/lib/action_pack/version.rb +5 -7
  150. data/lib/action_pack.rb +1 -1
  151. metadata +181 -292
  152. data/lib/abstract_controller/layouts.rb +0 -423
  153. data/lib/abstract_controller/view_paths.rb +0 -96
  154. data/lib/action_controller/caching/actions.rb +0 -185
  155. data/lib/action_controller/caching/pages.rb +0 -187
  156. data/lib/action_controller/caching/sweeping.rb +0 -97
  157. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  158. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  159. data/lib/action_controller/deprecated.rb +0 -3
  160. data/lib/action_controller/metal/compatibility.rb +0 -65
  161. data/lib/action_controller/metal/responder.rb +0 -286
  162. data/lib/action_controller/metal/session_management.rb +0 -14
  163. data/lib/action_controller/railties/paths.rb +0 -25
  164. data/lib/action_controller/record_identifier.rb +0 -85
  165. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  166. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  167. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  168. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  169. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  170. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  171. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  172. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  173. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  174. data/lib/action_dispatch/middleware/head.rb +0 -18
  175. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  176. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  177. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  178. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  179. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  180. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  181. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  182. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  183. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  184. data/lib/action_view/asset_paths.rb +0 -142
  185. data/lib/action_view/base.rb +0 -220
  186. data/lib/action_view/buffers.rb +0 -43
  187. data/lib/action_view/context.rb +0 -36
  188. data/lib/action_view/flows.rb +0 -79
  189. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  190. data/lib/action_view/helpers/asset_paths.rb +0 -7
  191. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  192. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  193. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  194. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  195. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  196. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  197. data/lib/action_view/helpers/cache_helper.rb +0 -64
  198. data/lib/action_view/helpers/capture_helper.rb +0 -203
  199. data/lib/action_view/helpers/controller_helper.rb +0 -25
  200. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  201. data/lib/action_view/helpers/date_helper.rb +0 -1062
  202. data/lib/action_view/helpers/debug_helper.rb +0 -40
  203. data/lib/action_view/helpers/form_helper.rb +0 -1486
  204. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  205. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  206. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  207. data/lib/action_view/helpers/number_helper.rb +0 -622
  208. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  209. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  210. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  211. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  212. data/lib/action_view/helpers/tag_helper.rb +0 -160
  213. data/lib/action_view/helpers/text_helper.rb +0 -426
  214. data/lib/action_view/helpers/translation_helper.rb +0 -91
  215. data/lib/action_view/helpers/url_helper.rb +0 -693
  216. data/lib/action_view/helpers.rb +0 -60
  217. data/lib/action_view/locale/en.yml +0 -160
  218. data/lib/action_view/log_subscriber.rb +0 -28
  219. data/lib/action_view/lookup_context.rb +0 -254
  220. data/lib/action_view/path_set.rb +0 -89
  221. data/lib/action_view/railtie.rb +0 -55
  222. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  223. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  224. data/lib/action_view/renderer/renderer.rb +0 -54
  225. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  226. data/lib/action_view/renderer/template_renderer.rb +0 -94
  227. data/lib/action_view/template/error.rb +0 -128
  228. data/lib/action_view/template/handlers/builder.rb +0 -26
  229. data/lib/action_view/template/handlers/erb.rb +0 -125
  230. data/lib/action_view/template/handlers.rb +0 -50
  231. data/lib/action_view/template/resolver.rb +0 -272
  232. data/lib/action_view/template/text.rb +0 -30
  233. data/lib/action_view/template.rb +0 -337
  234. data/lib/action_view/test_case.rb +0 -245
  235. data/lib/action_view/testing/resolvers.rb +0 -50
  236. data/lib/action_view.rb +0 -84
  237. data/lib/sprockets/assets.rake +0 -99
  238. data/lib/sprockets/bootstrap.rb +0 -37
  239. data/lib/sprockets/compressors.rb +0 -83
  240. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  241. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  242. data/lib/sprockets/helpers.rb +0 -6
  243. data/lib/sprockets/railtie.rb +0 -62
  244. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,693 +0,0 @@
1
- require 'action_view/helpers/javascript_helper'
2
- require 'active_support/core_ext/array/access'
3
- require 'active_support/core_ext/hash/keys'
4
- require 'active_support/core_ext/string/output_safety'
5
- require 'action_dispatch'
6
-
7
- module ActionView
8
- # = Action View URL Helpers
9
- module Helpers #:nodoc:
10
- # Provides a set of methods for making links and getting URLs that
11
- # depend on the routing subsystem (see ActionDispatch::Routing).
12
- # This allows you to use the same format for links in views
13
- # and controllers.
14
- module UrlHelper
15
- # This helper may be included in any class that includes the
16
- # URL helpers of a routes (routes.url_helpers). Some methods
17
- # provided here will only work in the context of a request
18
- # (link_to_unless_current, for instance), which must be provided
19
- # as a method called #request on the context.
20
-
21
- extend ActiveSupport::Concern
22
-
23
- include ActionDispatch::Routing::UrlFor
24
- include TagHelper
25
-
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
38
- end
39
-
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 ||= {}
102
- case options
103
- when String
104
- options
105
- when Hash
106
- options = options.symbolize_keys.reverse_merge!(:only_path => options[:host].nil?)
107
- super
108
- when :back
109
- controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
110
- else
111
- polymorphic_path(options)
112
- end
113
- end
114
-
115
- # Creates a link tag of the given +name+ using a URL created by the set of +options+.
116
- # See the valid options in the documentation for +url_for+. It's also possible to
117
- # pass a String instead of an options hash, which generates a link tag that uses the
118
- # value of the String as the href for the link. Using a <tt>:back</tt> Symbol instead
119
- # of an options hash will generate a link to the referrer (a JavaScript back link
120
- # will be used in place of a referrer if none exists). If +nil+ is passed as the name
121
- # the value of the link itself will become the name.
122
- #
123
- # ==== Signatures
124
- #
125
- # link_to(body, url, html_options = {})
126
- # # url is a String; you can use URL helpers like
127
- # # posts_path
128
- #
129
- # link_to(body, url_options = {}, html_options = {})
130
- # # url_options, except :confirm or :method,
131
- # # is passed to url_for
132
- #
133
- # link_to(options = {}, html_options = {}) do
134
- # # name
135
- # end
136
- #
137
- # link_to(url, html_options = {}) do
138
- # # name
139
- # end
140
- #
141
- # ==== 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
146
- # create an HTML form and immediately submit the form for processing using
147
- # the HTTP verb specified. Useful for having links perform a POST operation
148
- # 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>.
150
- # 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
152
- # disabled clicking the link will have no effect. If you are relying on the
153
- # 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
156
- # driver to make an Ajax request to the URL in question instead of following
157
- # the link. The drivers each provide mechanisms for listening for the
158
- # completion of the Ajax request and performing JavaScript operations once
159
- # they're complete
160
- #
161
- # ==== Examples
162
- # Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
163
- # and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
164
- # your application on resources and use
165
- #
166
- # link_to "Profile", profile_path(@profile)
167
- # # => <a href="/profiles/1">Profile</a>
168
- #
169
- # or the even pithier
170
- #
171
- # link_to "Profile", @profile
172
- # # => <a href="/profiles/1">Profile</a>
173
- #
174
- # in place of the older more verbose, non-resource-oriented
175
- #
176
- # link_to "Profile", :controller => "profiles", :action => "show", :id => @profile
177
- # # => <a href="/profiles/show/1">Profile</a>
178
- #
179
- # Similarly,
180
- #
181
- # link_to "Profiles", profiles_path
182
- # # => <a href="/profiles">Profiles</a>
183
- #
184
- # is better than
185
- #
186
- # link_to "Profiles", :controller => "profiles"
187
- # # => <a href="/profiles">Profiles</a>
188
- #
189
- # You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
190
- #
191
- # <%= link_to(@profile) do %>
192
- # <strong><%= @profile.name %></strong> -- <span>Check it out!</span>
193
- # <% end %>
194
- # # => <a href="/profiles/1">
195
- # <strong>David</strong> -- <span>Check it out!</span>
196
- # </a>
197
- #
198
- # Classes and ids for CSS are easy to produce:
199
- #
200
- # link_to "Articles", articles_path, :id => "news", :class => "article"
201
- # # => <a href="/articles" class="article" id="news">Articles</a>
202
- #
203
- # Be careful when using the older argument style, as an extra literal hash is needed:
204
- #
205
- # link_to "Articles", { :controller => "articles" }, :id => "news", :class => "article"
206
- # # => <a href="/articles" class="article" id="news">Articles</a>
207
- #
208
- # Leaving the hash off gives the wrong link:
209
- #
210
- # link_to "WRONG!", :controller => "articles", :id => "news", :class => "article"
211
- # # => <a href="/articles/index/news?class=article">WRONG!</a>
212
- #
213
- # +link_to+ can also produce links with anchors or query strings:
214
- #
215
- # link_to "Comment wall", profile_path(@profile, :anchor => "wall")
216
- # # => <a href="/profiles/1#wall">Comment wall</a>
217
- #
218
- # link_to "Ruby on Rails search", :controller => "searches", :query => "ruby on rails"
219
- # # => <a href="/searches?query=ruby+on+rails">Ruby on Rails search</a>
220
- #
221
- # link_to "Nonsense search", searches_path(:foo => "bar", :baz => "quux")
222
- # # => <a href="/searches?foo=bar&amp;baz=quux">Nonsense search</a>
223
- #
224
- # The two options specific to +link_to+ (<tt>:confirm</tt> and <tt>:method</tt>) are used as follows:
225
- #
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>
228
- #
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]
240
-
241
- html_options = convert_options_to_data_attributes(options, html_options)
242
- url = url_for(options)
243
-
244
- href = html_options['href']
245
- tag_options = tag_options(html_options)
246
-
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
250
- end
251
-
252
- # Generates a form containing a single button that submits to the URL created
253
- # by the set of +options+. This is the safest method to ensure links that
254
- # cause changes to your data are not triggered by search bots or accelerators.
255
- # If the HTML button does not work with your layout, you can also consider
256
- # using the +link_to+ method with the <tt>:method</tt> modifier as described in
257
- # the +link_to+ documentation.
258
- #
259
- # By default, the generated form element has a class name of <tt>button_to</tt>
260
- # to allow styling of the form itself and its children. This can be changed
261
- # using the <tt>:form_class</tt> modifier within +html_options+. You can control
262
- # 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+.
267
- # If you are using RESTful routes, you can pass the <tt>:method</tt>
268
- # to change the HTTP verb used to submit the form.
269
- #
270
- # ==== Options
271
- # The +options+ hash accepts the same options as +url_for+.
272
- #
273
- # There are a few special +html_options+:
274
- # * <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>.
276
- # * <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.
280
- # * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
281
- # submit behavior. By default this behavior is an ajax submit.
282
- # * <tt>:form</tt> - This hash will be form attributes
283
- # * <tt>:form_class</tt> - This controls the class of the form within which the submit button will
284
- # be placed
285
- #
286
- # ==== Examples
287
- # <%= button_to "New", :action => "new" %>
288
- # # => "<form method="post" action="/controller/new" class="button_to">
289
- # # <div><input value="New" type="submit" /></div>
290
- # # </form>"
291
- #
292
- #
293
- # <%= button_to "New", :action => "new", :form_class => "new-thing" %>
294
- # # => "<form method="post" action="/controller/new" class="new-thing">
295
- # # <div><input value="New" type="submit" /></div>
296
- # # </form>"
297
- #
298
- #
299
- # <%= button_to "Create", :action => "create", :remote => true, :form => { "data-type" => "json" } %>
300
- # # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
301
- # # <div><input value="Create" type="submit" /></div>
302
- # # </form>"
303
- #
304
- #
305
- # <%= button_to "Delete Image", { :action => "delete", :id => @image.id },
306
- # :confirm => "Are you sure?", :method => :delete %>
307
- # # => "<form method="post" action="/images/delete/1" class="button_to">
308
- # # <div>
309
- # # <input type="hidden" name="_method" value="delete" />
310
- # # <input data-confirm='Are you sure?' value="Delete" type="submit" />
311
- # # </div>
312
- # # </form>"
313
- #
314
- #
315
- # <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
316
- # :method => "delete", :remote => true, :disable_with => 'loading...') %>
317
- # # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
318
- # # <div>
319
- # # <input name='_method' value='delete' type='hidden' />
320
- # # <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' />
321
- # # </div>
322
- # # </form>"
323
- # #
324
- def button_to(name, options = {}, html_options = {})
325
- html_options = html_options.stringify_keys
326
- convert_boolean_attributes!(html_options, %w( disabled ))
327
-
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
332
-
333
- form_method = method.to_s == 'get' ? 'get' : 'post'
334
- form_options = html_options.delete('form') || {}
335
- 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
343
-
344
- url = options.is_a?(String) ? options : self.url_for(options)
345
- name ||= url
346
-
347
- html_options = convert_options_to_data_attributes(options, html_options)
348
-
349
- html_options.merge!("type" => "submit", "value" => name)
350
-
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
355
- end
356
-
357
-
358
- # Creates a link tag of the given +name+ using a URL created by the set of
359
- # +options+ unless the current request URI is the same as the links, in
360
- # which case only the name is returned (or the given block is yielded, if
361
- # one exists). You can give +link_to_unless_current+ a block which will
362
- # specialize the default behavior (e.g., show a "Start Here" link rather
363
- # than the link's text).
364
- #
365
- # ==== Examples
366
- # Let's say you have a navigation menu...
367
- #
368
- # <ul id="navbar">
369
- # <li><%= link_to_unless_current("Home", { :action => "index" }) %></li>
370
- # <li><%= link_to_unless_current("About Us", { :action => "about" }) %></li>
371
- # </ul>
372
- #
373
- # If in the "about" action, it will render...
374
- #
375
- # <ul id="navbar">
376
- # <li><a href="/controller/index">Home</a></li>
377
- # <li>About Us</li>
378
- # </ul>
379
- #
380
- # ...but if in the "index" action, it will render:
381
- #
382
- # <ul id="navbar">
383
- # <li>Home</li>
384
- # <li><a href="/controller/about">About Us</a></li>
385
- # </ul>
386
- #
387
- # The implicit block given to +link_to_unless_current+ is evaluated if the current
388
- # action is the action given. So, if we had a comments page and wanted to render a
389
- # "Go Back" link instead of a link to the comments page, we could do something like this...
390
- #
391
- # <%=
392
- # link_to_unless_current("Comment", { :controller => "comments", :action => "new" }) do
393
- # link_to("Go back", { :controller => "posts", :action => "index" })
394
- # end
395
- # %>
396
- def link_to_unless_current(name, options = {}, html_options = {}, &block)
397
- link_to_unless current_page?(options), name, options, html_options, &block
398
- end
399
-
400
- # Creates a link tag of the given +name+ using a URL created by the set of
401
- # +options+ unless +condition+ is true, in which case only the name is
402
- # returned. To specialize the default behavior (i.e., show a login link rather
403
- # than just the plaintext link text), you can pass a block that
404
- # accepts the name or the full argument list for +link_to_unless+.
405
- #
406
- # ==== Examples
407
- # <%= link_to_unless(@current_user.nil?, "Reply", { :action => "reply" }) %>
408
- # # If the user is logged in...
409
- # # => <a href="/controller/reply/">Reply</a>
410
- #
411
- # <%=
412
- # link_to_unless(@current_user.nil?, "Reply", { :action => "reply" }) do |name|
413
- # link_to(name, { :controller => "accounts", :action => "signup" })
414
- # end
415
- # %>
416
- # # If the user is logged in...
417
- # # => <a href="/controller/reply/">Reply</a>
418
- # # If not...
419
- # # => <a href="/accounts/signup">Reply</a>
420
- def link_to_unless(condition, name, options = {}, html_options = {}, &block)
421
- if condition
422
- if block_given?
423
- block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
424
- else
425
- ERB::Util.html_escape(name)
426
- end
427
- else
428
- link_to(name, options, html_options)
429
- end
430
- end
431
-
432
- # Creates a link tag of the given +name+ using a URL created by the set of
433
- # +options+ if +condition+ is true, otherwise only the name is
434
- # returned. To specialize the default behavior, you can pass a block that
435
- # accepts the name or the full argument list for +link_to_unless+ (see the examples
436
- # in +link_to_unless+).
437
- #
438
- # ==== Examples
439
- # <%= link_to_if(@current_user.nil?, "Login", { :controller => "sessions", :action => "new" }) %>
440
- # # If the user isn't logged in...
441
- # # => <a href="/sessions/new/">Login</a>
442
- #
443
- # <%=
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 })
446
- # end
447
- # %>
448
- # # If the user isn't logged in...
449
- # # => <a href="/sessions/new/">Login</a>
450
- # # If they are logged in...
451
- # # => <a href="/accounts/show/3">my_username</a>
452
- def link_to_if(condition, name, options = {}, html_options = {}, &block)
453
- link_to_unless !condition, name, options, html_options, &block
454
- end
455
-
456
- # Creates a mailto link tag to the specified +email_address+, which is
457
- # also used as the name of the link unless +name+ is specified. Additional
458
- # HTML attributes for the link can be passed in +html_options+.
459
- #
460
- # +mail_to+ has several methods for hindering email harvesters and customizing
461
- # the email itself by passing special keys to +html_options+.
462
- #
463
- # ==== 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
- # * <tt>:subject</tt> - Preset the subject line of the email.
478
- # * <tt>:body</tt> - Preset the body of the email.
479
- # * <tt>:cc</tt> - Carbon Copy additional recipients on the email.
480
- # * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
481
- #
482
- # ==== Examples
483
- # mail_to "me@domain.com"
484
- # # => <a href="mailto:me@domain.com">me@domain.com</a>
485
- #
486
- # mail_to "me@domain.com", "My email", :encode => "javascript"
487
- # # => <script type="text/javascript">eval(decodeURIComponent('%64%6f%63...%27%29%3b'))</script>
488
- #
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>
491
- #
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>
494
- #
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 = {})
499
- email_address = ERB::Util.html_escape(email_address)
500
-
501
- html_options = html_options.stringify_keys
502
- encode = html_options.delete("encode").to_s
503
-
504
- extras = %w{ cc bcc body subject }.map { |item|
505
- option = html_options.delete(item) || next
506
- "#{item}=#{Rack::Utils.escape(option).gsub("+", "%20")}"
507
- }.compact
508
- extras = extras.empty? ? '' : '?' + ERB::Util.html_escape(extras.join('&'))
509
-
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
538
- end
539
-
540
- # True if the current request URI was generated by the given +options+.
541
- #
542
- # ==== Examples
543
- # Let's say we're in the <tt>/shop/checkout?order=desc</tt> action.
544
- #
545
- # current_page?(:action => 'process')
546
- # # => false
547
- #
548
- # current_page?(:controller => 'shop', :action => 'checkout')
549
- # # => true
550
- #
551
- # current_page?(:controller => 'shop', :action => 'checkout', :order => 'asc')
552
- # # => false
553
- #
554
- # current_page?(:action => 'checkout')
555
- # # => true
556
- #
557
- # current_page?(:controller => 'library', :action => 'checkout')
558
- # # => false
559
- #
560
- # Let's say we're in the <tt>/shop/checkout?order=desc&page=1</tt> action.
561
- #
562
- # current_page?(:action => 'process')
563
- # # => false
564
- #
565
- # current_page?(:controller => 'shop', :action => 'checkout')
566
- # # => true
567
- #
568
- # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page => '1')
569
- # # => true
570
- #
571
- # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page => '2')
572
- # # => false
573
- #
574
- # current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc')
575
- # # => false
576
- #
577
- # current_page?(:action => 'checkout')
578
- # # => true
579
- #
580
- # current_page?(:controller => 'library', :action => 'checkout')
581
- # # => false
582
- #
583
- # Let's say we're in the <tt>/products</tt> action with method POST in case of invalid product.
584
- #
585
- # current_page?(:controller => 'product', :action => 'index')
586
- # # => false
587
- #
588
- def current_page?(options)
589
- unless request
590
- raise "You cannot use helpers that need to determine the current " \
591
- "page unless your view context provides a Request object " \
592
- "in a #request method"
593
- end
594
-
595
- return false unless request.get?
596
-
597
- url_string = url_for(options)
598
-
599
- # We ignore any extra parameters in the request_uri if the
600
- # submitted url doesn't have any either. This lets the function
601
- # 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
607
-
608
- if url_string =~ /^\w+:\/\//
609
- url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
610
- else
611
- url_string == request_uri
612
- end
613
- end
614
-
615
- private
616
- def convert_options_to_data_attributes(options, html_options)
617
- if html_options
618
- html_options = html_options.stringify_keys
619
- html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
620
-
621
- disable_with = html_options.delete("disable_with")
622
- confirm = html_options.delete('confirm')
623
- method = html_options.delete('method')
624
-
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
628
-
629
- html_options
630
- else
631
- link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
632
- end
633
- end
634
-
635
- def link_to_remote_options?(options)
636
- if options.is_a?(Hash)
637
- options.delete('remote') || options.delete(:remote)
638
- end
639
- end
640
-
641
- def add_method_to_attributes!(html_options, method)
642
- if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/
643
- html_options["rel"] = "#{html_options["rel"]} nofollow".strip
644
- end
645
- html_options["data-method"] = method
646
- end
647
-
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
- # Processes the +html_options+ hash, converting the boolean
665
- # attributes from true/false form into the form required by
666
- # HTML/XHTML. (An attribute is considered to be boolean if
667
- # its name is listed in the given +bool_attrs+ array.)
668
- #
669
- # More specifically, for each boolean attribute in +html_options+
670
- # given as:
671
- #
672
- # "attr" => bool_value
673
- #
674
- # if the associated +bool_value+ evaluates to true, it is
675
- # replaced with the attribute's name; otherwise the attribute is
676
- # removed from the +html_options+ hash. (See the XHTML 1.0 spec,
677
- # section 4.5 "Attribute Minimization" for more:
678
- # http://www.w3.org/TR/xhtml1/#h-4.5)
679
- #
680
- # Returns the updated +html_options+ hash, which is also modified
681
- # in place.
682
- #
683
- # Example:
684
- #
685
- # convert_boolean_attributes!( html_options,
686
- # %w( checked disabled readonly ) )
687
- def convert_boolean_attributes!(html_options, bool_attrs)
688
- bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
689
- html_options
690
- end
691
- end
692
- end
693
- end