Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge commit 'mainstream/master'

Conflicts:

	actionpack/lib/action_controller/cookies.rb
	actionpack/lib/action_controller/streaming.rb
	actionpack/lib/action_controller/test_case.rb
	actionpack/lib/action_view/base.rb
	actionpack/lib/action_view/helpers/date_helper.rb
	actionpack/lib/action_view/helpers/debug_helper.rb
	actionpack/lib/action_view/helpers/form_options_helper.rb
	actionpack/lib/action_view/helpers/javascript_helper.rb
	activerecord/lib/active_record/associations.rb
	activerecord/lib/active_record/validations.rb
	activeresource/README
	activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
	activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb
	activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb
	railties/doc/guides/actionview/helpers.markdown
	railties/doc/guides/actionview/partials.markdown
	railties/doc/guides/activerecord/basics.markdown
  • Loading branch information...
commit de211914d84737c4314e862b459b9a23a0baa28f 2 parents 6246a8e + 10d9fe4
@lifo lifo authored
Showing with 8,845 additions and 2,929 deletions.
  1. +3 −3 actionmailer/lib/action_mailer/base.rb
  2. +13 −5 actionmailer/test/abstract_unit.rb
  3. +3 −3 actionmailer/test/mail_service_test.rb
  4. +16 −0 actionpack/CHANGELOG
  5. +3 −3 actionpack/lib/action_controller/assertions/response_assertions.rb
  6. +25 −3 actionpack/lib/action_controller/base.rb
  7. +1 −3 actionpack/lib/action_controller/caching/fragments.rb
  8. +1 −1  actionpack/lib/action_controller/cookies.rb
  9. +2 −10 actionpack/lib/action_controller/filters.rb
  10. +2 −6 actionpack/lib/action_controller/rack_process.rb
  11. +14 −27 actionpack/lib/action_controller/request.rb
  12. +16 −12 actionpack/lib/action_controller/rescue.rb
  13. +5 −4 actionpack/lib/action_controller/resources.rb
  14. +33 −5 actionpack/lib/action_controller/response.rb
  15. +15 −0 actionpack/lib/action_controller/routing/builder.rb
  16. +1 −1  actionpack/lib/action_controller/routing/optimisations.rb
  17. +1 −1  actionpack/lib/action_controller/streaming.rb
  18. +1 −1  actionpack/lib/action_controller/test_case.rb
  19. +5 −12 actionpack/lib/action_controller/test_process.rb
  20. +3 −3 actionpack/lib/action_controller/url_rewriter.rb
  21. +4 −0 actionpack/lib/action_view.rb
  22. +24 −16 actionpack/lib/action_view/base.rb
  23. +49 −20 actionpack/lib/action_view/helpers/active_record_helper.rb
  24. +40 −45 actionpack/lib/action_view/helpers/asset_tag_helper.rb
  25. +1 −2  actionpack/lib/action_view/helpers/cache_helper.rb
  26. +9 −8 actionpack/lib/action_view/helpers/capture_helper.rb
  27. +167 −169 actionpack/lib/action_view/helpers/date_helper.rb
  28. +6 −6 actionpack/lib/action_view/helpers/debug_helper.rb
  29. +92 −0 actionpack/lib/action_view/helpers/form_country_helper.rb
  30. +25 −13 actionpack/lib/action_view/helpers/form_helper.rb
  31. +4 −79 actionpack/lib/action_view/helpers/form_options_helper.rb
  32. +3 −3 actionpack/lib/action_view/helpers/javascript_helper.rb
  33. +150 −154 actionpack/lib/action_view/helpers/javascripts/prototype.js
  34. +73 −36 actionpack/lib/action_view/helpers/number_helper.rb
  35. +190 −188 actionpack/lib/action_view/helpers/prototype_helper.rb
  36. +12 −6 actionpack/lib/action_view/helpers/tag_helper.rb
  37. +147 −57 actionpack/lib/action_view/helpers/text_helper.rb
  38. +20 −0 actionpack/lib/action_view/helpers/translation_helper.rb
  39. +50 −43 actionpack/lib/action_view/helpers/url_helper.rb
  40. +32 −0 actionpack/lib/action_view/locale/en-US.rb
  41. +12 −26 actionpack/lib/action_view/partials.rb
  42. +32 −29 actionpack/lib/action_view/paths.rb
  43. +48 −37 actionpack/lib/action_view/renderable.rb
  44. +21 −4 actionpack/lib/action_view/renderable_partial.rb
  45. +20 −31 actionpack/lib/action_view/template.rb
  46. +8 −19 actionpack/lib/action_view/template_handler.rb
  47. +0 −1  actionpack/lib/action_view/template_handlers.rb
  48. +2 −8 actionpack/lib/action_view/template_handlers/builder.rb
  49. +0 −20 actionpack/lib/action_view/template_handlers/compilable.rb
  50. +4 −7 actionpack/lib/action_view/template_handlers/erb.rb
  51. +0 −11 actionpack/lib/action_view/template_handlers/rjs.rb
  52. +1 −1  actionpack/test/abstract_unit.rb
  53. +3 −3 actionpack/test/controller/action_pack_assertions_test.rb
  54. +20 −0 actionpack/test/controller/base_test.rb
  55. +59 −54 actionpack/test/controller/caching_test.rb
  56. +46 −4 actionpack/test/controller/cgi_test.rb
  57. +1 −1  actionpack/test/controller/cookie_test.rb
  58. +2 −10 actionpack/test/controller/layout_test.rb
  59. +77 −4 actionpack/test/controller/rack_test.rb
  60. +54 −55 actionpack/test/controller/redirect_test.rb
  61. +119 −68 actionpack/test/controller/render_test.rb
  62. +27 −73 actionpack/test/controller/request_test.rb
  63. +9 −0 actionpack/test/controller/rescue_test.rb
  64. +20 −0 actionpack/test/controller/resources_test.rb
  65. +19 −7 actionpack/test/controller/routing_test.rb
  66. +27 −28 actionpack/test/controller/url_rewriter_test.rb
  67. +2 −8 actionpack/test/controller/view_paths_test.rb
  68. +3 −0  actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb
  69. +6 −0 actionpack/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs
  70. +5 −0 actionpack/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder
  71. +2 −0  actionpack/test/fixtures/functional_caching/inline_fragment_cached.html.erb
  72. +2 −0  actionpack/test/fixtures/test/implicit_content_type.atom.builder
  73. +46 −0 actionpack/test/template/active_record_helper_i18n_test.rb
  74. +24 −24 actionpack/test/template/active_record_helper_test.rb
  75. +27 −26 actionpack/test/template/asset_tag_helper_test.rb
  76. +47 −0 actionpack/test/template/compiled_templates_test.rb
  77. +91 −0 actionpack/test/template/date_helper_i18n_test.rb
  78. +96 −48 actionpack/test/template/date_helper_test.rb
  79. +1,549 −0 actionpack/test/template/form_country_helper_test.rb
  80. +113 −3 actionpack/test/template/form_helper_test.rb
  81. +109 −763 actionpack/test/template/form_options_helper_test.rb
  82. +6 −0 actionpack/test/template/javascript_helper_test.rb
  83. +18 −0 actionpack/test/template/number_helper_i18n_test.rb
  84. +27 −1 actionpack/test/template/number_helper_test.rb
  85. +6 −2 actionpack/test/template/prototype_helper_test.rb
  86. +5 −25 actionpack/test/template/render_test.rb
  87. +42 −9 actionpack/test/template/text_helper_test.rb
  88. +28 −0 actionpack/test/template/translation_helper_test.rb
  89. +10 −1 actionpack/test/template/url_helper_test.rb
  90. +24 −0 activerecord/CHANGELOG
  91. +1 −1  activerecord/Rakefile
  92. +5 −0 activerecord/lib/active_record.rb
  93. +13 −4 activerecord/lib/active_record/association_preload.rb
  94. +25 −10 activerecord/lib/active_record/associations.rb
  95. +12 −3 activerecord/lib/active_record/associations/association_collection.rb
  96. +5 −1 activerecord/lib/active_record/base.rb
  97. +8 −6 activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
  98. +13 −0 activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
  99. +26 −7 activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
  100. +13 −1 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  101. +12 −0 activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
  102. +8 −7 activerecord/lib/active_record/fixtures.rb
  103. +25 −0 activerecord/lib/active_record/locale/en-US.rb
  104. +16 −0 activerecord/lib/active_record/migration.rb
  105. +9 −1 activerecord/lib/active_record/named_scope.rb
  106. +7 −5 activerecord/lib/active_record/observer.rb
  107. +13 −2 activerecord/lib/active_record/test_case.rb
  108. +3 −14 activerecord/lib/active_record/transactions.rb
  109. +105 −79 activerecord/lib/active_record/validations.rb
  110. +6 −0 activerecord/test/cases/adapter_test.rb
  111. +36 −0 activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb
  112. +49 −0 activerecord/test/cases/associations/has_many_associations_test.rb
  113. +108 −0 activerecord/test/cases/associations_test.rb
  114. +19 −2 activerecord/test/cases/base_test.rb
  115. +36 −0 activerecord/test/cases/column_definition_test.rb
  116. +32 −3 activerecord/test/cases/fixtures_test.rb
  117. +5 −5 activerecord/test/cases/helper.rb
  118. +7 −0 activerecord/test/cases/inheritance_test.rb
  119. +37 −1 activerecord/test/cases/lifecycle_test.rb
  120. +56 −1 activerecord/test/cases/migration_test.rb
  121. +25 −0 activerecord/test/cases/multiple_db_test.rb
  122. +22 −0 activerecord/test/cases/named_scope_test.rb
  123. +623 −0 activerecord/test/cases/validations_i18n_test.rb
  124. +12 −1 activerecord/test/cases/validations_test.rb
  125. +1 −1  activerecord/test/models/author.rb
  126. +7 −0 activerecord/test/models/company.rb
  127. +6 −0 activerecord/test/models/post.rb
  128. +1 −0  activerecord/test/schema/schema.rb
  129. +1 −1  activeresource/README
  130. +13 −9 activeresource/test/abstract_unit.rb
  131. +10 −0 activesupport/CHANGELOG
  132. +6 −0 activesupport/lib/active_support.rb
  133. +15 −21 activesupport/lib/active_support/cache.rb
  134. +15 −15 activesupport/lib/active_support/cache/mem_cache_store.rb
  135. +7 −4 activesupport/lib/active_support/core_ext/array/conversions.rb
  136. +45 −2 activesupport/lib/active_support/core_ext/array/grouping.rb
  137. +2 −1  activesupport/lib/active_support/core_ext/hash.rb
  138. +23 −0 activesupport/lib/active_support/core_ext/hash/deep_merge.rb
  139. +2 −2 activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
  140. +5 −0 activesupport/lib/active_support/core_ext/hash/slice.rb
  141. +17 −6 activesupport/lib/active_support/core_ext/module/introspection.rb
  142. +1 −0  activesupport/lib/active_support/core_ext/object.rb
  143. +13 −0 activesupport/lib/active_support/core_ext/object/metaclass.rb
  144. +154 −104 activesupport/lib/active_support/dependencies.rb
  145. +1 −1  activesupport/lib/active_support/json/encoders/date_time.rb
  146. +28 −0 activesupport/lib/active_support/locale/en-US.rb
  147. +47 −0 activesupport/lib/active_support/memoizable.rb
  148. +1 −9 activesupport/lib/active_support/option_merger.rb
  149. +1 −1  activesupport/lib/active_support/testing/performance.rb
  150. +3 −0  activesupport/lib/active_support/testing/setup_and_teardown.rb
  151. +1 −1  activesupport/lib/active_support/time_with_zone.rb
  152. +31 −0 activesupport/lib/active_support/typed_array.rb
  153. +9 −1 activesupport/lib/active_support/vendor.rb
  154. +20 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/MIT-LICENSE
  155. +18 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/README.textile
  156. +24 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/i18n.gemspec
  157. +182 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb
  158. +154 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/backend/simple.rb
  159. +45 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n/exceptions.rb
  160. +4 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/test/all.rb
  161. +100 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_exceptions_test.rb
  162. +141 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/test/i18n_test.rb
  163. +376 −0 activesupport/lib/active_support/vendor/i18n-0.0.1/test/simple_backend_test.rb
  164. +1 −1  activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb
  165. +1 −1  activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb
  166. +67 −0 activesupport/test/caching_test.rb
  167. +46 −4 activesupport/test/core_ext/array_ext_test.rb
  168. +31 −0 activesupport/test/core_ext/hash_ext_test.rb
  169. +8 −0 activesupport/test/core_ext/object_and_class_ext_test.rb
  170. +7 −2 activesupport/test/core_ext/time_ext_test.rb
  171. +6 −0 activesupport/test/core_ext/time_with_zone_test.rb
  172. +12 −0 activesupport/test/dependencies_test.rb
  173. +75 −0 activesupport/test/i18n_test.rb
  174. +178 −0 activesupport/test/memoizable_test.rb
  175. +27 −0 activesupport/test/option_merger_test.rb
  176. +51 −0 activesupport/test/typed_array_test.rb
  177. +0 −1  cleanlogs.sh
  178. +9 −0 railties/CHANGELOG
  179. +17 −0 railties/config.ru
  180. +10 −10 railties/doc/guides/actionview/helpers.markdown
  181. +7 −8 railties/doc/guides/actionview/partials.markdown
  182. +1 −1  railties/doc/guides/activerecord/basics.markdown
  183. +861 −0 railties/doc/guides/creating_plugins/basics.markdown
  184. +4 −4 railties/environments/boot.rb
  185. +0 −1  railties/environments/production.rb
  186. +1 −5 railties/helpers/performance_test_helper.rb
  187. +150 −154 railties/html/javascripts/prototype.js
  188. +33 −16 railties/lib/commands/plugin.rb
  189. +3 −3 railties/lib/commands/server.rb
  190. +73 −9 railties/lib/initializer.rb
  191. +5 −0 railties/lib/performance_test_help.rb
  192. +16 −1 railties/lib/rails_generator/commands.rb
  193. +1 −0  railties/lib/rails_generator/generators/applications/app/app_generator.rb
  194. +20 −14 railties/lib/tasks/databases.rake
  195. +2 −1  railties/test/generators/generator_test_helper.rb
  196. +20 −1 railties/test/initializer_test.rb
