Browse files

Merge branch 'master' of https://github.com/lifo/docrails

Conflicts:
	activerecord/lib/active_record/callbacks.rb
  • Loading branch information...
2 parents 3e6b2f5 + ae27acb commit e041a50f2917f82950f9e5666f966d8992afd45d @elpic elpic committed Oct 22, 2012
Showing with 3,006 additions and 2,448 deletions.
  1. +5 −5 Gemfile
  2. +0 −1 actionmailer/lib/action_mailer/railtie.rb
  3. +26 −1 actionpack/CHANGELOG.md
  4. +1 −1 actionpack/lib/abstract_controller/asset_paths.rb
  5. +4 −2 actionpack/lib/abstract_controller/base.rb
  6. +9 −9 actionpack/lib/action_controller/base.rb
  7. +2 −8 actionpack/lib/action_controller/metal/hide_actions.rb
  8. +28 −3 actionpack/lib/action_controller/metal/strong_parameters.rb
  9. +0 −1 actionpack/lib/action_controller/railtie.rb
  10. +6 −5 actionpack/lib/action_controller/test_case.rb
  11. +24 −5 actionpack/lib/action_dispatch/http/filter_parameters.rb
  12. +25 −18 actionpack/lib/action_dispatch/http/headers.rb
  13. +44 −46 actionpack/lib/action_dispatch/http/parameter_filter.rb
  14. +7 −1 actionpack/lib/action_dispatch/http/request.rb
  15. +0 −1 actionpack/lib/action_view.rb
  16. +0 −143 actionpack/lib/action_view/asset_paths.rb
  17. +31 −9 actionpack/lib/action_view/digestor.rb
  18. +2 −4 actionpack/lib/action_view/helpers.rb
  19. +80 −278 actionpack/lib/action_view/helpers/asset_tag_helper.rb
  20. +0 −93 actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
  21. +0 −70 actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
  22. +0 −71 actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
  23. +355 −0 actionpack/lib/action_view/helpers/asset_url_helper.rb
  24. +8 −1 actionpack/lib/action_view/helpers/date_helper.rb
  25. +5 −3 actionpack/lib/action_view/helpers/tags/check_box.rb
  26. +0 −8 actionpack/lib/action_view/railtie.rb
  27. +29 −8 actionpack/lib/action_view/test_case.rb
  28. +14 −9 actionpack/test/controller/parameters/multi_parameter_attributes_test.rb
  29. +5 −1 actionpack/test/controller/parameters/nested_parameters_test.rb
  30. +1 −1 actionpack/test/controller/parameters/parameters_permit_test.rb
  31. +20 −0 actionpack/test/dispatch/header_test.rb
  32. 0 actionpack/test/fixtures/digestor/level/below/_header.html.erb
  33. +1 −0 actionpack/test/fixtures/digestor/level/below/index.html.erb
  34. +2 −0 actionpack/test/fixtures/test/render_two_partials.html.erb
  35. +166 −113 actionpack/test/template/asset_tag_helper_test.rb
  36. +19 −10 actionpack/test/template/date_helper_i18n_test.rb
  37. +16 −0 actionpack/test/template/date_helper_test.rb
  38. +15 −5 actionpack/test/template/digestor_test.rb
  39. +6 −0 actionpack/test/template/form_helper_test.rb
  40. +1 −5 actionpack/test/template/sanitize_helper_test.rb
  41. +8 −0 actionpack/test/template/test_case_test.rb
  42. +1 −1 activemodel/CHANGELOG.md
  43. +1 −1 activemodel/lib/active_model/attribute_methods.rb
  44. +1 −1 activemodel/lib/active_model/callbacks.rb
  45. +1 −1 activemodel/lib/active_model/conversion.rb
  46. +1 −1 activemodel/lib/active_model/dirty.rb
  47. +1 −1 activemodel/lib/active_model/errors.rb
  48. +4 −4 activemodel/lib/active_model/lint.rb
  49. +1 −1 activemodel/lib/active_model/model.rb
  50. +1 −1 activemodel/lib/active_model/naming.rb
  51. +3 −3 activemodel/lib/active_model/observing.rb
  52. +2 −2 activemodel/lib/active_model/railtie.rb
  53. +1 −1 activemodel/lib/active_model/serialization.rb
  54. +1 −1 activemodel/lib/active_model/translation.rb
  55. +7 −6 activemodel/lib/active_model/validations.rb
  56. +1 −1 activemodel/lib/active_model/validations/acceptance.rb
  57. +1 −1 activemodel/lib/active_model/validations/callbacks.rb
  58. +1 −1 activemodel/lib/active_model/validations/confirmation.rb
  59. +1 −1 activemodel/lib/active_model/validations/exclusion.rb
  60. +1 −1 activemodel/lib/active_model/validations/inclusion.rb
  61. +3 −3 activemodel/lib/active_model/validations/length.rb
  62. +2 −2 activemodel/lib/active_model/validations/numericality.rb
  63. +2 −2 activemodel/lib/active_model/validations/presence.rb
  64. +1 −1 activemodel/lib/active_model/validator.rb
  65. +1 −1 activemodel/test/cases/secure_password_test.rb
  66. +73 −2 activerecord/CHANGELOG.md
  67. +14 −10 activerecord/lib/active_record/associations/preloader.rb
  68. +2 −3 activerecord/lib/active_record/attribute_assignment.rb
  69. +130 −25 activerecord/lib/active_record/attribute_methods.rb
  70. +43 −0 activerecord/lib/active_record/attribute_methods/before_type_cast.rb
  71. +18 −16 activerecord/lib/active_record/attribute_methods/dirty.rb
  72. +31 −20 activerecord/lib/active_record/attribute_methods/read.rb
  73. +1 −1 activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
  74. +14 −10 activerecord/lib/active_record/attribute_methods/write.rb
  75. +5 −8 activerecord/lib/active_record/callbacks.rb
  76. +10 −8 activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
  77. +0 −4 activerecord/lib/active_record/connection_adapters/column.rb
  78. +2 −4 activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
  79. +2 −4 activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
  80. +1 −1 activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
  81. +5 −8 activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
  82. +3 −5 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  83. +2 −1 activerecord/lib/active_record/fixtures.rb
  84. +5 −1 activerecord/lib/active_record/locale/en.yml
  85. +1 −0 activerecord/lib/active_record/querying.rb
  86. +1 −1 activerecord/lib/active_record/railties/databases.rake
  87. +31 −22 activerecord/lib/active_record/relation.rb
  88. +2 −2 activerecord/lib/active_record/relation/calculations.rb
  89. +17 −5 activerecord/lib/active_record/relation/merger.rb
  90. +56 −15 activerecord/lib/active_record/relation/query_methods.rb
  91. +2 −1 activerecord/lib/active_record/timestamp.rb
  92. +4 −2 activerecord/lib/active_record/validations/presence.rb
  93. +2 −1 activerecord/lib/active_record/validations/uniqueness.rb
  94. +3 −3 activerecord/lib/rails/generators/active_record.rb
  95. +3 −3 activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
  96. +2 −2 activerecord/lib/rails/generators/active_record/model/model_generator.rb
  97. +2 −2 activerecord/lib/rails/generators/active_record/observer/observer_generator.rb
  98. +13 −0 activerecord/test/cases/adapters/postgresql/quoting_test.rb
  99. +2 −2 activerecord/test/cases/adapters/postgresql/schema_test.rb
  100. +1 −1 activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
  101. +0 −1 activerecord/test/cases/associations/has_many_through_associations_test.rb
  102. +2 −2 activerecord/test/cases/attribute_methods_test.rb
  103. +1 −2 activerecord/test/cases/autosave_association_test.rb
  104. +10 −13 activerecord/test/cases/calculations_test.rb
  105. +95 −17 activerecord/test/cases/defaults_test.rb
  106. +29 −15 activerecord/test/cases/dirty_test.rb
  107. +14 −0 activerecord/test/cases/dup_test.rb
  108. +1 −1 activerecord/test/cases/migration/change_schema_test.rb
  109. +1 −5 activerecord/test/cases/migration_test.rb
  110. +1 −1 activerecord/test/cases/query_cache_test.rb
  111. +0 −1 activerecord/test/cases/reflection_test.rb
  112. +49 −1 activerecord/test/cases/relations_test.rb
  113. +1 −5 activerecord/test/cases/schema_dumper_test.rb
  114. +6 −1 activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
  115. +7 −0 activerecord/test/cases/validations/presence_validation_test.rb
  116. +8 −1 activerecord/test/schema/postgresql_specific_schema.rb
  117. +1 −1 activerecord/test/support/connection.rb
  118. +11 −0 activesupport/CHANGELOG.md
  119. +4 −0 activesupport/lib/active_support/cache/mem_cache_store.rb
  120. +1 −1 activesupport/lib/active_support/core_ext/array/extract_options.rb
  121. +1 −1 activesupport/lib/active_support/core_ext/array/wrap.rb
  122. +1 −1 activesupport/lib/active_support/core_ext/hash/conversions.rb
  123. +3 −3 activesupport/lib/active_support/core_ext/hash/deep_merge.rb
  124. +4 −4 activesupport/lib/active_support/core_ext/hash/slice.rb
  125. +4 −4 activesupport/lib/active_support/core_ext/module/deprecation.rb
  126. +5 −2 activesupport/lib/active_support/core_ext/object.rb
  127. +4 −0 activesupport/lib/active_support/core_ext/object/conversions.rb
  128. +1 −1 activesupport/lib/active_support/core_ext/time/calculations.rb
  129. +34 −19 activesupport/lib/active_support/descendants_tracker.rb
  130. +0 −30 activesupport/lib/active_support/queueing.rb
  131. +1 −1 activesupport/lib/active_support/testing/performance/ruby.rb
  132. +14 −0 activesupport/test/caching_test.rb
  133. +1 −1 activesupport/test/callbacks_test.rb
  134. +1 −0 activesupport/test/core_ext/array_ext_test.rb
  135. +26 −1 activesupport/test/core_ext/hash_ext_test.rb
  136. +13 −7 activesupport/test/descendants_tracker_test_cases.rb
  137. +5 −5 activesupport/test/descendants_tracker_with_autoloading_test.rb
  138. +0 −28 activesupport/test/queueing/container_test.rb
  139. +44 −0 activesupport/test/queueing/test_queue_test.rb
  140. +12 −3 activesupport/test/testing/performance_test.rb
  141. +6 −2 guides/source/4_0_release_notes.md
  142. +35 −21 guides/source/active_record_querying.md
  143. +8 −0 guides/source/active_support_core_extensions.md
  144. +0 −316 guides/source/ajax_on_rails.md
  145. +2 −14 guides/source/configuring.md
  146. +1 −1 guides/source/initialization.md
  147. +21 −0 guides/source/migrations.md
  148. +2 −0 guides/source/upgrading_ruby_on_rails.md
  149. +394 −0 guides/source/working_with_javascript.md
  150. +1 −1 rails.gemspec
  151. +4 −2 railties/CHANGELOG.md
  152. +1 −1 railties/lib/rails/all.rb
  153. +7 −11 railties/lib/rails/application.rb
  154. +7 −7 railties/lib/rails/application/bootstrap.rb
  155. +7 −11 railties/lib/rails/application/configuration.rb
  156. +5 −4 railties/lib/rails/application/finisher.rb
  157. +1 −1 railties/lib/rails/application/routes_reloader.rb
  158. +32 −23 railties/lib/rails/commands.rb
  159. +1 −1 railties/lib/rails/commands/destroy.rb
  160. +1 −1 railties/lib/rails/commands/generate.rb
  161. +1 −1 railties/lib/rails/commands/runner.rb
  162. +7 −7 railties/lib/rails/commands/server.rb
  163. +1 −1 railties/lib/rails/commands/update.rb
  164. +8 −8 railties/lib/rails/engine.rb
  165. +15 −15 railties/lib/rails/engine/configuration.rb
  166. +29 −29 railties/lib/rails/generators.rb
  167. +22 −22 railties/lib/rails/generators/actions.rb
  168. +4 −4 railties/lib/rails/generators/base.rb
  169. +2 −2 railties/lib/rails/generators/erb.rb
  170. +4 −4 railties/lib/rails/generators/erb/controller/controller_generator.rb
  171. +3 −3 railties/lib/rails/generators/erb/mailer/mailer_generator.rb
  172. +4 −4 railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
  173. +4 −4 railties/lib/rails/generators/generated_attribute.rb
  174. +2 −2 railties/lib/rails/generators/js/assets/assets_generator.rb
  175. +3 −3 railties/lib/rails/generators/named_base.rb
  176. +4 −4 railties/lib/rails/generators/rails/app/app_generator.rb
  177. +1 −1 railties/lib/rails/generators/rails/app/templates/config/application.rb
  178. +3 −1 railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
  179. +0 −3 railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
  180. +4 −3 railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
  181. +2 −2 railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
  182. +4 −4 railties/lib/rails/generators/rails/assets/assets_generator.rb
  183. +2 −2 railties/lib/rails/generators/rails/controller/controller_generator.rb
  184. +3 −3 railties/lib/rails/generators/rails/generator/generator_generator.rb
  185. +2 −2 railties/lib/rails/generators/rails/helper/helper_generator.rb
  186. +1 −1 railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb
  187. +2 −2 railties/lib/rails/generators/rails/migration/migration_generator.rb
  188. +2 −2 railties/lib/rails/generators/rails/model/model_generator.rb
  189. +1 −1 railties/lib/rails/generators/rails/observer/observer_generator.rb
  190. +1 −1 railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb
  191. +16 −16 railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb
  192. +1 −1 .../lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt
  193. +1 −1 railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb
  194. +4 −4 railties/lib/rails/generators/rails/resource/resource_generator.rb
  195. +3 −3 railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
  196. +6 −6 railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
  197. +1 −1 railties/lib/rails/generators/rails/task/task_generator.rb
  198. +1 −1 railties/lib/rails/generators/rails/task/templates/task.rb
  199. +1 −1 railties/lib/rails/generators/resource_helpers.rb
  200. +2 −2 railties/lib/rails/generators/test_case.rb
  201. +2 −2 railties/lib/rails/generators/test_unit/controller/controller_generator.rb
  202. +1 −1 railties/lib/rails/generators/test_unit/helper/helper_generator.rb
  203. +1 −1 railties/lib/rails/generators/test_unit/integration/integration_generator.rb
  204. +2 −2 railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
  205. +3 −3 railties/lib/rails/generators/test_unit/model/model_generator.rb
  206. +1 −1 railties/lib/rails/generators/test_unit/observer/observer_generator.rb
  207. +1 −1 railties/lib/rails/generators/test_unit/performance/performance_generator.rb
  208. +1 −1 railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb
  209. +2 −2 railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
  210. +1 −1 railties/lib/rails/info_controller.rb
  211. +1 −1 railties/lib/rails/paths.rb
  212. +1 −1 railties/lib/rails/railtie.rb
  213. +1 −1 railties/lib/rails/railtie/configurable.rb
  214. +4 −4 railties/lib/rails/railtie/configuration.rb
  215. +7 −7 railties/lib/rails/source_annotation_extractor.rb
  216. +1 −1 railties/lib/rails/tasks/annotations.rake
  217. +5 −5 railties/lib/rails/tasks/framework.rake
  218. +1 −1 railties/lib/rails/tasks/middleware.rake
  219. +2 −2 railties/lib/rails/tasks/misc.rake
  220. +1 −1 railties/lib/rails/tasks/routes.rake
  221. +2 −2 railties/lib/rails/tasks/tmp.rake
  222. +2 −2 railties/lib/rails/test_unit/railtie.rb
  223. +14 −14 railties/lib/rails/test_unit/testing.rake
  224. +4 −5 railties/test/application/asset_debugging_test.rb
  225. +56 −130 railties/test/application/assets_test.rb
  226. +14 −42 railties/test/application/configuration_test.rb
  227. +15 −15 railties/test/application/generators_test.rb
  228. +2 −3 railties/test/application/initializers/frameworks_test.rb
  229. +7 −7 railties/test/application/initializers/i18n_test.rb
  230. +1 −1 railties/test/application/initializers/notifications_test.rb
  231. +14 −14 railties/test/application/loading_test.rb
  232. +24 −14 railties/test/application/middleware/cache_test.rb
  233. +1 −1 railties/test/application/middleware/session_test.rb
  234. +5 −8 railties/test/application/middleware_test.rb
  235. +21 −58 railties/test/application/queue_test.rb
  236. +3 −1 railties/test/application/rake/notes_test.rb
  237. +5 −5 railties/test/application/rake_test.rb
  238. +14 −14 railties/test/application/routing_test.rb
  239. +4 −3 railties/test/application/url_generation_test.rb
  240. +4 −4 railties/test/commands/console_test.rb
  241. +1 −1 railties/test/fixtures/lib/plugin_builders/spec_builder.rb
  242. +18 −18 railties/test/generators/actions_test.rb
  243. +6 −10 railties/test/generators/app_generator_test.rb
  244. +3 −3 railties/test/generators/model_generator_test.rb
  245. +3 −3 railties/test/generators/namespaced_generators_test.rb
  246. +2 −2 railties/test/generators/orm_test.rb
  247. +1 −1 railties/test/generators/plugin_new_generator_test.rb
  248. +1 −1 railties/test/generators/resource_generator_test.rb
  249. +1 −1 railties/test/generators/scaffold_generator_test.rb
  250. +7 −7 railties/test/generators/shared_generator_tests.rb
  251. +4 −4 railties/test/generators_test.rb
  252. +9 −9 railties/test/initializable_test.rb
  253. +4 −4 railties/test/isolation/abstract_unit.rb
  254. +14 −14 railties/test/paths_test.rb
  255. +3 −3 railties/test/rails_info_controller_test.rb
  256. +21 −21 railties/test/railties/engine_test.rb
  257. +1 −1 railties/test/railties/generators_test.rb
  258. +19 −19 railties/test/railties/mounted_engine_test.rb
View
10 Gemfile
@@ -6,9 +6,9 @@ gem 'arel', github: 'rails/arel', branch: 'master'
gem 'mocha', '>= 0.11.2', :require => false
gem 'rack-test', github: 'brynary/rack-test'
-gem 'rack-cache', "~> 1.2"
+gem 'rack-cache', '~> 1.2'
gem 'bcrypt-ruby', '~> 3.0.0'
-gem 'jquery-rails'
+gem 'jquery-rails', '~> 2.1.4', github: 'rails/jquery-rails'
gem 'turbolinks'
gem 'coffee-rails', github: 'rails/coffee-rails'
@@ -28,7 +28,7 @@ group :doc do
# for some weeks unapplied. As a temporary solution
# this is our own fork with the fix.
gem 'sdoc', github: 'fxn/sdoc'
- gem 'redcarpet', '~> 2.1.1'
+ gem 'redcarpet', '~> 2.1.1', :platforms => :ruby
gem 'w3c_validators'
end
@@ -41,8 +41,8 @@ instance_eval File.read local_gemfile if File.exists? local_gemfile
platforms :mri do
group :test do
- gem 'ruby-prof', '~> 0.11.2'
- gem 'debugger' if !ENV['TRAVIS'] && RUBY_VERSION < "2.0"
+ gem 'ruby-prof', '~> 0.11.2' if RUBY_VERSION < '2.0'
+ gem 'debugger' if !ENV['TRAVIS'] && RUBY_VERSION < '2.0' && RUBY_PATCHLEVEL < 286
end
end
View
1 actionmailer/lib/action_mailer/railtie.rb
@@ -22,7 +22,6 @@ class Railtie < Rails::Railtie # :nodoc:
options.queue ||= app.queue
# make sure readers methods get compiled
- options.asset_path ||= app.config.asset_path
options.asset_host ||= app.config.asset_host
options.relative_url_root ||= app.config.relative_url_root
View
27 actionpack/CHANGELOG.md
@@ -1,6 +1,31 @@
## Rails 4.0.0 (unreleased) ##
-* Remove old asset tag concatenation (no longer needed now that we have the asset pipeline). *Josh Peek*
+* `date_select` helper accepts `with_css_classes: true` to add css classes similar with type
+ of generated select tags.
+
+ *Pavel Nikitin*
+
+* Only non-js/css under app/assets path will be included in default config.assets.precompile.
+
+ *Josh Peek*
+
+* Remove support for the RAILS_ASSET_ID environment configuration
+ (no longer needed now that we have the asset pipeline).
+
+ *Josh Peek*
+
+* Remove old asset_path configuration (no longer needed now that we have the asset pipeline).
+
+ *Josh Peek*
+
+* `assert_template` can be used to assert on the same template with different locals
+ Fix #3675
+
+ *Yves Senn*
+
+* Remove old asset tag concatenation (no longer needed now that we have the asset pipeline).
+
+ *Josh Peek*
* Accept :remote as symbolic option for `link_to` helper. *Riley Lynch*
View
2 actionpack/lib/abstract_controller/asset_paths.rb
@@ -3,7 +3,7 @@ module AssetPaths #:nodoc:
extend ActiveSupport::Concern
included do
- config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir,
+ config_accessor :asset_host, :assets_dir, :javascripts_dir,
:stylesheets_dir, :default_asset_host_protocol, :relative_url_root
end
end
View
6 actionpack/lib/abstract_controller/base.rb
@@ -217,8 +217,10 @@ def _handle_action_missing(*args)
# * <tt>string</tt> - The name of the method that handles the action
# * <tt>nil</tt> - No method name could be found. Raise ActionNotFound.
def method_for_action(action_name)
- if action_method?(action_name) then action_name
- elsif respond_to?(:action_missing, true) then "_handle_action_missing"
+ if action_method?(action_name)
+ action_name
+ elsif respond_to?(:action_missing, true)
+ "_handle_action_missing"
end
end
end
View
18 actionpack/lib/action_controller/base.rb
@@ -43,7 +43,7 @@ module ActionController
#
# def server_ip
# location = request.env["SERVER_ADDR"]
- # render :text => "This server hosted at #{location}"
+ # render text: "This server hosted at #{location}"
# end
#
# == Parameters
@@ -113,9 +113,9 @@ module ActionController
# def search
# @results = Search.find(params[:query])
# case @results.count
- # when 0 then render :action => "no_results"
- # when 1 then render :action => "show"
- # when 2..10 then render :action => "show_many"
+ # when 0 then render action: "no_results"
+ # when 1 then render action: "show"
+ # when 2..10 then render action: "show_many"
# end
# end
#
@@ -131,7 +131,7 @@ module ActionController
# @entry = Entry.new(params[:entry])
# if @entry.save
# # The entry was saved correctly, redirect to show
- # redirect_to :action => 'show', :id => @entry.id
+ # redirect_to action: 'show', id: @entry.id
# else
# # things didn't go so well, do something else
# end
@@ -148,15 +148,15 @@ module ActionController
# An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError:
#
# def do_something
- # redirect_to :action => "elsewhere"
- # render :action => "overthere" # raises DoubleRenderError
+ # redirect_to action: "elsewhere"
+ # render action: "overthere" # raises DoubleRenderError
# end
#
# If you need to redirect on the condition of something, then be sure to add "and return" to halt execution.
#
# def do_something
- # redirect_to(:action => "elsewhere") and return if monkeys.nil?
- # render :action => "overthere" # won't be called if monkeys is nil
+ # redirect_to(action: "elsewhere") and return if monkeys.nil?
+ # render action: "overthere" # won't be called if monkeys is nil
# end
#
class Base < Metal
View
10 actionpack/lib/action_controller/metal/hide_actions.rb
@@ -26,20 +26,14 @@ def hide_action(*args)
self.hidden_actions = hidden_actions.dup.merge(args.map(&:to_s)).freeze
end
- def inherited(klass)
- klass.class_eval { @visible_actions = {} }
- super
- end
-
def visible_action?(action_name)
- return @visible_actions[action_name] if @visible_actions.key?(action_name)
- @visible_actions[action_name] = !hidden_actions.include?(action_name)
+ action_methods.include?(action_name)
end
# Overrides AbstractController::Base#action_methods to remove any methods
# that are listed as hidden methods.
def action_methods
- @action_methods ||= Set.new(super.reject { |name| hidden_actions.include?(name) })
+ @action_methods ||= Set.new(super.reject { |name| hidden_actions.include?(name) }).freeze
end
end
end
View
31 actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -171,14 +171,39 @@ def require(key)
# permitted[:person][:age] # => nil
# permitted[:person][:pets][0][:name] # => "Purplish"
# permitted[:person][:pets][0][:category] # => nil
+ #
+ # Note that if you use +permit+ in a key that points to a hash,
+ # it won't allow all the hash. You also need to specify which
+ # attributes inside the hash should be whitelisted.
+ #
+ # params = ActionController::Parameters.new({
+ # person: {
+ # contact: {
+ # email: 'none@test.com'
+ # phone: '555-1234'
+ # }
+ # }
+ # })
+ #
+ # params.require(:person).permit(:contact)
+ # # => {}
+ #
+ # params.require(:person).permit(contact: :phone)
+ # # => {"contact"=>{"phone"=>"555-1234"}}
+ #
+ # params.require(:person).permit(contact: [ :email, :phone ])
+ # # => {"contact"=>{"email"=>"none@test.com", "phone"=>"555-1234"}}
def permit(*filters)
params = self.class.new
filters.each do |filter|
case filter
when Symbol, String then
- params[filter] = self[filter] if has_key?(filter)
- keys.grep(/\A#{Regexp.escape(filter)}\(\di\)\z/) { |key| params[key] = self[key] }
+ if has_key?(filter)
+ _value = self[filter]
+ params[filter] = _value unless Hash === _value
+ end
+ keys.grep(/\A#{Regexp.escape(filter)}\(\d+[if]?\)\z/) { |key| params[key] = self[key] }
when Hash then
self.slice(*filter.keys).each do |key, values|
return unless values
@@ -336,7 +361,7 @@ def each_element(object)
# # It's mandatory to specify the nested attributes that should be whitelisted.
# # If you use `permit` with just the key that points to the nested attributes hash,
# # it will return an empty hash.
- # params.require(:person).permit(:name, :age, pets_attributes: { :name, :category })
+ # params.require(:person).permit(:name, :age, pets_attributes: [ :name, :category ])
# end
# end
#
View
1 actionpack/lib/action_controller/railtie.rb
@@ -34,7 +34,6 @@ class Railtie < Rails::Railtie #:nodoc:
options.stylesheets_dir ||= paths["public/stylesheets"].first
# Ensure readers methods get compiled
- options.asset_path ||= app.config.asset_path
options.asset_host ||= app.config.asset_host
options.relative_url_root ||= app.config.relative_url_root
View
11 actionpack/lib/action_controller/test_case.rb
@@ -123,11 +123,12 @@ def assert_template(options = {}, message = nil)
if expected_partial = options[:partial]
if expected_locals = options[:locals]
- if defined?(@locals)
- actual_locals = @locals[expected_partial.to_s.sub(/^_/,'')]
- expected_locals.each_pair do |k,v|
- assert_equal(v, actual_locals[k])
- end
+ if defined?(@_rendered_views)
+ view = expected_partial.to_s.sub(/^_/,'')
+ msg = 'expecting %s to be rendered with %s but was with %s' % [expected_partial,
+ expected_locals,
+ @_rendered_views.locals_for(view)]
+ assert(@_rendered_views.view_rendered?(view, options[:locals]), msg)
else
warn "the :locals option to #assert_template is only supported in a ActionView::TestCase"
end
View
29 actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -1,3 +1,4 @@
+require 'mutex_m'
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/object/duplicable'
@@ -20,9 +21,18 @@ module Http
# end
# => reverses the value to all keys matching /secret/i
module FilterParameters
- extend ActiveSupport::Concern
+ @@parameter_filter_for = {}.extend(Mutex_m)
- @@parameter_filter_for = {}
+ ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
+ NULL_PARAM_FILTER = ParameterFilter.new # :nodoc:
+ NULL_ENV_FILTER = ParameterFilter.new ENV_MATCH # :nodoc:
+
+ def initialize(env)
+ super
+ @filtered_parameters = nil
+ @filtered_env = nil
+ @filtered_path = nil
+ end
# Return a hash of parameters with all sensitive data replaced.
def filtered_parameters
@@ -42,15 +52,24 @@ def filtered_path
protected
def parameter_filter
- parameter_filter_for(@env["action_dispatch.parameter_filter"])
+ parameter_filter_for @env.fetch("action_dispatch.parameter_filter") {
+ return NULL_PARAM_FILTER
+ }
end
def env_filter
- parameter_filter_for(Array(@env["action_dispatch.parameter_filter"]) + [/RAW_POST_DATA/, "rack.request.form_vars"])
+ user_key = @env.fetch("action_dispatch.parameter_filter") {
+ return NULL_ENV_FILTER
+ }
+ parameter_filter_for(Array(user_key) + ENV_MATCH)
end
def parameter_filter_for(filters)
- @@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
+ @@parameter_filter_for.synchronize do
+ # Do we *actually* need this cache? Constructing ParameterFilters
+ # doesn't seem too expensive.
+ @@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
+ end
end
KV_RE = '[^&;=]+'
View
43 actionpack/lib/action_dispatch/http/headers.rb
@@ -1,32 +1,39 @@
module ActionDispatch
module Http
- class Headers < ::Hash
- @@env_cache = Hash.new { |h,k| h[k] = "HTTP_#{k.upcase.gsub(/-/, '_')}" }
+ class Headers
+ include Enumerable
- def initialize(*args)
-
- if args.size == 1 && args[0].is_a?(Hash)
- super()
- update(args[0])
- else
- super
- end
+ def initialize(env = {})
+ @headers = env
end
def [](header_name)
- super env_name(header_name)
+ @headers[env_name(header_name)]
+ end
+
+ def []=(k,v); @headers[k] = v; end
+ def key?(k); @headers.key? k; end
+ alias :include? :key?
+
+ def fetch(header_name, *args, &block)
+ @headers.fetch env_name(header_name), *args, &block
end
- def fetch(header_name, default=nil, &block)
- super env_name(header_name), default, &block
+ def each(&block)
+ @headers.each(&block)
end
private
- # Converts a HTTP header name to an environment variable name if it is
- # not contained within the headers hash.
- def env_name(header_name)
- include?(header_name) ? header_name : @@env_cache[header_name]
- end
+
+ # Converts a HTTP header name to an environment variable name if it is
+ # not contained within the headers hash.
+ def env_name(header_name)
+ @headers.include?(header_name) ? header_name : cgi_name(header_name)
+ end
+
+ def cgi_name(k)
+ "HTTP_#{k.upcase.gsub(/-/, '_')}"
+ end
end
end
end
View
90 actionpack/lib/action_dispatch/http/parameter_filter.rb
@@ -1,74 +1,72 @@
module ActionDispatch
module Http
class ParameterFilter
+ FILTERED = '[FILTERED]'.freeze # :nodoc:
- def initialize(filters)
+ def initialize(filters = [])
@filters = filters
end
def filter(params)
- if enabled?
- compiled_filter.call(params)
- else
- params.dup
- end
+ compiled_filter.call(params)
end
private
- def enabled?
- @filters.present?
+ def compiled_filter
+ @compiled_filter ||= CompiledFilter.compile(@filters)
end
- FILTERED = '[FILTERED]'.freeze
+ class CompiledFilter # :nodoc:
+ def self.compile(filters)
+ return lambda { |params| params.dup } if filters.empty?
- def compiled_filter
- @compiled_filter ||= begin
- regexps, blocks = compile_filter
+ strings, regexps, blocks = [], [], []
- lambda do |original_params|
- filtered_params = {}
+ filters.each do |item|
+ case item
+ when Proc
+ blocks << item
+ when Regexp
+ regexps << item
+ else
+ strings << item.to_s
+ end
+ end
- original_params.each do |key, value|
- if regexps.find { |r| key =~ r }
- value = FILTERED
- elsif value.is_a?(Hash)
- value = filter(value)
- elsif value.is_a?(Array)
- value = value.map { |v| v.is_a?(Hash) ? filter(v) : v }
- elsif blocks.present?
- key = key.dup
- value = value.dup if value.duplicable?
- blocks.each { |b| b.call(key, value) }
- end
+ regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
+ new regexps, blocks
+ end
- filtered_params[key] = value
- end
+ attr_reader :regexps, :blocks
- filtered_params
- end
+ def initialize(regexps, blocks)
+ @regexps = regexps
+ @blocks = blocks
end
- end
- def compile_filter
- strings, regexps, blocks = [], [], []
+ def call(original_params)
+ filtered_params = {}
+
+ original_params.each do |key, value|
+ if regexps.any? { |r| key =~ r }
+ value = FILTERED
+ elsif value.is_a?(Hash)
+ value = call(value)
+ elsif value.is_a?(Array)
+ value = value.map { |v| v.is_a?(Hash) ? call(v) : v }
+ elsif blocks.any?
+ key = key.dup
+ value = value.dup if value.duplicable?
+ blocks.each { |b| b.call(key, value) }
+ end
- @filters.each do |item|
- case item
- when NilClass
- when Proc
- blocks << item
- when Regexp
- regexps << item
- else
- strings << item.to_s
+ filtered_params[key] = value
end
- end
- regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
- [regexps, blocks]
+ filtered_params
+ end
end
-
end
end
end
View
8 actionpack/lib/action_dispatch/http/request.rb
@@ -70,7 +70,13 @@ def key?(key)
RFC5789 = %w(PATCH)
HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789
- HTTP_METHOD_LOOKUP = Hash.new { |h, m| h[m] = m.underscore.to_sym if HTTP_METHODS.include?(m) }
+
+ HTTP_METHOD_LOOKUP = {}
+
+ # Populate the HTTP method lookup cache
+ HTTP_METHODS.each { |method|
+ HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
+ }
# Returns the HTTP \method that the application should see.
# In the case where the \method was overridden by a middleware
View
1 actionpack/lib/action_view.rb
@@ -29,7 +29,6 @@ module ActionView
extend ActiveSupport::Autoload
eager_autoload do
- autoload :AssetPaths
autoload :Base
autoload :Context
autoload :CompiledTemplates, "action_view/context"
View
143 actionpack/lib/action_view/asset_paths.rb
@@ -1,143 +0,0 @@
-require 'zlib'
-require 'active_support/core_ext/file'
-
-module ActionView
- class AssetPaths #:nodoc:
- URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}
-
- attr_reader :config, :controller
-
- def initialize(config, controller = nil)
- @config = config
- @controller = controller
- end
-
- # Add the extension +ext+ if not present. Return full or scheme-relative URLs otherwise untouched.
- # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL
- # roots. Rewrite the asset path for cache-busting asset ids. Include
- # asset host, if configured, with the correct request protocol.
- #
- # When :relative (default), the protocol will be determined by the client using current protocol
- # When :request, the protocol will be the request protocol
- # Otherwise, the protocol is used (E.g. :http, :https, etc)
- def compute_public_path(source, dir, options = {})
- source = source.to_s
- return source if is_uri?(source)
-
- source = rewrite_extension(source, dir, options[:ext]) if options[:ext]
- source = rewrite_asset_path(source, dir, options)
- source = rewrite_relative_url_root(source, relative_url_root)
- source = rewrite_host_and_protocol(source, options[:protocol])
- source
- end
-
- # Return the filesystem path for the source
- def compute_source_path(source, dir, ext)
- source = rewrite_extension(source, dir, ext) if ext
-
- sources = []
- sources << config.assets_dir
- sources << dir unless source[0] == ?/
- sources << source
-
- File.join(sources)
- end
-
- def is_uri?(path)
- path =~ URI_REGEXP
- end
-
- private
-
- def rewrite_extension(source, dir, ext)
- raise NotImplementedError
- end
-
- def rewrite_asset_path(source, path = nil)
- raise NotImplementedError
- end
-
- def rewrite_relative_url_root(source, relative_url_root)
- relative_url_root && !source.starts_with?("#{relative_url_root}/") ? "#{relative_url_root}#{source}" : source
- end
-
- def has_request?
- controller.respond_to?(:request)
- end
-
- def rewrite_host_and_protocol(source, protocol = nil)
- host = compute_asset_host(source)
- if host && !is_uri?(host)
- if (protocol || default_protocol) == :request && !has_request?
- host = nil
- else
- host = "#{compute_protocol(protocol)}#{host}"
- end
- end
- host ? "#{host}#{source}" : source
- end
-
- def compute_protocol(protocol)
- protocol ||= default_protocol
- case protocol
- when :relative
- "//"
- when :request
- unless @controller
- invalid_asset_host!("The protocol requested was :request. Consider using :relative instead.")
- end
- @controller.request.protocol
- else
- "#{protocol}://"
- end
- end
-
- def default_protocol
- @config.default_asset_host_protocol || (has_request? ? :request : :relative)
- end
-
- def invalid_asset_host!(help_message)
- raise ActionView::MissingRequestError, "This asset host cannot be computed without a request in scope. #{help_message}"
- end
-
- # Pick an asset host for this source. Returns +nil+ if no host is set,
- # the host if no wildcard is set, the host interpolated with the
- # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4),
- # or the value returned from invoking call on an object responding to call
- # (proc or otherwise).
- def compute_asset_host(source)
- if host = asset_host_config
- if host.respond_to?(:call)
- args = [source]
- arity = arity_of(host)
- if (arity > 1 || arity < -2) && !has_request?
- invalid_asset_host!("Remove the second argument to your asset_host Proc if you do not need the request, or make it optional.")
- end
- args << current_request if (arity > 1 || arity < 0) && has_request?
- host.call(*args)
- else
- (host =~ /%d/) ? host % (Zlib.crc32(source) % 4) : host
- end
- end
- end
-
- def relative_url_root
- config.relative_url_root || current_request.try(:script_name)
- end
-
- def asset_host_config
- config.asset_host
- end
-
- # Returns the current request if one exists.
- def current_request
- controller.request if has_request?
- end
-
- # Returns the arity of a callable
- def arity_of(callable)
- callable.respond_to?(:arity) ? callable.arity : callable.method(:call).arity
- end
-
- end
-end
View
40 actionpack/lib/action_view/digestor.rb
@@ -1,3 +1,5 @@
+require 'mutex_m'
+
module ActionView
class Digestor
EXPLICIT_DEPENDENCY = /# Template Dependency: ([^ ]+)/
@@ -19,16 +21,30 @@ class Digestor
/x
cattr_reader(:cache)
- @@cache = Hash.new
+ @@cache = Hash.new.extend Mutex_m
def self.digest(name, format, finder, options = {})
- cache["#{name}.#{format}"] ||= new(name, format, finder, options).digest
+ cache.synchronize do
+ unsafe_digest name, format, finder, options
+ end
end
- attr_reader :name, :format, :finder, :options
+ ###
+ # This method is NOT thread safe. DO NOT CALL IT DIRECTLY, instead call
+ # Digestor.digest
+ def self.unsafe_digest(name, format, finder, options = {}) # :nodoc:
+ key = "#{name}.#{format}"
- def initialize(name, format, finder, options = {})
- @name, @format, @finder, @options = name, format, finder, options
+ cache.fetch(key) do
+ klass = options[:partial] || name.include?("/_") ? PartialDigestor : Digestor
+ cache[key] = klass.new(name, format, finder).digest
+ end
+ end
+
+ attr_reader :name, :format, :finder
+
+ def initialize(name, format, finder)
+ @name, @format, @finder = name, format, finder
end
def digest
@@ -48,7 +64,7 @@ def dependencies
def nested_dependencies
dependencies.collect do |dependency|
- dependencies = Digestor.new(dependency, format, finder, partial: true).nested_dependencies
+ dependencies = PartialDigestor.new(dependency, format, finder).nested_dependencies
dependencies.any? ? { dependency => dependencies } : dependency
end
end
@@ -64,11 +80,11 @@ def logical_name
end
def directory
- name.split("/").first
+ name.split("/")[0..-2].join("/")
end
def partial?
- options[:partial] || name.include?("/_")
+ false
end
def source
@@ -77,7 +93,7 @@ def source
def dependency_digest
dependencies.collect do |template_name|
- Digestor.digest(template_name, format, finder, partial: true)
+ Digestor.unsafe_digest(template_name, format, finder, partial: true)
end.join("-")
end
@@ -101,4 +117,10 @@ def explicit_dependencies
source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
end
end
+
+ class PartialDigestor < Digestor # :nodoc:
+ def partial?
+ true
+ end
+ end
end
View
6 actionpack/lib/action_view/helpers.rb
@@ -4,6 +4,7 @@ module Helpers #:nodoc:
autoload :ActiveModelHelper
autoload :AssetTagHelper
+ autoload :AssetUrlHelper
autoload :AtomFeedHelper
autoload :BenchmarkHelper
autoload :CacheHelper
@@ -28,12 +29,9 @@ module Helpers #:nodoc:
extend ActiveSupport::Concern
- included do
- extend SanitizeHelper::ClassMethods
- end
-
include ActiveModelHelper
include AssetTagHelper
+ include AssetUrlHelper
include AtomFeedHelper
include BenchmarkHelper
include CacheHelper
View
358 actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -1,8 +1,6 @@
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/hash/keys'
-require 'action_view/helpers/asset_tag_helpers/javascript_tag_helpers'
-require 'action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers'
-require 'action_view/helpers/asset_tag_helpers/asset_paths'
+require 'action_view/helpers/asset_url_helper'
require 'action_view/helpers/tag_helper'
module ActionView
@@ -17,187 +15,87 @@ module Helpers #:nodoc:
# stylesheet_link_tag("application")
# # => <link href="/assets/application.css?body=1" media="screen" rel="stylesheet" />
#
- #
- # === Using asset hosts
- #
- # By default, Rails links to these assets on the current host in the public
- # folder, but you can direct Rails to link to assets from a dedicated asset
- # server by setting <tt>ActionController::Base.asset_host</tt> in the application
- # configuration, typically in <tt>config/environments/production.rb</tt>.
- # For example, you'd define <tt>assets.example.com</tt> to be your asset
- # host this way, inside the <tt>configure</tt> block of your environment-specific
- # configuration files or <tt>config/application.rb</tt>:
- #
- # config.action_controller.asset_host = "assets.example.com"
- #
- # Helpers take that into account:
- #
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # Browsers typically open at most two simultaneous connections to a single
- # host, which means your assets often have to wait for other assets to finish
- # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the
- # +asset_host+. For example, "assets%d.example.com". If that wildcard is
- # present Rails distributes asset requests among the corresponding four hosts
- # "assets0.example.com", ..., "assets3.example.com". With this trick browsers
- # will open eight simultaneous connections rather than two.
- #
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets0.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # To do this, you can either setup four actual hosts, or you can use wildcard
- # DNS to CNAME the wildcard to a single asset host. You can read more about
- # setting up your DNS CNAME records from your ISP.
- #
- # Note: This is purely a browser performance optimization and is not meant
- # for server load balancing. See http://www.die.net/musings/page_load_time/
- # for background.
- #
- # Alternatively, you can exert more control over the asset host by setting
- # +asset_host+ to a proc like this:
- #
- # ActionController::Base.asset_host = Proc.new { |source|
- # "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
- # }
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets1.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # The example above generates "http://assets1.example.com" and
- # "http://assets2.example.com". This option is useful for example if
- # you need fewer/more than four hosts, custom host names, etc.
- #
- # As you see the proc takes a +source+ parameter. That's a string with the
- # absolute path of the asset, for example "/assets/rails.png".
- #
- # ActionController::Base.asset_host = Proc.new { |source|
- # if source.ends_with?('.css')
- # "http://stylesheets.example.com"
- # else
- # "http://assets.example.com"
- # end
- # }
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://stylesheets.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # Alternatively you may ask for a second parameter +request+. That one is
- # particularly useful for serving assets from an SSL-protected page. The
- # example proc below disables asset hosting for HTTPS connections, while
- # still sending assets for plain HTTP requests from asset hosts. If you don't
- # have SSL certificates for each of the asset hosts this technique allows you
- # to avoid warnings in the client about mixed media.
- #
- # config.action_controller.asset_host = Proc.new { |source, request|
- # if request.ssl?
- # "#{request.protocol}#{request.host_with_port}"
- # else
- # "#{request.protocol}assets.example.com"
- # end
- # }
- #
- # You can also implement a custom asset host object that responds to +call+
- # and takes either one or two parameters just like the proc.
- #
- # config.action_controller.asset_host = AssetHostingWithMinimumSsl.new(
- # "http://asset%d.example.com", "https://asset1.example.com"
- # )
- #
- # === Customizing the asset path
- #
- # By default, Rails appends asset's timestamps to all asset paths. This allows
- # you to set a cache-expiration date for the asset far into the future, but
- # still be able to instantly invalidate it by simply updating the file (and
- # hence updating the timestamp, which then updates the URL as the timestamp
- # is part of that, which in turn busts the cache).
- #
- # It's the responsibility of the web server you use to set the far-future
- # expiration date on cache assets that you need to take advantage of this
- # feature. Here's an example for Apache:
- #
- # # Asset Expiration
- # ExpiresActive On
- # <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
- # ExpiresDefault "access plus 1 year"
- # </FilesMatch>
- #
- # Also note that in order for this to work, all your application servers must
- # return the same timestamps. This means that they must have their clocks
- # synchronized. If one of them drifts out of sync, you'll see different
- # timestamps at random and the cache won't work. In that case the browser
- # will request the same assets over and over again even thought they didn't
- # change. You can use something like Live HTTP Headers for Firefox to verify
- # that the cache is indeed working.
- #
- # This strategy works well enough for most server setups and requires the
- # least configuration, but if you deploy several application servers at
- # different times - say to handle a temporary spike in load - then the
- # asset time stamps will be out of sync. In a setup like this you may want
- # to set the way that asset paths are generated yourself.
- #
- # Altering the asset paths that Rails generates can be done in two ways.
- # The easiest is to define the RAILS_ASSET_ID environment variable. The
- # contents of this variable will always be used in preference to
- # calculated timestamps. A more complex but flexible way is to set
- # <tt>ActionController::Base.config.asset_path</tt> to a proc
- # that takes the unmodified asset path and returns the path needed for
- # your asset caching to work. Typically you'd do something like this in
- # <tt>config/environments/production.rb</tt>:
- #
- # # Normally you'd calculate RELEASE_NUMBER at startup.
- # RELEASE_NUMBER = 12345
- # config.action_controller.asset_path = proc { |asset_path|
- # "/release-#{RELEASE_NUMBER}#{asset_path}"
- # }
- #
- # This example would cause the following behavior on all servers no
- # matter when they were deployed:
- #
- # image_tag("rails.png")
- # # => <img alt="Rails" src="/release-12345/images/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="/release-12345/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" />
- #
- # Changing the asset_path does require that your web servers have
- # knowledge of the asset template paths that you rewrite to so it's not
- # suitable for out-of-the-box use. To use the example given above you
- # could use something like this in your Apache VirtualHost configuration:
- #
- # <LocationMatch "^/release-\d+/(images|javascripts|stylesheets)/.*$">
- # # Some browsers still send conditional-GET requests if there's a
- # # Last-Modified header or an ETag header even if they haven't
- # # reached the expiry date sent in the Expires header.
- # Header unset Last-Modified
- # Header unset ETag
- # FileETag None
- #
- # # Assets requested using a cache-busting filename should be served
- # # only once and then cached for a really long time. The HTTP/1.1
- # # spec frowns on hugely-long expiration times though and suggests
- # # that assets which never expire be served with an expiration date
- # # 1 year from access.
- # ExpiresActive On
- # ExpiresDefault "access plus 1 year"
- # </LocationMatch>
- #
- # # We use cached-busting location names with the far-future expires
- # # headers to ensure that if a file does change it can force a new
- # # request. The actual asset filenames are still the same though so we
- # # need to rewrite the location from the cache-busting location to the
- # # real asset location so that we can serve it.
- # RewriteEngine On
- # RewriteRule ^/release-\d+/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L]
module AssetTagHelper
+ extend ActiveSupport::Concern
+
+ include AssetUrlHelper
include TagHelper
- include JavascriptTagHelpers
- include StylesheetTagHelpers
+
+ # Returns an HTML script tag for each of the +sources+ provided.
+ #
+ # Sources may be paths to JavaScript files. Relative paths are assumed to be relative
+ # to <tt>assets/javascripts</tt>, full paths are assumed to be relative to the document
+ # root. Relative paths are idiomatic, use absolute paths only when needed.
+ #
+ # When passing paths, the ".js" extension is optional.
+ #
+ # You can modify the HTML attributes of the script tag by passing a hash as the
+ # last argument.
+ #
+ # javascript_include_tag "xmlhr"
+ # # => <script src="/assets/xmlhr.js?1284139606"></script>
+ #
+ # javascript_include_tag "xmlhr.js"
+ # # => <script src="/assets/xmlhr.js?1284139606"></script>
+ #
+ # javascript_include_tag "common.javascript", "/elsewhere/cools"
+ # # => <script src="/assets/common.javascript?1284139606"></script>
+ # # <script src="/elsewhere/cools.js?1423139606"></script>
+ #
+ # javascript_include_tag "http://www.example.com/xmlhr"
+ # # => <script src="http://www.example.com/xmlhr"></script>
+ #
+ # javascript_include_tag "http://www.example.com/xmlhr.js"
+ # # => <script src="http://www.example.com/xmlhr.js"></script>
+ #
+ def javascript_include_tag(*sources)
+ options = sources.extract_options!.stringify_keys
+ sources.uniq.map { |source|
+ tag_options = {
+ "src" => path_to_javascript(source)
+ }.merge(options)
+ content_tag(:script, "", tag_options)
+ }.join("\n").html_safe
+ end
+
+ # Returns a stylesheet link tag for the sources specified as arguments. If
+ # you don't specify an extension, <tt>.css</tt> will be appended automatically.
+ # You can modify the link attributes by passing a hash as the last argument.
+ # For historical reasons, the 'media' attribute will always be present and defaults
+ # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to
+ # apply to all media types.
+ #
+ # stylesheet_link_tag "style"
+ # # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "style.css"
+ # # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "http://www.example.com/style.css"
+ # # => <link href="http://www.example.com/style.css" media="screen" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "style", :media => "all"
+ # # => <link href="/assets/style.css" media="all" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "style", :media => "print"
+ # # => <link href="/assets/style.css" media="print" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "random.styles", "/css/stylish"
+ # # => <link href="/assets/random.styles" media="screen" rel="stylesheet" />
+ # # <link href="/css/stylish.css" media="screen" rel="stylesheet" />
+ #
+ def stylesheet_link_tag(*sources)
+ options = sources.extract_options!.stringify_keys
+ sources.uniq.map { |source|
+ tag_options = {
+ "rel" => "stylesheet",
+ "media" => "screen",
+ "href" => path_to_stylesheet(source)
+ }.merge(options)
+ tag(:link, tag_options)
+ }.join("\n").html_safe
+ end
+
# Returns a link tag that browsers and news readers can use to auto-detect
# an RSS or Atom feed. The +type+ can either be <tt>:rss</tt> (default) or
# <tt>:atom</tt>. Control the link options in url_for format using the
@@ -268,93 +166,6 @@ def favicon_link_tag(source='favicon.ico', options={})
}.merge(options.symbolize_keys))
end
- # Computes the path to an image asset.
- # Full paths from the document root will be passed through.
- # Used internally by +image_tag+ to build the image path:
- #
- # image_path("edit") # => "/assets/edit"
- # image_path("edit.png") # => "/assets/edit.png"
- # image_path("icons/edit.png") # => "/assets/icons/edit.png"
- # image_path("/icons/edit.png") # => "/icons/edit.png"
- # image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png"
- #
- # If you have images as application resources this method may conflict with their named routes.
- # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and
- # plugin authors are encouraged to do so.
- def image_path(source)
- source.present? ? asset_paths.compute_public_path(source, 'images') : ""
- end
- alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route
-
- # Computes the full URL to an image asset.
- # This will use +image_path+ internally, so most of their behaviors will be the same.
- def image_url(source)
- URI.join(current_host, path_to_image(source)).to_s
- end
- alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route
-
- # Computes the path to a video asset in the public videos directory.
- # Full paths from the document root will be passed through.
- # Used internally by +video_tag+ to build the video path.
- #
- # video_path("hd") # => /videos/hd
- # video_path("hd.avi") # => /videos/hd.avi
- # video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
- # video_path("/trailers/hd.avi") # => /trailers/hd.avi
- # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi
- def video_path(source)
- asset_paths.compute_public_path(source, 'videos')
- end
- alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route
-
- # Computes the full URL to a video asset in the public videos directory.
- # This will use +video_path+ internally, so most of their behaviors will be the same.
- def video_url(source)
- URI.join(current_host, path_to_video(source)).to_s
- end
- alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route
-
- # Computes the path to an audio asset in the public audios directory.
- # Full paths from the document root will be passed through.
- # Used internally by +audio_tag+ to build the audio path.
- #
- # audio_path("horse") # => /audios/horse
- # audio_path("horse.wav") # => /audios/horse.wav
- # audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
- # audio_path("/sounds/horse.wav") # => /sounds/horse.wav
- # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav
- def audio_path(source)
- asset_paths.compute_public_path(source, 'audios')
- end
- alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route
-
- # Computes the full URL to an audio asset in the public audios directory.
- # This will use +audio_path+ internally, so most of their behaviors will be the same.
- def audio_url(source)
- URI.join(current_host, path_to_audio(source)).to_s
- end
- alias_method :url_to_audio, :audio_url # aliased to avoid conflicts with an audio_url named route
-
- # Computes the path to a font asset.
- # Full paths from the document root will be passed through.
- #
- # font_path("font") # => /assets/font
- # font_path("font.ttf") # => /assets/font.ttf
- # font_path("dir/font.ttf") # => /assets/dir/font.ttf
- # font_path("/dir/font.ttf") # => /dir/font.ttf
- # font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf
- def font_path(source)
- asset_paths.compute_public_path(source, 'fonts')
- end
- alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route
-
- # Computes the full URL to a font asset.
- # This will use +font_path+ internally, so most of their behaviors will be the same.
- def font_url(source)
- URI.join(current_host, path_to_font(source)).to_s
- end
- alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route
-
# Returns an html image tag for the +source+. The +source+ can be a full
# path or a file.
#
@@ -462,11 +273,6 @@ def audio_tag(*sources)
end
private
-
- def asset_paths
- @asset_paths ||= AssetTagHelper::AssetPaths.new(config, controller)
- end
-
def multiple_sources_tag(type, sources)
options = sources.extract_options!.symbolize_keys
sources.flatten!
@@ -482,10 +288,6 @@ def multiple_sources_tag(type, sources)
content_tag(type, nil, options)
end
end
-
- def current_host
- url_for(:only_path => false)
- end
end
end
end
View
93 actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
@@ -1,93 +0,0 @@
-require 'thread'
-require 'active_support/core_ext/file'
-require 'active_support/core_ext/module/attribute_accessors'
-
-module ActionView
- module Helpers
- module AssetTagHelper
-
- class AssetPaths < ::ActionView::AssetPaths #:nodoc:
- # You can enable or disable the asset tag ids cache.
- # With the cache enabled, the asset tag helper methods will make fewer
- # expensive file system calls (the default implementation checks the file
- # system timestamp). However this prevents you from modifying any asset
- # files while the server is running.
- #
- # ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids = false
- mattr_accessor :cache_asset_ids
-
- # Add or change an asset id in the asset id cache. This can be used
- # for SASS on Heroku.
- # :api: public
- def add_to_asset_ids_cache(source, asset_id)
- self.asset_ids_cache_guard.synchronize do
- self.asset_ids_cache[source] = asset_id
- end
- end
-
- private
-
- def rewrite_extension(source, dir, ext)
- source_ext = File.extname(source)
-
- source_with_ext = if source_ext.empty?
- "#{source}.#{ext}"
- elsif ext != source_ext[1..-1]
- with_ext = "#{source}.#{ext}"
- with_ext if File.exist?(File.join(config.assets_dir, dir, with_ext))
- end
-
- source_with_ext || source
- end
-
- # Break out the asset path rewrite in case plugins wish to put the asset id
- # someplace other than the query string.
- def rewrite_asset_path(source, dir, options = nil)
- source = "/#{dir}/#{source}" unless source[0] == ?/
- path = config.asset_path
-
- if path && path.respond_to?(:call)
- return path.call(source)
- elsif path && path.is_a?(String)
- return path % [source]
- end
-
- asset_id = rails_asset_id(source)
- if asset_id.empty?
- source
- else
- "#{source}?#{asset_id}"
- end
- end
-
- mattr_accessor :asset_ids_cache
- self.asset_ids_cache = {}
-
- mattr_accessor :asset_ids_cache_guard
- self.asset_ids_cache_guard = Mutex.new
-
- # Use the RAILS_ASSET_ID environment variable or the source's
- # modification time as its cache-busting asset id.
- def rails_asset_id(source)
- if asset_id = ENV["RAILS_ASSET_ID"]
- asset_id
- else
- if self.cache_asset_ids && (asset_id = self.asset_ids_cache[source])
- asset_id
- else
- path = File.join(config.assets_dir, source)
- asset_id = File.exist?(path) ? File.mtime(path).to_i.to_s : ''
-
- if self.cache_asset_ids
- add_to_asset_ids_cache(source, asset_id)
- end
-
- asset_id
- end
- end
- end
- end
-
- end
- end
-end
View
70 actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
@@ -1,70 +0,0 @@
-require 'active_support/core_ext/file'
-
-module ActionView
- module Helpers
- module AssetTagHelper
- module JavascriptTagHelpers
- extend ActiveSupport::Concern
-
- # Computes the path to a javascript asset in the public javascripts directory.
- # If the +source+ filename has no extension, .js will be appended (except for explicit URIs)
- # Full paths from the document root will be passed through.
- # Used internally by javascript_include_tag to build the script path.
- #
- # javascript_path "xmlhr" # => /javascripts/xmlhr.js
- # javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
- # javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
- # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr
- # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
- def javascript_path(source)
- asset_paths.compute_public_path(source, 'javascripts', :ext => 'js')
- end
- alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
-
- # Computes the full URL to a javascript asset in the public javascripts directory.
- # This will use +javascript_path+ internally, so most of their behaviors will be the same.
- def javascript_url(source)
- URI.join(current_host, path_to_javascript(source)).to_s
- end
- alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route
-
- # Returns an HTML script tag for each of the +sources+ provided.
- #
- # Sources may be paths to JavaScript files. Relative paths are assumed to be relative
- # to <tt>public/javascripts</tt>, full paths are assumed to be relative to the document
- # root. Relative paths are idiomatic, use absolute paths only when needed.
- #
- # When passing paths, the ".js" extension is optional.
- #
- # You can modify the HTML attributes of the script tag by passing a hash as the
- # last argument.
- #
- # javascript_include_tag "xmlhr"
- # # => <script src="/javascripts/xmlhr.js?1284139606"></script>
- #
- # javascript_include_tag "xmlhr.js"
- # # => <script src="/javascripts/xmlhr.js?1284139606"></script>
- #
- # javascript_include_tag "common.javascript", "/elsewhere/cools"
- # # => <script src="/javascripts/common.javascript?1284139606"></script>
- # # <script src="/elsewhere/cools.js?1423139606"></script>
- #
- # javascript_include_tag "http://www.example.com/xmlhr"
- # # => <script src="http://www.example.com/xmlhr"></script>
- #
- # javascript_include_tag "http://www.example.com/xmlhr.js"
- # # => <script src="http://www.example.com/xmlhr.js"></script>
- #
- def javascript_include_tag(*sources)
- options = sources.extract_options!.stringify_keys
- sources.dup.map { |source|
- tag_options = {
- "src" => path_to_javascript(source)
- }.merge(options)
- content_tag(:script, "", tag_options)
- }.join("\n").html_safe
- end
- end
- end
- end
-end
View
71 actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
@@ -1,71 +0,0 @@
-require 'active_support/core_ext/file'
-
-module ActionView
- module Helpers
- module AssetTagHelper
- module StylesheetTagHelpers
- extend ActiveSupport::Concern
-
- # Computes the path to a stylesheet asset in the public stylesheets directory.
- # If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs).
- # Full paths from the document root will be passed through.
- # Used internally by +stylesheet_link_tag+ to build the stylesheet path.
- #
- # stylesheet_path "style" # => /stylesheets/style.css
- # stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
- # stylesheet_path "/dir/style.css" # => /dir/style.css
- # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style
- # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
- def stylesheet_path(source)
- asset_paths.compute_public_path(source, 'stylesheets', :ext => 'css', :protocol => :request)
- end
- alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route
-
- # Computes the full URL to a stylesheet asset in the public stylesheets directory.
- # This will use +stylesheet_path+ internally, so most of their behaviors will be the same.
- def stylesheet_url(source)
- URI.join(current_host, path_to_stylesheet(source)).to_s
- end
- alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route
-
- # Returns a stylesheet link tag for the sources specified as arguments. If
- # you don't specify an extension, <tt>.css</tt> will be appended automatically.
- # You can modify the link attributes by passing a hash as the last argument.
- # For historical reasons, the 'media' attribute will always be present and defaults
- # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to
- # apply to all media types.
- #
- # stylesheet_link_tag "style" # =>
- # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" />
- #
- # stylesheet_link_tag "style.css" # =>
- # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" />
- #
- # stylesheet_link_tag "http://www.example.com/style.css" # =>
- # <link href="http://www.example.com/style.css" media="screen" rel="stylesheet" />
- #
- # stylesheet_link_tag "style", :media => "all" # =>
- # <link href="/stylesheets/style.css" media="all" rel="stylesheet" />
- #
- # stylesheet_link_tag "style", :media => "print" # =>
- # <link href="/stylesheets/style.css" media="print" rel="stylesheet" />
- #
- # stylesheet_link_tag "random.styles", "/css/stylish" # =>
- # <link href="/stylesheets/random.styles" media="screen" rel="stylesheet" />
- # <link href="/css/stylish.css" media="screen" rel="stylesheet" />
- #
- def stylesheet_link_tag(*sources)
- options = sources.extract_options!.stringify_keys
- sources.uniq.map { |source|
- tag_options = {
- "rel" => "stylesheet",
- "media" => "screen",
- "href" => path_to_stylesheet(source)
- }.merge(options)
- tag(:link, tag_options)
- }.join("\n").html_safe
- end
- end
- end
- end
-end
View
355 actionpack/lib/action_view/helpers/asset_url_helper.rb
@@ -0,0 +1,355 @@
+require 'zlib'
+
+module ActionView
+ # = Action View Asset URL Helpers
+ module Helpers #:nodoc:
+ # This module provides methods for generating asset paths and
+ # urls.
+ #
+ # image_path("rails.png")
+ # # => "/assets/rails.png"
+ #
+ # image_url("rails.png")
+ # # => "http://www.example.com/assets/rails.png"
+ #
+ # === Using asset hosts
+ #
+ # By default, Rails links to these assets on the current host in the public
+ # folder, but you can direct Rails to link to assets from a dedicated asset
+ # server by setting <tt>ActionController::Base.asset_host</tt> in the application
+ # configuration, typically in <tt>config/environments/production.rb</tt>.
+ # For example, you'd define <tt>assets.example.com</tt> to be your asset
+ # host this way, inside the <tt>configure</tt> block of your environment-specific
+ # configuration files or <tt>config/application.rb</tt>:
+ #
+ # config.action_controller.asset_host = "assets.example.com"
+ #
+ # Helpers take that into account:
+ #
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # Browsers typically open at most two simultaneous connections to a single
+ # host, which means your assets often have to wait for other assets to finish
+ # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the
+ # +asset_host+. For example, "assets%d.example.com". If that wildcard is
+ # present Rails distributes asset requests among the corresponding four hosts
+ # "assets0.example.com", ..., "assets3.example.com". With this trick browsers
+ # will open eight simultaneous connections rather than two.
+ #
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets0.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # To do this, you can either setup four actual hosts, or you can use wildcard
+ # DNS to CNAME the wildcard to a single asset host. You can read more about
+ # setting up your DNS CNAME records from your ISP.
+ #
+ # Note: This is purely a browser performance optimization and is not meant
+ # for server load balancing. See http://www.die.net/musings/page_load_time/
+ # for background.
+ #
+ # Alternatively, you can exert more control over the asset host by setting
+ # +asset_host+ to a proc like this:
+ #
+ # ActionController::Base.asset_host = Proc.new { |source|
+ # "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
+ # }
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets1.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # The example above generates "http://assets1.example.com" and
+ # "http://assets2.example.com". This option is useful for example if
+ # you need fewer/more than four hosts, custom host names, etc.
+ #
+ # As you see the proc takes a +source+ parameter. That's a string with the
+ # absolute path of the asset, for example "/assets/rails.png".
+ #
+ # ActionController::Base.asset_host = Proc.new { |source|
+ # if source.ends_with?('.css')
+ # "http://stylesheets.example.com"
+ # else
+ # "http://assets.example.com"
+ # end
+ # }
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://stylesheets.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # Alternatively you may ask for a second parameter +request+. That one is
+ # particularly useful for serving assets from an SSL-protected page. The
+ # example proc below disables asset hosting for HTTPS connections, while
+ # still sending assets for plain HTTP requests from asset hosts. If you don't
+ # have SSL certificates for each of the asset hosts this technique allows you
+ # to avoid warnings in the client about mixed media.
+ #
+ # config.action_controller.asset_host = Proc.new { |source, request|
+ # if request.ssl?
+ # "#{request.protocol}#{request.host_with_port}"
+ # else
+ # "#{request.protocol}assets.example.com"
+ # end
+ # }
+ #
+ # You can also implement a custom asset host object that responds to +call+
+ # and takes either one or two parameters just like the proc.
+ #
+ # config.action_controller.asset_host = AssetHostingWithMinimumSsl.new(
+ # "http://asset%d.example.com", "https://asset1.example.com"
+ # )
+ #
+ module AssetUrlHelper
+ URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}
+
+ # Computes the path to asset in public directory. If :type
+ # options is set, a file extension will be appended and scoped
+ # to the corresponding public directory.
+ #
+ # All other asset *_path helpers delegate through this method.
+ #
+ # asset_path "application.js" # => /application.js
+ # asset_path "application", type: :javascript # => /javascripts/application.js
+ # asset_path "application", type: :stylesheet # => /stylesheets/application.css
+ # asset_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
+ def asset_path(source, options = {})
+ source = source.to_s
+ return "" unless source.present?
+ return source if source =~ URI_REGEXP
+
+ tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, '')
+
+ if extname = compute_asset_extname(source, options)
+ source = "#{source}#{extname}"
+ end
+
+ if source[0] != ?/
+ source = compute_asset_path(source, options)
+ end
+
+ relative_url_root = (defined?(config.relative_url_root) && config.relative_url_root) ||
+ (respond_to?(:request) && request.try(:script_name))
+ if relative_url_root
+ source = "#{relative_url_root}#{source}" unless source.starts_with?("#{relative_url_root}/")
+ end
+
+ if host = compute_asset_host(source, options)
+ source = "#{host}#{source}"
+ end
+
+ "#{source}#{tail}"
+ end
+ alias_method :path_to_asset, :asset_path # aliased to avoid conflicts with a asset_path named route
+
+ # Computes the full URL to a asset in the public directory. This
+ # will use +asset_path+ internally, so most of their behaviors
+ # will be the same.
+ def asset_url(source, options = {})
+ path_to_asset(source, options.merge(:protocol => :request))
+ end
+ alias_method :url_to_asset, :asset_url # aliased to avoid conflicts with an asset_url named route
+
+ ASSET_EXTENSIONS = {
+ javascript: '.js',
+ stylesheet: '.css'
+ }
+
+ # Compute extname to append to asset path. Returns nil if
+ # nothing should be added.
+ def compute_asset_extname(source, options = {})
+ return if options[:extname] == false
+ extname = options[:extname] || ASSET_EXTENSIONS[options[:type]]
+ extname if extname && File.extname(source) != extname
+ end
+
+ # Maps asset types to public directory.
+ ASSET_PUBLIC_DIRECTORIES = {
+ audio: '/audios',
+ font: '/fonts',
+ image: '/images',
+ javascript: '/javascripts',
+ stylesheet: '/stylesheets',
+ video: '/videos'
+ }
+
+ # Computes asset path to public directory. Plugins and
+ # extensions can override this method to point to custom assets
+ # or generate digested paths or query strings.
+ def compute_asset_path(source, options = {})
+ dir = ASSET_PUBLIC_DIRECTORIES[options[:type]] || ""
+ File.join(dir, source)
+ end
+
+ # Pick an asset host for this source. Returns +nil+ if no host is set,
+ # the host if no wildcard is set, the host interpolated with the
+ # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4),
+ # or the value returned from invoking call on an object responding to call
+ # (proc or otherwise).
+ def compute_asset_host(source = "", options = {})
+ request = self.request if respond_to?(:request)
+ host = config.asset_host if defined? config.asset_host
+ host ||= request.base_url if request && options[:protocol] == :request
+ return unless host
+
+ if host.respond_to?(:call)
+ arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
+ args = [source]
+ args << request if request && (arity > 1 || arity < 0)
+ host = host.call(*args)
+ elsif host =~ /%d/
+ host = host % (Zlib.crc32(source) % 4)
+ end
+
+ if host =~ URI_REGEXP
+ host
+ else
+ protocol = options[:protocol] || config.default_asset_host_protocol || (request ? :request : :relative)
+ case protocol
+ when :relative
+ "//#{host}"
+ when :request
+ "#{request.protocol}#{host}"
+ else
+ "#{protocol}://#{host}"
+ end
+ end
+ end
+
+ # Computes the path to a javascript asset in the public javascripts directory.
+ # If the +source+ filename has no extension, .js will be appended (except for explicit URIs)
+ # Full paths from the document root will be passed through.