View
6 actionmailer/lib/action_mailer/base.rb
@@ -426,7 +426,8 @@ def register_template_extension(extension)
end
def template_root=(root)
- write_inheritable_attribute(:template_root, ActionView::PathSet.new(Array(root)))
+ root = ActionView::PathSet::Path.new(root) if root.is_a?(String)
+ write_inheritable_attribute(:template_root, root)
end
end
@@ -529,7 +530,7 @@ def initialize_defaults(method_name)
end
def render_message(method_name, body)
- render :file => method_name, :body => body, :use_full_path => true
+ render :file => method_name, :body => body
end
def render(opts)
@@ -537,7 +538,6 @@ def render(opts)
if opts[:file] && opts[:file] !~ /\//
opts[:file] = "#{mailer_name}/#{opts[:file]}"
end
- opts[:use_full_path] = true
initialize_template_class(body).render(opts)
end
View
18 actionmailer/test/abstract_unit.rb
@@ -30,12 +30,20 @@ def self.start(*args)
end
end
-# Wrap tests that use Mocha and skip if unavailable.
-def uses_mocha(test_name)
- gem 'mocha', ">=0.9.0"
+def uses_gem(gem_name, test_name, version = '> 0')
+ require 'rubygems'
+ gem gem_name.to_s, version
+ require gem_name.to_s
yield
-rescue Gem::LoadError
- $stderr.puts "Skipping #{test_name} tests (Mocha >= 0.5 is required). `gem install mocha` and try again."
+rescue LoadError
+ $stderr.puts "Skipping #{test_name} tests. `gem install #{gem_name}` and try again."
+end
+
+# Wrap tests that use Mocha and skip if unavailable.
+unless defined? uses_mocha
+ def uses_mocha(test_name, &block)
+ uses_gem('mocha', test_name, '>= 0.5.5', &block)
+ end
end
def set_delivery_method(delivery_method)
View
6 actionmailer/test/mail_service_test.rb
@@ -942,13 +942,13 @@ def test_return_path_with_deliver
class InheritableTemplateRootTest < Test::Unit::TestCase
def test_attr
expected = "#{File.dirname(__FILE__)}/fixtures/path.with.dots"
- assert_equal [expected], FunkyPathMailer.template_root.map(&:to_s)
+ assert_equal expected, FunkyPathMailer.template_root
sub = Class.new(FunkyPathMailer)
sub.template_root = 'test/path'
- assert_equal ['test/path'], sub.template_root.map(&:to_s)
- assert_equal [expected], FunkyPathMailer.template_root.map(&:to_s)
+ assert_equal 'test/path', sub.template_root
+ assert_equal expected, FunkyPathMailer.template_root
end
end
View
16 actionpack/CHANGELOG
@@ -1,5 +1,21 @@
*Edge*
+* AbstractRequest.relative_url_root is no longer automatically configured by a HTTP header. It can now be set in your configuration environment with config.action_controller.relative_url_root [Josh Peek]
+
+* Update Prototype to 1.6.0.2 #599 [Patrick Joyce]
+
+* Conditional GET utility methods. [Jeremy Kemper]
+ * etag!([:admin, post, current_user]) sets the ETag response header and returns head(:not_modified) if it matches the If-None-Match request header.
+ * last_modified!(post.updated_at) sets Last-Modified and returns head(:not_modified) if it's no later than If-Modified-Since.
+
+* All 2xx requests are considered successful [Josh Peek]
+
+* Fixed that AssetTagHelper#compute_public_path shouldn't cache the asset_host along with the source or per-request proc's won't run [DHH]
+
+* Removed config.action_view.cache_template_loading, use config.cache_classes instead [Josh Peek]
+
+* Get buffer for fragment cache from template's @output_buffer [Josh Peek]
+
* Set config.action_view.warn_cache_misses = true to receive a warning if you perform an action that results in an expensive disk operation that could be cached [Josh Peek]
* Refactor template preloading. New abstractions include Renderable mixins and a refactored Template class [Josh Peek]
View
6 actionpack/lib/action_controller/assertions/response_assertions.rb
@@ -87,13 +87,13 @@ def assert_redirected_to(options = {}, message=nil)
#
def assert_template(expected = nil, message=nil)
clean_backtrace do
- rendered = expected ? @response.rendered_file(!expected.include?('/')) : @response.rendered_file
+ rendered = @response.rendered_template
msg = build_message(message, "expecting <?> but rendering with <?>", expected, rendered)
assert_block(msg) do
if expected.nil?
- !@response.rendered_with_file?
+ @response.rendered_template.nil?
else
- rendered.match(expected)
+ rendered.to_s.match(expected)
end
end
end
View
28 actionpack/lib/action_controller/base.rb
@@ -354,6 +354,15 @@ class Base
class_inheritable_accessor :allow_forgery_protection
self.allow_forgery_protection = true
+ # If you are deploying to a subdirectory, you will need to set
+ # <tt>config.action_controller.relative_url_root</tt>
+ # This defaults to ENV['RAILS_RELATIVE_URL_ROOT']
+ cattr_writer :relative_url_root
+
+ def self.relative_url_root
+ @@relative_url_root || ENV['RAILS_RELATIVE_URL_ROOT']
+ end
+
# Holds the request object that's primarily used to get environment variables through access like
# <tt>request.env["REQUEST_URI"]</tt>.
attr_internal :request
@@ -519,6 +528,8 @@ def exempt_from_layout(*extensions)
public
# Extracts the action_name from the request parameters and performs that action.
def process(request, response, method = :perform_action, *arguments) #:nodoc:
+ response.request = request
+
initialize_template_class(response)
assign_shortcuts(request, response)
initialize_current_url
@@ -529,8 +540,6 @@ def process(request, response, method = :perform_action, *arguments) #:nodoc:
send(method, *arguments)
assign_default_content_type_and_charset
-
- response.request = request
response.prepare! unless component_request?
response
ensure
@@ -968,6 +977,17 @@ def head(*args)
render :nothing => true, :status => status
end
+ # Sets the Last-Modified response header. Returns 304 Not Modified if the
+ # If-Modified-Since request header is <= last modified.
+ def last_modified!(utc_time)
+ head(:not_modified) if response.last_modified!(utc_time)
+ end
+
+ # Sets the ETag response header. Returns 304 Not Modified if the
+ # If-None-Match request header matches.
+ def etag!(etag)
+ head(:not_modified) if response.etag!(etag)
+ end
# Clears the rendered results, allowing for another render to be performed.
def erase_render_results #:nodoc:
@@ -1155,7 +1175,7 @@ def initialize_current_url
def log_processing
if logger && logger.info?
- logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
+ logger.info "\n\nProcessing #{self.class.name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
logger.info " Session ID: #{@_session.session_id}" if @_session and @_session.respond_to?(:session_id)
logger.info " Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(params).inspect : params.inspect}"
end
@@ -1250,6 +1270,8 @@ def template_public?(template_name = default_template_name)
def template_exempt_from_layout?(template_name = default_template_name)
template_name = @template.pick_template(template_name).to_s if @template
@@exempt_from_layout.any? { |ext| template_name =~ ext }
+ rescue ActionView::MissingTemplate
+ false
end
def default_template_name(action_name = self.action_name)
View
4 actionpack/lib/action_controller/caching/fragments.rb
@@ -60,10 +60,8 @@ def fragment_cache_key(key)
ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views)
end
- def fragment_for(block, name = {}, options = nil) #:nodoc:
+ def fragment_for(buffer, name = {}, options = nil, &block) #:nodoc:
if perform_caching
- buffer = yield
-
if cache = read_fragment(name, options)
buffer.concat(cache)
else
View
2  actionpack/lib/action_controller/cookies.rb
@@ -23,7 +23,7 @@ module ActionController #:nodoc:
# cookies.delete :user_name
#
# Please note that if you specify a :domain when setting a cookie, you must also specify the domain when deleting the cookie:
- #
+ #
# cookies[:key] = {
# :value => 'a yummy cookie',
# :expires => 1.year.from_now,
View
12 actionpack/lib/action_controller/filters.rb
@@ -569,21 +569,13 @@ def filter_chain
# Returns all the before filters for this class and all its ancestors.
# This method returns the actual filter that was assigned in the controller to maintain existing functionality.
def before_filters #:nodoc:
- filters = []
- filter_chain.each do |filter|
- filters << filter.method if filter.before?
- end
- filters
+ filter_chain.select(&:before?).map(&:method)
end
# Returns all the after filters for this class and all its ancestors.
# This method returns the actual filter that was assigned in the controller to maintain existing functionality.
def after_filters #:nodoc:
- filters = []
- filter_chain.each do |filter|
- filters << filter.method if filter.after?
- end
- filters
+ filter_chain.select(&:after?).map(&:method)
end
end
View
8 actionpack/lib/action_controller/rack_process.rb
@@ -24,7 +24,7 @@ def initialize(env, session_options = DEFAULT_SESSION_OPTIONS)
super()
end
- %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
+ %w[ AUTH_TYPE GATEWAY_INTERFACE PATH_INFO
PATH_TRANSLATED QUERY_STRING REMOTE_HOST
REMOTE_IDENT REMOTE_USER SCRIPT_NAME
SERVER_NAME SERVER_PROTOCOL
@@ -98,10 +98,6 @@ def remote_addr
@env['REMOTE_ADDR']
end
- def request_method
- @env['REQUEST_METHOD'].downcase.to_sym
- end
-
def server_port
@env['SERVER_PORT'].to_i
end
@@ -250,7 +246,7 @@ def normalize_headers(options = "text/html")
headers['Content-Language'] = options.delete('language') if options['language']
headers['Expires'] = options.delete('expires') if options['expires']
- @status = options['Status'] || "200 OK"
+ @status = options.delete('Status') || "200 OK"
# Convert 'cookie' header to 'Set-Cookie' headers.
# Because Set-Cookie header can appear more the once in the response body,
View
41 actionpack/lib/action_controller/request.rb
@@ -3,13 +3,16 @@
require 'strscan'
module ActionController
- # HTTP methods which are accepted by default.
+ # HTTP methods which are accepted by default.
ACCEPTED_HTTP_METHODS = Set.new(%w( get head put post delete options ))
# CgiRequest and TestRequest provide concrete implementations.
class AbstractRequest
- cattr_accessor :relative_url_root
- remove_method :relative_url_root
+ def self.relative_url_root=(*args)
+ ActiveSupport::Deprecation.warn(
+ "ActionController::AbstractRequest.relative_url_root= has been renamed." +
+ "You can now set it with config.action_controller.relative_url_root=", caller)
+ end
# The hash of environment variables for this request,
# such as { 'RAILS_ENV' => 'production' }.
@@ -111,14 +114,14 @@ def format
end
end
end
-
-
+
+
# Sets the format by string extension, which can be used to force custom formats that are not controlled by the extension.
# Example:
#
# class ApplicationController < ActionController::Base
# before_filter :adjust_format_for_iphone
- #
+ #
# private
# def adjust_format_for_iphone
# request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
@@ -303,26 +306,10 @@ def path
path = (uri = request_uri) ? uri.split('?').first.to_s : ''
# Cut off the path to the installation directory if given
- path.sub!(%r/^#{relative_url_root}/, '')
- path || ''
- end
-
- # Returns the path minus the web server relative installation directory.
- # This can be set with the environment variable RAILS_RELATIVE_URL_ROOT.
- # It can be automatically extracted for Apache setups. If the server is not
- # Apache, this method returns an empty string.
- def relative_url_root
- @@relative_url_root ||= case
- when @env["RAILS_RELATIVE_URL_ROOT"]
- @env["RAILS_RELATIVE_URL_ROOT"]
- when server_software == 'apache'
- @env["SCRIPT_NAME"].to_s.sub(/\/dispatch\.(fcgi|rb|cgi)$/, '')
- else
- ''
- end
+ path.sub!(%r/^#{ActionController::Base.relative_url_root}/, '')
+ path || ''
end
-
# Read the request body. This is useful for web services that need to
# work with raw requests directly.
def raw_post
@@ -343,15 +330,15 @@ def path_parameters=(parameters) #:nodoc:
@symbolized_path_parameters = @parameters = nil
end
- # The same as <tt>path_parameters</tt> with explicitly symbolized keys
- def symbolized_path_parameters
+ # The same as <tt>path_parameters</tt> with explicitly symbolized keys
+ def symbolized_path_parameters
@symbolized_path_parameters ||= path_parameters.symbolize_keys
end
# Returns a hash with the parameters used to form the path of the request.
# Returned hash keys are strings. See <tt>symbolized_path_parameters</tt> for symbolized keys.
#
- # Example:
+ # Example:
#
# {'action' => 'my_action', 'controller' => 'my_controller'}
def path_parameters
View
28 actionpack/lib/action_controller/rescue.rb
@@ -112,19 +112,23 @@ def rescue_from(*klasses, &block)
protected
# Exception handler called when the performance of an action raises an exception.
def rescue_action(exception)
- log_error(exception) if logger
- erase_results if performed?
+ if handler_for_rescue(exception)
+ rescue_action_with_handler(exception)
+ else
+ log_error(exception) if logger
+ erase_results if performed?
- # Let the exception alter the response if it wants.
- # For example, MethodNotAllowed sets the Allow header.
- if exception.respond_to?(:handle_response!)
- exception.handle_response!(response)
- end
+ # Let the exception alter the response if it wants.
+ # For example, MethodNotAllowed sets the Allow header.
+ if exception.respond_to?(:handle_response!)
+ exception.handle_response!(response)
+ end
- if consider_all_requests_local || local_request?
- rescue_action_locally(exception)
- else
- rescue_action_in_public(exception)
+ if consider_all_requests_local || local_request?
+ rescue_action_locally(exception)
+ else
+ rescue_action_in_public(exception)
+ end
end
end
@@ -200,7 +204,7 @@ def rescue_action_with_handler(exception)
def perform_action_with_rescue #:nodoc:
perform_action_without_rescue
rescue Exception => exception
- rescue_action_with_handler(exception) || rescue_action(exception)
+ rescue_action(exception)
end
def rescues_path(template_name)
View
9 actionpack/lib/action_controller/resources.rb
@@ -307,13 +307,13 @@ def initialize(entity, options)
# map.resources :tags, :path_prefix => '/toys/:toy_id', :name_prefix => 'toy_'
#
# You may also use <tt>:name_prefix</tt> to override the generic named routes in a nested resource:
- #
+ #
# map.resources :articles do |article|
# article.resources :comments, :name_prefix => nil
- # end
- #
+ # end
+ #
# This will yield named resources like so:
- #
+ #
# comments_url(@article)
# comment_url(@article, @comment)
#
@@ -559,6 +559,7 @@ def add_conditions_for(conditions, method)
def action_options_for(action, resource, method = nil)
default_options = { :action => action.to_s }
require_id = !resource.kind_of?(SingletonResource)
+
case default_options[:action]
when "index", "new"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements)
when "create"; default_options.merge(add_conditions_for(resource.conditions, method || :post)).merge(resource.requirements)
View
38 actionpack/lib/action_controller/response.rb
@@ -83,20 +83,48 @@ def prepare!
set_content_length!
end
+ # Sets the Last-Modified response header. Returns whether it's older than
+ # the If-Modified-Since request header.
+ def last_modified!(utc_time)
+ headers['Last-Modified'] ||= utc_time.httpdate
+ if request && since = request.headers['HTTP_IF_MODIFIED_SINCE']
+ utc_time <= Time.rfc2822(since)
+ end
+ end
+
+ # Sets the ETag response header. Returns whether it matches the
+ # If-None-Match request header.
+ def etag!(tag)
+ headers['ETag'] ||= %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(tag))}")
+ if request && request.headers['HTTP_IF_NONE_MATCH'] == headers['ETag']
+ true
+ end
+ end
private
def handle_conditional_get!
- if body.is_a?(String) && (headers['Status'] ? headers['Status'][0..2] == '200' : true) && !body.empty?
- self.headers['ETag'] ||= %("#{Digest::MD5.hexdigest(body)}")
- self.headers['Cache-Control'] = 'private, max-age=0, must-revalidate' if headers['Cache-Control'] == DEFAULT_HEADERS['Cache-Control']
+ if nonempty_ok_response?
+ set_conditional_cache_control!
- if request.headers['HTTP_IF_NONE_MATCH'] == headers['ETag']
- self.headers['Status'] = '304 Not Modified'
+ if etag!(body)
+ headers['Status'] = '304 Not Modified'
self.body = ''
end
end
end
+ def nonempty_ok_response?
+ status = headers['Status']
+ ok = !status || status[0..2] == '200'
+ ok && body.is_a?(String) && !body.empty?
+ end
+
+ def set_conditional_cache_control!
+ if headers['Cache-Control'] == DEFAULT_HEADERS['Cache-Control']
+ headers['Cache-Control'] = 'private, max-age=0, must-revalidate'
+ end
+ end
+
def convert_content_type!
if content_type = headers.delete("Content-Type")
self.headers["type"] = content_type
View
15 actionpack/lib/action_controller/routing/builder.rb
@@ -76,6 +76,8 @@ def divide_route_options(segments, options)
defaults = (options.delete(:defaults) || {}).dup
conditions = (options.delete(:conditions) || {}).dup
+ validate_route_conditions(conditions)
+
path_keys = segments.collect { |segment| segment.key if segment.respond_to?(:key) }.compact
options.each do |key, value|
hash = (path_keys.include?(key) && ! value.is_a?(Regexp)) ? defaults : requirements
@@ -198,6 +200,19 @@ def build(path, options)
route
end
+
+ private
+ def validate_route_conditions(conditions)
+ if method = conditions[:method]
+ if method == :head
+ raise ArgumentError, "HTTP method HEAD is invalid in route conditions. Rails processes HEAD requests the same as GETs, returning just the response headers"
+ end
+
+ unless HTTP_METHODS.include?(method.to_sym)
+ raise ArgumentError, "Invalid HTTP method specified in route conditions: #{conditions.inspect}"
+ end
+ end
+ end
end
end
end
View
2  actionpack/lib/action_controller/routing/optimisations.rb
@@ -76,7 +76,7 @@ def generation_code
elements << '#{request.host_with_port}'
end
- elements << '#{request.relative_url_root if request.relative_url_root}'
+ elements << '#{ActionController::Base.relative_url_root if ActionController::Base.relative_url_root}'
# The last entry in <tt>route.segments</tt> appears to *always* be a
# 'divider segment' for '/' but we have assertions to ensure that
View
2  actionpack/lib/action_controller/streaming.rb
@@ -41,7 +41,7 @@ module Streaming
# only available with Lighttpd/Apache2 and specific modules installed and activated. Since this
# uses the web server to send the file, this may lower memory consumption on your server and
# it will not block your application for further requests.
- # See http://blog.lighttpd.net/articles/2006/07/02/x-sendfile and
+ # See http://blog.lighttpd.net/articles/2006/07/02/x-sendfile and
# http://tn123.ath.cx/mod_xsendfile/ for details. Defaults to +false+.
#
# The default Content-Type and Content-Disposition headers are
View
2  actionpack/lib/action_controller/test_case.rb
@@ -100,7 +100,7 @@ def rescue_action(e)
@@controller_class = nil
class << self
- # Sets the controller class name. Useful if the name can't be inferred from test class.
+ # Sets the controller class name. Useful if the name can't be inferred from test class.
# Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
def tests(controller_class)
self.controller_class = controller_class
View
17 actionpack/lib/action_controller/test_process.rb
@@ -171,7 +171,7 @@ def message
# Was the response successful?
def success?
- response_code == 200
+ (200..299).include?(response_code)
end
# Was the URL not found?
@@ -205,17 +205,10 @@ def redirect_url_match?( pattern )
p.match(redirect_url) != nil
end
- # Returns the template path of the file which was used to
- # render this response (or nil)
- def rendered_file(with_controller = false)
- if template.first_render
- template.first_render.to_s
- end
- end
-
- # Was this template rendered by a file?
- def rendered_with_file?
- !rendered_file.nil?
+ # Returns the template of the file which was used to
+ # render this response (or nil)
+ def rendered_template
+ template._first_render
end
# A shortcut to the flash. Returns an empty hash if no session flash exists.
View
6 actionpack/lib/action_controller/url_rewriter.rb
@@ -114,7 +114,7 @@ def self.included(base) #:nodoc:
# * <tt>:port</tt> - Optionally specify the port to connect to.
# * <tt>:anchor</tt> - An anchor name to be appended to the path.
# * <tt>:skip_relative_url_root</tt> - If true, the url is not constructed using the
- # +relative_url_root+ set in ActionController::AbstractRequest.relative_url_root.
+ # +relative_url_root+ set in ActionController::Base.relative_url_root.
# * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
#
# Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to
@@ -144,7 +144,7 @@ def url_for(options)
[:protocol, :host, :port, :skip_relative_url_root].each { |k| options.delete(k) }
end
trailing_slash = options.delete(:trailing_slash) if options.key?(:trailing_slash)
- url << ActionController::AbstractRequest.relative_url_root.to_s unless options[:skip_relative_url_root]
+ url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root]
anchor = "##{CGI.escape options.delete(:anchor).to_param.to_s}" if options[:anchor]
generated = Routing::Routes.generate(options, {})
url << (trailing_slash ? generated.sub(/\?|\z/) { "/" + $& } : generated)
@@ -185,7 +185,7 @@ def rewrite_url(options)
end
path = rewrite_path(options)
- rewritten_url << @request.relative_url_root.to_s unless options[:skip_relative_url_root]
+ rewritten_url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root]
rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path)
rewritten_url << "##{options[:anchor]}" if options[:anchor]
View
4 actionpack/lib/action_view.rb
@@ -34,6 +34,10 @@
require 'action_view/partials'
require 'action_view/template_error'
+I18n.backend.populate do
+ require 'action_view/locale/en-US.rb'
+end
+
ActionView::Base.class_eval do
include ActionView::Partials
View
40 actionpack/lib/action_view/base.rb
@@ -159,11 +159,11 @@ def initialize(paths, path, template_format = nil)
class Base
include ERB::Util
- attr_accessor :base_path, :assigns, :template_extension, :first_render
+ attr_accessor :base_path, :assigns, :template_extension
attr_accessor :controller
+ attr_accessor :_first_render, :_last_render
attr_writer :template_format
- attr_accessor :current_render_extension
attr_accessor :output_buffer
@@ -171,13 +171,16 @@ class << self
delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB'
end
- # Specify whether templates should be cached. Otherwise the file we be read everytime it is accessed.
- @@cache_template_loading = false
- cattr_accessor :cache_template_loading
+ def self.cache_template_loading=(*args)
+ ActiveSupport::Deprecation.warn(
+ "config.action_view.cache_template_loading option has been deprecated" +
+ "and has no effect. Please remove it from your config files.", caller)
+ end
def self.cache_template_extensions=(*args)
- ActiveSupport::Deprecation.warn("config.action_view.cache_template_extensions option has been deprecated and has no effect. " <<
- "Please remove it from your config files.", caller)
+ ActiveSupport::Deprecation.warn(
+ "config.action_view.cache_template_extensions option has been" +
+ "deprecated and has no effect. Please remove it from your config files.", caller)
end
# Specify whether RJS responses should be wrapped in a try/catch block
@@ -199,10 +202,6 @@ module CompiledTemplates #:nodoc:
end
include CompiledTemplates
- # Cache public asset paths
- cattr_reader :computed_public_paths
- @@computed_public_paths = {}
-
def self.helper_modules #:nodoc:
helpers = []
Dir.entries(File.expand_path("#{File.dirname(__FILE__)}/helpers")).sort.each do |file|
@@ -313,7 +312,7 @@ def pick_template(template_path)
template
elsif template = self.view_paths[template_file_name]
template
- elsif first_render && template = self.view_paths["#{template_file_name}.#{first_render.extension}"]
+ elsif _first_render && template = self.view_paths["#{template_file_name}.#{_first_render.format_and_extension}"]
template
elsif template_format == :js && template = self.view_paths["#{template_file_name}.html"]
@template_format = :html
@@ -324,8 +323,8 @@ def pick_template(template_path)
if self.class.warn_cache_misses && logger = ActionController::Base.logger
logger.debug "[PERFORMANCE] Rendering a template that was " +
"not found in view path. Templates outside the view path are " +
- "not cached and result in expensive disk operations. Move this " +
- "file into #{view_paths.join(':')} or add the folder to your " +
+ "not cached and result in expensive disk operations. Move this " +
+ "file into #{view_paths.join(':')} or add the folder to your " +
"view path list"
end
@@ -333,6 +332,9 @@ def pick_template(template_path)
end
end
+ extend ActiveSupport::Memoizable
+ memoize :pick_template
+
private
# Renders the template present at <tt>template_path</tt>. The hash in <tt>local_assigns</tt>
# is made available as local variables.
@@ -382,8 +384,14 @@ def assign_variables_from_controller
@assigns.each { |key, value| instance_variable_set("@#{key}", value) }
end
- def execute(template, local_assigns = {})
- send(template.method(local_assigns), local_assigns) do |*names|
+ def set_controller_content_type(content_type)
+ if controller.respond_to?(:response)
+ controller.response.content_type ||= content_type
+ end
+ end
+
+ def execute(method, local_assigns = {})
+ send(method, local_assigns) do |*names|
instance_variable_get "@content_for_#{names.first || 'layout'}"
end
end
View
69 actionpack/lib/action_view/helpers/active_record_helper.rb
@@ -25,7 +25,7 @@ def input(record_name, method, options = {})
# Returns an entire form with all needed input tags for a specified Active Record object. For example, if <tt>@post</tt>
# has attributes named +title+ of type +VARCHAR+ and +body+ of type +TEXT+ then
#
- # form("post")
+ # form("post")
#
# would yield a form like the following (modulus formatting):
#
@@ -90,23 +90,41 @@ def form(record_name, options = {})
end
# Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
- # This error message is wrapped in a <tt>DIV</tt> tag, which can be extended to include a +prepend_text+ and/or +append_text+
- # (to properly explain the error), and a +css_class+ to style it accordingly. +object+ should either be the name of an instance variable or
- # the actual object. As an example, let's say you have a model <tt>@post</tt> that has an error message on the +title+ attribute:
+ # This error message is wrapped in a <tt>DIV</tt> tag, which can be extended to include a <tt>:prepend_text</tt>
+ # and/or <tt>:append_text</tt> (to properly explain the error), and a <tt>:css_class</tt> to style it
+ # accordingly. +object+ should either be the name of an instance variable or the actual object. The method can be
+ # passed in either as a string or a symbol.
+ # As an example, let's say you have a model <tt>@post</tt> that has an error message on the +title+ attribute:
#
# <%= error_message_on "post", "title" %>
# # => <div class="formError">can't be empty</div>
#
- # <%= error_message_on @post, "title" %>
+ # <%= error_message_on @post, :title %>
# # => <div class="formError">can't be empty</div>
#
- # <%= error_message_on "post", "title", "Title simply ", " (or it won't work).", "inputError" %>
- # # => <div class="inputError">Title simply can't be empty (or it won't work).</div>
- def error_message_on(object, method, prepend_text = "", append_text = "", css_class = "formError")
+ # <%= error_message_on "post", "title",
+ # :prepend_text => "Title simply ",
+ # :append_text => " (or it won't work).",
+ # :css_class => "inputError" %>
+ def error_message_on(object, method, *args)
+ options = args.extract_options!
+ unless args.empty?
+ ActiveSupport::Deprecation.warn('error_message_on takes an option hash instead of separate ' +
+ 'prepend_text, append_text, and css_class arguments', caller)
+
+ options[:prepend_text] = args[0] || ''
+ options[:append_text] = args[1] || ''
+ options[:css_class] = args[2] || 'formError'
+ end
+ options.reverse_merge!(:prepend_text => '', :append_text => '', :css_class => 'formError')
+
if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
(errors = obj.errors.on(method))
- content_tag("div", "#{prepend_text}#{errors.is_a?(Array) ? errors.first : errors}#{append_text}", :class => css_class)
- else
+ content_tag("div",
+ "#{options[:prepend_text]}#{errors.is_a?(Array) ? errors.first : errors}#{options[:append_text]}",
+ :class => options[:css_class]
+ )
+ else
''
end
end
@@ -133,7 +151,7 @@ def error_message_on(object, method, prepend_text = "", append_text = "", css_cl
#
# To specify the display for one object, you simply provide its name as a parameter.
# For example, for the <tt>@user</tt> model:
- #
+ #
# error_messages_for 'user'
#
# To specify more than one object, you simply list them; optionally, you can add an extra <tt>:object_name</tt> parameter, which
@@ -151,12 +169,14 @@ def error_message_on(object, method, prepend_text = "", append_text = "", css_cl
# instance yourself and set it up. View the source of this method to see how easy it is.
def error_messages_for(*params)
options = params.extract_options!.symbolize_keys
+
if object = options.delete(:object)
objects = [object].flatten
else
objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact
end
- count = objects.inject(0) {|sum, object| sum + object.errors.count }
+
+ count = objects.inject(0) {|sum, object| sum + object.errors.count }
unless count.zero?
html = {}
[:id, :class].each do |key|
@@ -168,16 +188,25 @@ def error_messages_for(*params)
end
end
options[:object_name] ||= params.first
- options[:header_message] = "#{pluralize(count, 'error')} prohibited this #{options[:object_name].to_s.gsub('_', ' ')} from being saved" unless options.include?(:header_message)
- options[:message] ||= 'There were problems with the following fields:' unless options.include?(:message)
- error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join
- contents = ''
- contents << content_tag(options[:header_tag] || :h2, options[:header_message]) unless options[:header_message].blank?
- contents << content_tag(:p, options[:message]) unless options[:message].blank?
- contents << content_tag(:ul, error_messages)
+ I18n.with_options :locale => options[:locale], :scope => [:active_record, :error] do |locale|
+ header_message = if options.include?(:header_message)
+ options[:header_message]
+ else
+ object_name = options[:object_name].to_s.gsub('_', ' ')
+ object_name = I18n.t(object_name, :default => object_name)
+ locale.t :header_message, :count => count, :object_name => object_name
+ end
+ message = options.include?(:message) ? options[:message] : locale.t(:message)
+ error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join
- content_tag(:div, contents, html)
+ contents = ''
+ contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
+ contents << content_tag(:p, message) unless message.blank?
+ contents << content_tag(:ul, error_messages)
+
+ content_tag(:div, contents, html)
+ end
else
''
end
View
85 actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -5,12 +5,12 @@
module ActionView
module Helpers #:nodoc:
# This module provides methods for generating HTML that links views to assets such
- # as images, javascripts, stylesheets, and feeds. These methods do not verify
- # the assets exist before linking to them.
+ # as images, javascripts, stylesheets, and feeds. These methods do not verify
+ # the assets exist before linking to them.
#
# === 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 assets server by
+ # folder, but you can direct Rails to link to assets from a dedicated assets server by
# setting ActionController::Base.asset_host in your <tt>config/environment.rb</tt>. For example,
# let's say your asset host is <tt>assets.example.com</tt>.
#
@@ -22,16 +22,16 @@ module Helpers #:nodoc:
#
# This is useful since browsers typically open at most two connections to a single host,
# which means your assets often wait in single file for their turn to load. You can
- # alleviate this by using a <tt>%d</tt> wildcard in <tt>asset_host</tt> (for example, "assets%d.example.com")
+ # alleviate this by using a <tt>%d</tt> wildcard in <tt>asset_host</tt> (for example, "assets%d.example.com")
# to automatically distribute asset requests among four hosts (e.g., "assets0.example.com" through "assets3.example.com")
- # so browsers will open eight connections rather than two.
+ # so browsers will open eight connections rather than two.
#
# image_tag("rails.png")
# => <img src="http://assets0.example.com/images/rails.png" alt="Rails" />
# stylesheet_link_tag("application")
# => <link href="http://assets3.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
#
- # To do this, you can either setup 4 actual hosts, or you can use wildcard DNS to CNAME
+ # To do this, you can either setup 4 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.
#
@@ -86,7 +86,7 @@ module Helpers #:nodoc:
# 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
+ # 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
@@ -95,16 +95,17 @@ module Helpers #:nodoc:
# 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
+ # 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 drift out of sync, you'll see different timestamps at random and the cache won't
# work. Which means that 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 (and that the assets are not being
+ # something like Live HTTP Headers for Firefox to verify that the cache is indeed working (and that the assets are not being
# requested over and over).
module AssetTagHelper
ASSETS_DIR = defined?(Rails.public_path) ? Rails.public_path : "public"
JAVASCRIPTS_DIR = "#{ASSETS_DIR}/javascripts"
STYLESHEETS_DIR = "#{ASSETS_DIR}/stylesheets"
-
+ JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'].map(&:to_s).freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)
+
# 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
@@ -154,10 +155,6 @@ def javascript_path(source)
end
alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
- JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'] unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)
- @@javascript_expansions = { :defaults => JAVASCRIPT_DEFAULT_SOURCES.dup }
- @@stylesheet_expansions = {}
-
# Returns an html script tag for each of the +sources+ provided. You
# can pass in the filename (.js extension is optional) of javascript files
# that exist in your public/javascripts directory for inclusion into the
@@ -193,7 +190,7 @@ def javascript_path(source)
#
# * = The application.js file is only referenced if it exists
#
- # Though it's not really recommended practice, if you need to extend the default JavaScript set for any reason
+ # Though it's not really recommended practice, if you need to extend the default JavaScript set for any reason
# (e.g., you're going to be using a certain .js file in every action), then take a look at the register_javascript_include_default method.
#
# You can also include all javascripts in the javascripts directory using <tt>:all</tt> as the source:
@@ -218,7 +215,7 @@ def javascript_path(source)
# You can also cache multiple javascripts into one file, which requires less HTTP connections to download and can better be
# compressed by gzip (leading to faster transfers). Caching will only happen if ActionController::Base.perform_caching
# is set to <tt>true</tt> (which is the case by default for the Rails production environment, but not for the development
- # environment).
+ # environment).
#
# ==== Examples
# javascript_include_tag :all, :cache => true # when ActionController::Base.perform_caching is false =>
@@ -259,6 +256,8 @@ def javascript_include_tag(*sources)
end
end
+ @@javascript_expansions = { :defaults => JAVASCRIPT_DEFAULT_SOURCES.dup }
+
# Register one or more javascript files to be included when <tt>symbol</tt>
# is passed to <tt>javascript_include_tag</tt>. This method is typically intended
# to be called from plugin initialization to register javascript files
@@ -274,6 +273,8 @@ def self.register_javascript_expansion(expansions)
@@javascript_expansions.merge!(expansions)
end
+ @@stylesheet_expansions = {}
+
# Register one or more stylesheet files to be included when <tt>symbol</tt>
# is passed to <tt>stylesheet_link_tag</tt>. This method is typically intended
# to be called from plugin initialization to register stylesheet files
@@ -439,9 +440,9 @@ def image_path(source)
# <img alt="Icon" height="32" src="/icons/icon.gif" width="32" />
# image_tag("/icons/icon.gif", :class => "menu_icon") # =>
# <img alt="Icon" class="menu_icon" src="/icons/icon.gif" />
- # image_tag("mouse.png", :mouseover => "/images/mouse_over.png") # =>
+ # image_tag("mouse.png", :mouseover => "/images/mouse_over.png") # =>
# <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />
- # image_tag("mouse.png", :mouseover => image_path("mouse_over.png")) # =>
+ # image_tag("mouse.png", :mouseover => image_path("mouse_over.png")) # =>
# <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />
def image_tag(source, options = {})
options.symbolize_keys!
@@ -454,23 +455,15 @@ def image_tag(source, options = {})
end
if mouseover = options.delete(:mouseover)
- options[:onmouseover] = "this.src='#{image_path(mouseover)}'"
- options[:onmouseout] = "this.src='#{image_path(options[:src])}'"
+ options[:onmouseover] = "this.src='#{image_path(mouseover)}'"
+ options[:onmouseout] = "this.src='#{image_path(options[:src])}'"
end
tag("img", options)
end
private
- def file_exist?(path)
- @@file_exist_cache ||= {}
- if !(@@file_exist_cache[path] ||= File.exist?(path))
- @@file_exist_cache[path] = true
- false
- else
- true
- end
- end
+ COMPUTED_PUBLIC_PATHS = ActiveSupport::Cache::MemoryStore.new.silence!.threadsafe!
# Add the the extension +ext+ if not present. Return full URLs otherwise untouched.
# Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL
@@ -483,14 +476,14 @@ def compute_public_path(source, dir, ext = nil, include_host = true)
if has_request
[ @controller.request.protocol,
ActionController::Base.asset_host.to_s,
- @controller.request.relative_url_root,
+ ActionController::Base.relative_url_root,
dir, source, ext, include_host ].join
else
[ ActionController::Base.asset_host.to_s,
dir, source, ext, include_host ].join
end
- ActionView::Base.computed_public_paths[cache_key] ||=
+ source = COMPUTED_PUBLIC_PATHS.fetch(cache_key) do
begin
source += ".#{ext}" if ext && File.extname(source).blank? || File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}"))
@@ -499,25 +492,27 @@ def compute_public_path(source, dir, ext = nil, include_host = true)
else
source = "/#{dir}/#{source}" unless source[0] == ?/
if has_request
- unless source =~ %r{^#{@controller.request.relative_url_root}/}
- source = "#{@controller.request.relative_url_root}#{source}"
+ unless source =~ %r{^#{ActionController::Base.relative_url_root}/}
+ source = "#{ActionController::Base.relative_url_root}#{source}"
end
end
- source = rewrite_asset_path(source)
- if include_host
- host = compute_asset_host(source)
+ rewrite_asset_path(source)
+ end
+ end
+ end
- if has_request && !host.blank? && host !~ %r{^[-a-z]+://}
- host = "#{@controller.request.protocol}#{host}"
- end
+ if include_host && source !~ %r{^[-a-z]+://}
+ host = compute_asset_host(source)
- "#{host}#{source}"
- else
- source
- end
- end
+ if has_request && !host.blank? && host !~ %r{^[-a-z]+://}
+ host = "#{@controller.request.protocol}#{host}"
end
+
+ "#{host}#{source}"
+ else
+ source
+ end
end
# Pick an asset host for this source. Returns +nil+ if no host is set,
@@ -591,7 +586,7 @@ def expand_javascript_sources(sources, recursive = false)
expanded_sources = sources.collect do |source|
determine_source(source, @@javascript_expansions)
end.flatten
- expanded_sources << "application" if sources.include?(:defaults) && file_exist?(File.join(JAVASCRIPTS_DIR, "application.js"))
+ expanded_sources << "application" if sources.include?(:defaults) && File.exist?(File.join(JAVASCRIPTS_DIR, "application.js"))
expanded_sources
end
end
View
3  actionpack/lib/action_view/helpers/cache_helper.rb
@@ -32,8 +32,7 @@ module CacheHelper
# <i>Topics listed alphabetically</i>
# <% end %>
def cache(name = {}, options = nil, &block)
- handler = Template.handler_class_for_extension(current_render_extension.to_sym)
- handler.new(@controller).cache_fragment(block, name, options)
+ @controller.fragment_for(output_buffer, name, options, &block)
end
end
end
View
17 actionpack/lib/action_view/helpers/capture_helper.rb
@@ -122,14 +122,15 @@ def content_for(name, content = nil, &block)
nil
end
- private
- def with_output_buffer(buf = '')
- self.output_buffer, old_buffer = buf, output_buffer
- yield
- output_buffer
- ensure
- self.output_buffer = old_buffer
- end
+ # Use an alternate output buffer for the duration of the block.
+ # Defaults to a new empty string.
+ def with_output_buffer(buf = '') #:nodoc:
+ self.output_buffer, old_buffer = buf, output_buffer
+ yield
+ output_buffer
+ ensure
+ self.output_buffer = old_buffer
+ end
end
end
end
View
336 actionpack/lib/action_view/helpers/date_helper.rb
@@ -3,14 +3,15 @@
module ActionView
module Helpers
- # The Date Helper primarily creates select/option tags for different kinds of dates and date elements. All of the select-type methods
- # share a number of common options that are as follows:
+ # The Date Helper primarily creates select/option tags for different kinds of dates and date elements. All of the
+ # select-type methods share a number of common options that are as follows:
#
- # * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday" would give
- # birthday[month] instead of date[month] if passed to the select_month method.
+ # * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday"
+ # would give birthday[month] instead of date[month] if passed to the select_month method.
# * <tt>:include_blank</tt> - set to true if it should be possible to set an empty date.
- # * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true, the select_month
- # method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead of "date[month]".
+ # * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true,
+ # the select_month method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead of
+ # "date[month]".
module DateHelper
include ActionView::Helpers::TagHelper
DEFAULT_PREFIX = 'date' unless const_defined?('DEFAULT_PREFIX')
@@ -58,33 +59,38 @@ module DateHelper
# distance_of_time_in_words(to_time, from_time, true) # => over 6 years
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
#
- def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
+ def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
from_time = from_time.to_time if from_time.respond_to?(:to_time)
to_time = to_time.to_time if to_time.respond_to?(:to_time)
distance_in_minutes = (((to_time - from_time).abs)/60).round
distance_in_seconds = ((to_time - from_time).abs).round
- case distance_in_minutes
- when 0..1
- return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
- case distance_in_seconds
- when 0..4 then 'less than 5 seconds'
- when 5..9 then 'less than 10 seconds'
- when 10..19 then 'less than 20 seconds'
- when 20..39 then 'half a minute'
- when 40..59 then 'less than a minute'
- else '1 minute'
- end
+ I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
+ case distance_in_minutes
+ when 0..1
+ return distance_in_minutes == 0 ?
+ locale.t(:less_than_x_minutes, :count => 1) :
+ locale.t(:x_minutes, :count => distance_in_minutes) unless include_seconds
+
+ case distance_in_seconds
+ when 0..4 then locale.t :less_than_x_seconds, :count => 5
+ when 5..9 then locale.t :less_than_x_seconds, :count => 10
+ when 10..19 then locale.t :less_than_x_seconds, :count => 20
+ when 20..39 then locale.t :half_a_minute
+ when 40..59 then locale.t :less_than_x_minutes, :count => 1
+ else locale.t :x_minutes, :count => 1
+ end
- when 2..44 then "#{distance_in_minutes} minutes"
- when 45..89 then 'about 1 hour'
- when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
- when 1440..2879 then '1 day'
- when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
- when 43200..86399 then 'about 1 month'
- when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
- when 525600..1051199 then 'about 1 year'
- else "over #{(distance_in_minutes / 525600).round} years"
+ when 2..44 then locale.t :x_minutes, :count => distance_in_minutes
+ when 45..89 then locale.t :about_x_hours, :count => 1
+ when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round
+ when 1440..2879 then locale.t :x_days, :count => 1
+ when 2880..43199 then locale.t :x_days, :count => (distance_in_minutes / 1440).round
+ when 43200..86399 then locale.t :about_x_months, :count => 1
+ when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes / 43200).round
+ when 525600..1051199 then locale.t :about_x_years, :count => 1
+ else locale.t :over_x_years, :count => (distance_in_minutes / 525600).round
+ end
end
end
@@ -102,15 +108,18 @@ def time_ago_in_words(from_time, include_seconds = false)
alias_method :distance_of_time_in_words_to_now, :time_ago_in_words
- # Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by
- # +method+) on an object assigned to the template (identified by +object+). It's possible to tailor the selects through the +options+ hash,
- # which accepts all the keys that each of the individual select builders do (like <tt>:use_month_numbers</tt> for select_month) as well as a range of
- # discard options. The discard options are <tt>:discard_year</tt>, <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set to true, they'll
- # drop the respective select. Discarding the month select will also automatically discard the day select. It's also possible to explicitly
- # set the order of the tags using the <tt>:order</tt> option with an array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in
- # the desired order. Symbols may be omitted and the respective select is not included.
+ # Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based
+ # attribute (identified by +method+) on an object assigned to the template (identified by +object+). It's
+ # possible to tailor the selects through the +options+ hash, which accepts all the keys that each of the
+ # individual select builders do (like <tt>:use_month_numbers</tt> for select_month) as well as a range of discard
+ # options. The discard options are <tt>:discard_year</tt>, <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set
+ # to true, they'll drop the respective select. Discarding the month select will also automatically discard the
+ # day select. It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with an
+ # array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. Symbols may be omitted
+ # and the respective select is not included.
#
- # Pass the <tt>:default</tt> option to set the default date. Use a Time object or a Hash of <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt>, and <tt>:second</tt>.
+ # Pass the <tt>:default</tt> option to set the default date. Use a Time object or a Hash of <tt>:year</tt>,
+ # <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt>, and <tt>:second</tt>.
#
# Passing <tt>:disabled => true</tt> as part of the +options+ will make elements inaccessible for change.
#
@@ -128,7 +137,7 @@ def time_ago_in_words(from_time, include_seconds = false)
#
# # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute,
# # with the year in the year drop down box starting at 1995, numbers used for months instead of words,
- # # and without a day select box.
+ # # and without a day select box.
# date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true,
# :discard_day => true, :include_blank => true)
#
@@ -150,8 +159,8 @@ def time_ago_in_words(from_time, include_seconds = false)
#
# The selects are prepared for multi-parameter assignment to an Active Record object.
#
- # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month
- # choices are valid.
+ # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
+ # all month choices are valid.
def date_select(object_name, method, options = {}, html_options = {})
InstanceTag.new(object_name, method, self, options.delete(:object)).to_date_select_tag(options, html_options)
end
@@ -175,12 +184,12 @@ def date_select(object_name, method, options = {}, html_options = {})
# # Creates a time select tag that, when POSTed, will be stored in the mail variable in the sent_at attribute
# time_select("mail", "sent_at")
#
- # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the post variables in
- # # the sunrise attribute.
+ # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the post variables in
+ # # the sunrise attribute.
# time_select("post", "start_time", :include_seconds => true)
#
- # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the entry variables in
- # # the submission_time attribute.
+ # # Creates a time select tag with a seconds field that, when POSTed, will be stored in the entry variables in
+ # # the submission_time attribute.
# time_select("entry", "submission_time", :include_seconds => true)
#
# # You can set the :minute_step to 15 which will give you: 00, 15, 30 and 45.
@@ -188,14 +197,15 @@ def date_select(object_name, method, options = {}, html_options = {})
#
# The selects are prepared for multi-parameter assignment to an Active Record object.
#
- # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month
- # choices are valid.
+ # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
+ # all month choices are valid.
def time_select(object_name, method, options = {}, html_options = {})
InstanceTag.new(object_name, method, self, options.delete(:object)).to_time_select_tag(options, html_options)
end
- # Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based
- # attribute (identified by +method+) on an object assigned to the template (identified by +object+). Examples:
+ # Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a
+ # specified datetime-based attribute (identified by +method+) on an object assigned to the template (identified
+ # by +object+). Examples:
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
@@ -203,16 +213,16 @@ def time_select(object_name, method, options = {}, html_options = {})
# # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on attribute
# datetime_select("post", "written_on")
#
- # # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the
+ # # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the
# # post variable in the written_on attribute.
# datetime_select("post", "written_on", :start_year => 1995)
#
- # # Generates a datetime select with a default value of 3 days from the current time that, when POSTed, will be stored in the
- # # trip variable in the departing attribute.
+ # # Generates a datetime select with a default value of 3 days from the current time that, when POSTed, will
+ # # be stored in the trip variable in the departing attribute.
# datetime_select("trip", "departing", :default => 3.days.from_now)
#
- # # Generates a datetime select that discards the type that, when POSTed, will be stored in the post variable as the written_on
- # # attribute.
+ # # Generates a datetime select that discards the type that, when POSTed, will be stored in the post variable
+ # # as the written_on attribute.
# datetime_select("post", "written_on", :discard_type => true)
#
# The selects are prepared for multi-parameter assignment to an Active Record object.
@@ -222,9 +232,10 @@ def datetime_select(object_name, method, options = {}, html_options = {})
# Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
# It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
- # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it
- # will be appended onto the <tt>:order</tt> passed in. You can also add <tt>:date_separator</tt> and <tt>:time_separator</tt>
- # keys to the +options+ to control visual display of the elements.
+ # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol,
+ # it will be appended onto the <tt>:order</tt> passed in. You can also add <tt>:date_separator</tt>,
+ # <tt>:datetime_separator</tt> and <tt>:time_separator</tt> keys to the +options+ to control visual display of
+ # the elements.
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
@@ -245,7 +256,12 @@ def datetime_select(object_name, method, options = {}, html_options = {})
# # with a '/' between each date field.
# select_datetime(my_date_time, :date_separator => '/')
#
- # # Generates a datetime select that discards the type of the field and defaults to the datetime in
+ # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
+ # # with a date fields separated by '/', time fields separated by '' and the date and time fields
+ # # separated by a comma (',').
+ # select_datetime(my_date_time, :date_separator => '/', :time_separator => '', :datetime_separator => ',')
+ #
+ # # Generates a datetime select that discards the type of the field and defaults to the datetime in
# # my_date_time (four days after today)
# select_datetime(my_date_time, :discard_type => true)
#
@@ -256,7 +272,7 @@ def datetime_select(object_name, method, options = {}, html_options = {})
def select_datetime(datetime = Time.current, options = {}, html_options = {})
separator = options[:datetime_separator] || ''
select_date(datetime, options, html_options) + separator + select_time(datetime, options, html_options)
- end
+ end
# Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
# It's possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
@@ -278,27 +294,29 @@ def select_datetime(datetime = Time.current, options = {}, html_options = {})
# # with the fields ordered year, month, day rather than month, day, year.
# select_date(my_date, :order => [:year, :month, :day])
#
- # # Generates a date select that discards the type of the field and defaults to the date in
+ # # Generates a date select that discards the type of the field and defaults to the date in
# # my_date (six days after today)
# select_date(my_date, :discard_type => true)
#
+ # # Generates a date select that defaults to the date in my_date,
+ # # which has fields separated by '/'
+ # select_date(my_date, :date_separator => '/')
+ #
# # Generates a date select that defaults to the datetime in my_date (six days after today)
# # prefixed with 'payday' rather than 'date'
# select_date(my_date, :prefix => 'payday')
#
def select_date(date = Date.current, options = {}, html_options = {})
- options[:order] ||= []
+ options.reverse_merge!(:order => [], :date_separator => '')
[:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) }
- select_date = ''
- options[:order].each do |o|
- select_date << self.send("select_#{o}", date, options, html_options)
- end
- select_date
+ options[:order].inject([]) { |s, o|
+ s << self.send("select_#{o}", date, options, html_options)
+ }.join(options[:date_separator])
end
# Returns a set of html select-tags (one for hour and minute)
- # You can set <tt>:time_separator</tt> key to format the output, and
+ # You can set <tt>:time_separator</tt> key to format the output, and
# the <tt>:include_seconds</tt> option to include an input for seconds.
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
@@ -313,7 +331,7 @@ def select_date(date = Date.current, options = {}, html_options = {})
# select_time()
#
# # Generates a time select that defaults to the time in my_time,
- # # which has fields separated by ':'
+ # # which has fields separated by ':'
# select_time(my_time, :time_separator => ':')
#
# # Generates a time select that defaults to the time in my_time,
@@ -326,7 +344,8 @@ def select_date(date = Date.current, options = {}, html_options = {})
#
def select_time(datetime = Time.current, options = {}, html_options = {})
separator = options[:time_separator] || ''
- select_hour(datetime, options, html_options) + separator + select_minute(datetime, options, html_options) + (options[:include_seconds] ? separator + select_second(datetime, options, html_options) : '')
+ select_hour(datetime, options, html_options) + separator + select_minute(datetime, options, html_options) +
+ (options[:include_seconds] ? separator + select_second(datetime, options, html_options) : '')
end
# Returns a select tag with options for each of the seconds 0 through 59 with the current second selected.
@@ -341,26 +360,16 @@ def select_time(datetime = Time.current, options = {}, html_options = {})
#
# # Generates a select field for seconds that defaults to the number given
# select_second(33)
- #
+ #
# # Generates a select field for seconds that defaults to the seconds for the time in my_time
# # that is named 'interval' rather than 'second'
# select_second(my_time, :field_name => 'interval')
#
def select_second(datetime, options = {}, html_options = {})
val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) : ''
- if options[:use_hidden]
- options[:include_seconds] ? hidden_html(options[:field_name] || 'second', val, options) : ''
- else
- second_options = []
- 0.upto(59) do |second|
- second_options << ((val == second) ?
- content_tag(:option, leading_zero_on_single_digits(second), :value => leading_zero_on_single_digits(second), :selected => "selected") :
- content_tag(:option, leading_zero_on_single_digits(second), :value => leading_zero_on_single_digits(second))
- )
- second_options << "\n"
- end
- select_html(options[:field_name] || 'second', second_options.join, options, html_options)
- end
+ options[:use_hidden] ?
+ (options[:include_seconds] ? _date_hidden_html(options[:field_name] || 'second', val, options) : '') :
+ _date_select_html(options[:field_name] || 'second', _date_build_options(val), options, html_options)
end
# Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected.
@@ -376,26 +385,17 @@ def select_second(datetime, options = {}, html_options = {})
#
# # Generates a select field for minutes that defaults to the number given
# select_minute(14)
- #
+ #
# # Generates a select field for minutes that defaults to the minutes for the time in my_time
# # that is named 'stride' rather than 'second'
# select_minute(my_time, :field_name => 'stride')
#
def select_minute(datetime, options = {}, html_options = {})
val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.min) : ''
- if options[:use_hidden]
- hidden_html(options[:field_name] || 'minute', val, options)
- else
- minute_options = []
- 0.step(59, options[:minute_step] || 1) do |minute|
- minute_options << ((val == minute) ?
- content_tag(:option, leading_zero_on_single_digits(minute), :value => leading_zero_on_single_digits(minute), :selected => "selected") :
- content_tag(:option, leading_zero_on_single_digits(minute), :value => leading_zero_on_single_digits(minute))
- )
- minute_options << "\n"
- end
- select_html(options[:field_name] || 'minute', minute_options.join, options, html_options)
- end
+ options[:use_hidden] ?
+ _date_hidden_html(options[:field_name] || 'minute', val, options) :
+ _date_select_html(options[:field_name] || 'minute',
+ _date_build_options(val, :step => options[:minute_step]), options, html_options)
end
# Returns a select tag with options for each of the hours 0 through 23 with the current hour selected.
@@ -410,26 +410,15 @@ def select_minute(datetime, options = {}, html_options = {})
#
# # Generates a select field for minutes that defaults to the number given
# select_minute(14)
- #
+ #
# # Generates a select field for minutes that defaults to the minutes for the time in my_time
# # that is named 'stride' rather than 'second'
# select_minute(my_time, :field_name => 'stride')
#
def select_hour(datetime, options = {}, html_options = {})
val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) : ''
- if options[:use_hidden]
- hidden_html(options[:field_name] || 'hour', val, options)
- else
- hour_options = []
- 0.upto(23) do |hour|
- hour_options << ((val == hour) ?
- content_tag(:option, leading_zero_on_single_digits(hour), :value => leading_zero_on_single_digits(hour), :selected => "selected") :
- content_tag(:option, leading_zero_on_single_digits(hour), :value => leading_zero_on_single_digits(hour))
- )
- hour_options << "\n"
- end
- select_html(options[:field_name] || 'hour', hour_options.join, options, html_options)
- end
+ options[:use_hidden] ? _date_hidden_html(options[:field_name] || 'hour', val, options) :
+ _date_select_html(options[:field_name] || 'hour', _date_build_options(val, :end => 23), options, html_options)
end
# Returns a select tag with options for each of the days 1 through 31 with the current day selected.
@@ -444,36 +433,27 @@ def select_hour(datetime, options = {}, html_options = {})
#
# # Generates a select field for days that defaults to the number given
# select_day(5)
- #
+ #
# # Generates a select field for days that defaults to the day for the date in my_date
# # that is named 'due' rather than 'day'
# select_day(my_time, :field_name => 'due')
#
def select_day(date, options = {}, html_options = {})
val = date ? (date.kind_of?(Fixnum) ? date : date.day) : ''
- if options[:use_hidden]
- hidden_html(options[:field_name] || 'day', val, options)
- else
- day_options = []
- 1.upto(31) do |day|
- day_options << ((val == day) ?
- content_tag(:option, day, :value => day, :selected => "selected") :
- content_tag(:option, day, :value => day)
- )
- day_options << "\n"
- end
- select_html(options[:field_name] || 'day', day_options.join, options, html_options)
- end
+ options[:use_hidden] ? _date_hidden_html(options[:field_name] || 'day', val, options) :
+ _date_select_html(options[:field_name] || 'day',
+ _date_build_options(val, :start => 1, :end => 31, :leading_zeros => false),
+ options, html_options)
end
- # Returns a select tag with options for each of the months January through December with the current month selected.
- # The month names are presented as keys (what's shown to the user) and the month numbers (1-12) are used as values
- # (what's submitted to the server). It's also possible to use month numbers for the presentation instead of names --
- # set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names,
- # set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer to show month names as abbreviations,
- # set the <tt>:use_short_month</tt> key in +options+ to true. If you want to use your own month names, set the
- # <tt>:use_month_names</tt> key in +options+ to an array of 12 month names. Override the field name using the
- # <tt>:field_name</tt> option, 'month' by default.
+ # Returns a select tag with options for each of the months January through December with the current month
+ # selected. The month names are presented as keys (what's shown to the user) and the month numbers (1-12) are
+ # used as values (what's submitted to the server). It's also possible to use month numbers for the presentation
+ # instead of names -- set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you
+ # want both numbers and names, set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer
+ # to show month names as abbreviations, set the <tt>:use_short_month</tt> key in +options+ to true. If you want
+ # to use your own month names, set the <tt>:use_month_names</tt> key in +options+ to an array of 12 month names.
+ # Override the field name using the <tt>:field_name</tt> option, 'month' by default.
#
# ==== Examples
# # Generates a select field for months that defaults to the current month that
@@ -485,7 +465,7 @@ def select_day(date, options = {}, html_options = {})
# select_month(Date.today, :field_name => 'start')
#
# # Generates a select field for months that defaults to the current month that
- # # will use keys like "1", "3".
+ # # will use keys like "1", "3".
# select_month(Date.today, :use_month_numbers => true)
#
# # Generates a select field for months that defaults to the current month that
@@ -501,13 +481,19 @@ def select_day(date, options = {}, html_options = {})
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
#
def select_month(date, options = {}, html_options = {})
+ locale = options[:locale]
+
val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
if options[:use_hidden]
- hidden_html(options[:field_name] || 'month', val, options)
+ _date_hidden_html(options[:field_name] || 'month', val, options)
else
month_options = []
- month_names = options[:use_month_names] || (options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES)
+ month_names = options[:use_month_names] || begin
+ key = options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names'
+ I18n.translate key, :locale => locale
+ end
month_names.unshift(nil) if month_names.size < 13
+
1.upto(12) do |month_number|
month_name = if options[:use_month_numbers]
month_number
@@ -523,14 +509,15 @@ def select_month(date, options = {}, html_options = {})
)
month_options << "\n"
end
- select_html(options[:field_name] || 'month', month_options.join, options, html_options)
+ _date_select_html(options[:field_name] || 'month', month_options.join, options, html_options)
end
end
- # Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius
- # can be changed using the <tt>:start_year</tt> and <tt>:end_year</tt> keys in the +options+. Both ascending and descending year
- # lists are supported by making <tt>:start_year</tt> less than or greater than <tt>:end_year</tt>. The <tt>date</tt> can also be
- # substituted for a year given as a number. Override the field name using the <tt>:field_name</tt> option, 'year' by default.
+ # Returns a select tag with options for each of the five years on each side of the current, which is selected.
+ # The five year radius can be changed using the <tt>:start_year</tt> and <tt>:end_year</tt> keys in the
+ # +options+. Both ascending and descending year lists are supported by making <tt>:start_year</tt> less than or
+ # greater than <tt>:end_year</tt>. The <tt>date</tt> can also be substituted for a year given as a number.
+ # Override the field name using the <tt>:field_name</tt> option, 'year' by default.
#
# ==== Examples
# # Generates a select field for years that defaults to the current year that
@@ -551,38 +538,48 @@ def select_month(date, options = {}, html_options = {})
#
def select_year(date, options = {}, html_options = {})
if !date || date == 0
- value = ''
+ val = ''
middle_year = Date.today.year
elsif date.kind_of?(Fixnum)
- value = middle_year = date
+ val = middle_year = date
else
- value = middle_year = date.year
+ val = middle_year = date.year
end
if options[:use_hidden]
- hidden_html(options[:field_name] || 'year', value, options)
+ _date_hidden_html(options[:field_name] || 'year', val, options)
else
- year_options = ''
- start_year = options[:start_year] || middle_year - 5
- end_year = options[:end_year] || middle_year + 5
- step_val = start_year < end_year ? 1 : -1
-
- start_year.step(end_year, step_val) do |year|
- if value == year
- year_options << content_tag(:option, year, :value => year, :selected => "selected")
- else
- year_options << content_tag(:option, year, :value => year)
- end
- year_options << "\n"
- end
- select_html(options[:field_name] || 'year', year_options, options, html_options)
+ options[:start_year] ||= middle_year - 5
+ options[:end_year] ||= middle_year + 5
+ step = options[:start_year] < options[:end_year] ? 1 : -1
+
+ _date_select_html(options[:field_name] || 'year',
+ _date_build_options(val,
+ :start => options[:start_year],
+ :end => options[:end_year],
+ :step => step,
+ :leading_zeros => false
+ ), options, html_options)
end
end
private
+ def _date_build_options(selected, options={})
+ options.reverse_merge!(:start => 0, :end => 59, :step => 1, :leading_zeros => true)
+
+ select_options = []
+ (options[:start] || 0).step((options[:end] || 59), options[:step] || 1) do |i|
+ value = options[:leading_zeros] ? sprintf("%02d", i) : i
+ tag_options = { :value => value }
+ tag_options[:selected] = "selected" if selected == i
+
+ select_options << content_tag(:option, value, tag_options)
+ end
+ select_options.join("\n") + "\n"
+ end
- def select_html(type, html_options, options, select_tag_options = {})
- name_and_id_from_options(options, type)
+ def _date_select_html(type, html_options, options, select_tag_options = {})
+ _date_name_and_id_from_options(options, type)
select_options = {:id => options[:id], :name => options[:name]}
select_options.merge!(:disabled => 'disabled') if options[:disabled]
select_options.merge!(select_tag_options) unless select_tag_options.empty?
@@ -592,19 +589,15 @@ def select_html(type, html_options, options, select_tag_options = {})
content_tag(:select, select_html, select_options) + "\n"
end
- def hidden_html(type, value, options)
- name_and_id_from_options(options, type)
+ def _date_hidden_html(type, value, options)
+ _date_name_and_id_from_options(options, type)
hidden_html = tag(:input, :type => "hidden", :id => options[:id], :name => options[:name], :value => value) + "\n"
end
- def name_and_id_from_options(options, type)
+ def _date_name_and_id_from_options(options, type)
options[:name] = (options[:prefix] || DEFAULT_PREFIX) + (options[:discard_type] ? '' : "[#{type}]")
options[:id] = options[:name].gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
end
-
- def leading_zero_on_single_digits(number)
- number > 9 ? number : "0#{number}"
- end
end
class InstanceTag #:nodoc:
@@ -624,6 +617,8 @@ def to_datetime_select_tag(options = {}, html_options = {})
private
def date_or_time_select(options, html_options = {})
+ locale = options[:locale]
+
defaults = { :discard_type => true }
options = defaults.merge(options)
datetime = value(object)
@@ -631,7 +626,7 @@ def date_or_time_select(options, html_options = {})
position = { :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6 }
- order = (options[:order] ||= [:year, :month, :day])
+ order = options[:order] ||= I18n.translate(:'date.order', :locale => locale)
# Discard explicit and implicit by not being included in the :order
discard = {}
@@ -660,7 +655,11 @@ def date_or_time_select(options, html_options = {})
# This ensures AR can reconstruct valid dates using ParseDate
next if discard[param] && (date_or_time_select.empty? || options[:ignore_date])
- date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param])), html_options))
+ date_or_time_select.insert(0,
+ self.send("select_#{param}",
+ datetime,
+ options_with_prefix(position[param], options.merge(:use_hidden => discard[param])),
+ html_options))
date_or_time_select.insert(0,
case param
when :hour then (discard[:year] && discard[:day] ? "" : " &mdash; ")
@@ -668,7 +667,6 @@ def date_or_time_select(options, html_options = {})
when :second then options[:include_seconds] ? " : " : ""
else ""
end)
-
end
date_or_time_select
@@ -696,7 +694,7 @@ def default_time_from_options(default)
default[:sec] ||= default[:second]
time = Time.current
-
+
[:year, :month, :day, :hour, :min, :sec].each do |key|
default[key] ||= time.send(key)
end