Skip to content
Browse files

Merge branch 'master' of github.com:rails/rails

  • Loading branch information...
2 parents 91963e9 + 6b55947 commit 0fe8827bf384cb99ab757236555c7af18793d515 @wycats wycats committed Apr 30, 2010
Showing with 3,072 additions and 1,419 deletions.
  1. +3 −0 Gemfile
  2. +1 −2 actionmailer/lib/action_mailer/base.rb
  3. 0 {railties/lib/rails/generators/rails → actionmailer/lib/rails/generators}/mailer/USAGE
  4. +2 −0 {railties/lib/rails/generators/rails → actionmailer/lib/rails/generators}/mailer/mailer_generator.rb
  5. 0 {railties/lib/rails/generators/rails → actionmailer/lib/rails/generators}/mailer/templates/mailer.rb
  6. +4 −0 actionpack/CHANGELOG
  7. +1 −1 actionpack/lib/action_controller/caching/actions.rb
  8. +2 −2 actionpack/lib/action_view/base.rb
  9. +33 −44 actionpack/lib/action_view/helpers/date_helper.rb
  10. +1 −1 actionpack/lib/action_view/helpers/prototype_helper.rb
  11. +31 −0 actionpack/test/controller/caching_test.rb
  12. +80 −21 actionpack/test/template/date_helper_test.rb
  13. +51 −111 activemodel/lib/active_model/serializers/xml.rb
  14. +3 −0 activemodel/lib/active_model/validations.rb
  15. +4 −2 activemodel/lib/active_model/validations/acceptance.rb
  16. +13 −2 activemodel/test/cases/serializeration/xml_serialization_test.rb
  17. +8 −0 activemodel/test/models/contact.rb
  18. +6 −0 activerecord/CHANGELOG
  19. +70 −18 activerecord/lib/active_record/associations.rb
  20. +4 −0 activerecord/lib/active_record/base.rb
  21. +56 −0 activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
  22. +34 −1 activerecord/lib/active_record/locking/optimistic.rb
  23. +7 −3 activerecord/lib/active_record/migration.rb
  24. +2 −7 activerecord/lib/active_record/railtie.rb
  25. +0 −1 activerecord/lib/active_record/relation/finder_methods.rb
  26. +42 −31 activerecord/lib/active_record/relation/query_methods.rb
  27. +35 −50 activerecord/lib/active_record/serializers/xml_serializer.rb
  28. +112 −14 activerecord/lib/active_record/transactions.rb
  29. +3 −7 activerecord/lib/rails/generators/active_record.rb
  30. +9 −0 activerecord/test/cases/associations/cascaded_eager_loading_test.rb
  31. +1 −4 activerecord/test/cases/base_test.rb
  32. +48 −3 activerecord/test/cases/locking_test.rb
  33. +19 −0 activerecord/test/cases/migration_test.rb
  34. +7 −0 activerecord/test/cases/serialization_test.rb
  35. +244 −0 activerecord/test/cases/transaction_callbacks_test.rb
  36. +47 −14 activerecord/test/cases/transactions_test.rb
  37. +10 −2 activerecord/test/cases/xml_serialization_test.rb
  38. +4 −0 activerecord/test/models/author.rb
  39. +3 −1 activerecord/test/models/contact.rb
  40. +34 −0 activesupport/CHANGELOG
  41. +1 −1 activesupport/activesupport.gemspec
  42. +427 −69 activesupport/lib/active_support/cache.rb
  43. +6 −15 activesupport/lib/active_support/cache/compressed_mem_cache_store.rb
  44. +139 −41 activesupport/lib/active_support/cache/file_store.rb
  45. +109 −75 activesupport/lib/active_support/cache/mem_cache_store.rb
  46. +125 −31 activesupport/lib/active_support/cache/memory_store.rb
  47. +109 −57 activesupport/lib/active_support/cache/strategy/local_cache.rb
  48. +2 −38 activesupport/lib/active_support/cache/synchronized_memory_store.rb
  49. +20 −22 activesupport/lib/active_support/core_ext/array/conversions.rb
  50. +13 −136 activesupport/lib/active_support/core_ext/hash/conversions.rb
  51. +56 −38 activesupport/lib/active_support/inflector/transliterate.rb
  52. +1 −1 activesupport/lib/active_support/json/encoding.rb
  53. +27 −18 activesupport/lib/active_support/multibyte/chars.rb
  54. +126 −1 activesupport/lib/active_support/xml_mini.rb
  55. +461 −188 activesupport/test/caching_test.rb
  56. +5 −5 activesupport/test/core_ext/array_ext_test.rb
  57. +3 −3 activesupport/test/json/encoding_test.rb
  58. +18 −33 activesupport/test/transliterate_test.rb
  59. +3 −1 railties/guides/source/3_0_release_notes.textile
  60. +9 −1 railties/guides/source/action_mailer_basics.textile
  61. +21 −21 railties/guides/source/command_line.textile
  62. +4 −4 railties/guides/source/credits.html.erb
  63. +14 −20 railties/guides/source/generators.textile
  64. +69 −45 railties/guides/source/getting_started.textile
  65. +77 −77 railties/guides/source/initialization.textile
  66. +10 −10 railties/guides/source/performance_testing.textile
  67. +19 −19 railties/guides/source/testing.textile
  68. +2 −2 railties/lib/rails/application.rb
  69. +2 −1 railties/lib/rails/application/bootstrap.rb
  70. +11 −9 railties/lib/rails/application/configuration.rb
  71. +48 −54 railties/lib/rails/commands.rb
  72. +1 −1 railties/lib/rails/commands/application.rb
  73. 0 railties/lib/rails/commands/{performance → }/benchmarker.rb
  74. 0 railties/lib/rails/commands/{performance → }/profiler.rb
  75. +2 −1 railties/lib/rails/commands/runner.rb
  76. +1 −0 railties/lib/rails/configuration.rb
  77. +1 −1 railties/lib/rails/engine.rb
  78. +22 −16 railties/lib/rails/generators/base.rb
  79. +1 −0 railties/lib/rails/generators/rails/app/app_generator.rb
  80. +5 −5 railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
  81. +2 −5 railties/lib/rails/generators/rails/app/templates/script/rails
  82. +1 −3 railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt
  83. +1 −0 railties/lib/rails/railtie.rb
  84. +1 −1 railties/railties.gemspec
  85. +4 −3 railties/test/application/middleware_test.rb
  86. +33 −0 railties/test/application/model_initialization_test.rb
  87. +3 −2 railties/test/application/paths_test.rb
  88. +14 −0 railties/test/application/rake_test.rb
  89. +1 −1 railties/test/generators/actions_test.rb
  90. +6 −1 railties/test/generators/app_generator_test.rb
  91. +2 −1 railties/test/generators/mailer_generator_test.rb
View
3 Gemfile
@@ -7,6 +7,9 @@ gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
group :mri do
+ gem 'json'
+ gem 'yajl-ruby'
+
if RUBY_VERSION < '1.9'
gem "system_timer"
gem "ruby-debug", ">= 0.10.3"
View
3 actionmailer/lib/action_mailer/base.rb
@@ -291,8 +291,6 @@ class Base < AbstractController::Base
:parts_order => [ "text/plain", "text/enriched", "text/html" ]
}.freeze
- ActiveSupport.run_load_hooks(:action_mailer, self)
-
class << self
def mailer_name
@@ -643,5 +641,6 @@ def insert_part(container, response, charset) #:nodoc:
container.add_part(part)
end
+ ActiveSupport.run_load_hooks(:action_mailer, self)
end
end
View
0 ...s/lib/rails/generators/rails/mailer/USAGE → ...nmailer/lib/rails/generators/mailer/USAGE
File renamed without changes.
View
2 ...nerators/rails/mailer/mailer_generator.rb → ...ils/generators/mailer/mailer_generator.rb
@@ -1,6 +1,8 @@
module Rails
module Generators
class MailerGenerator < NamedBase
+ source_root File.expand_path("../templates", __FILE__)
+
argument :actions, :type => :array, :default => [], :banner => "method method"
check_class_collision
View
0 ...nerators/rails/mailer/templates/mailer.rb → ...ils/generators/mailer/templates/mailer.rb
File renamed without changes.
View
4 actionpack/CHANGELOG
@@ -1,5 +1,9 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
+* Fixed inconsistencies in form builder and view helpers #4432 [Neeraj Singh]
+
+* Both :xml and :json renderers now forwards the given options to the model, allowing you to invoke them as render :xml => @projects, :include => :tasks [José Valim, Yehuda Katz]
+
* Renamed the field error CSS class from fieldWithErrors to field_with_errors for consistency. [Jeremy Kemper]
* Add support for shorthand routes like /projects/status(.:format) #4423 [Diego Carrion]
View
2 actionpack/lib/action_controller/caching/actions.rb
@@ -133,7 +133,7 @@ def filter(controller)
body = controller._save_fragment(cache_path.path, @store_options)
end
- body = controller.render_to_string(:text => cache, :layout => true) unless @cache_layout
+ body = controller.render_to_string(:text => body, :layout => true) unless @cache_layout
controller.response_body = body
controller.content_type = Mime[cache_path.extension || :html]
View
4 actionpack/lib/action_view/base.rb
@@ -176,8 +176,6 @@ class << self
delegate :logger, :to => 'ActionController::Base', :allow_nil => true
end
- ActiveSupport.run_load_hooks(:action_view, self)
-
attr_accessor :base_path, :assigns, :template_extension, :lookup_context
attr_internal :captures, :request, :controller, :template, :config
@@ -229,5 +227,7 @@ def punctuate_body!(part)
response.body_parts << part
nil
end
+
+ ActiveSupport.run_load_hooks(:action_view, self)
end
end
View
77 actionpack/lib/action_view/helpers/date_helper.rb
@@ -589,56 +589,50 @@ def initialize(datetime, options = {}, html_options = {})
@options = options.dup
@html_options = html_options.dup
@datetime = datetime
+ @options[:datetime_separator] ||= ' &mdash; '
+ @options[:time_separator] ||= ' : '
end
def select_datetime
- # TODO: Remove tag conditional
- # Ideally we could just join select_date and select_date for the tag case
+ order = date_order.dup
+ order -= [:hour, :minute, :second]
+ @options[:discard_year] ||= true unless order.include?(:year)
+ @options[:discard_month] ||= true unless order.include?(:month)
+ @options[:discard_day] ||= true if @options[:discard_month] || !order.include?(:day)
+ @options[:discard_minute] ||= true if @options[:discard_hour]
+ @options[:discard_second] ||= true unless @options[:include_seconds] && !@options[:discard_minute]
+
+ # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
+ # valid (otherwise it could be 31 and february wouldn't be a valid date)
+ if @datetime && @options[:discard_day] && !@options[:discard_month]
+ @datetime = @datetime.change(:day => 1)
+ end
+
if @options[:tag] && @options[:ignore_date]
select_time
- elsif @options[:tag]
- order = date_order.dup
- order -= [:hour, :minute, :second]
-
- @options[:discard_year] ||= true unless order.include?(:year)
- @options[:discard_month] ||= true unless order.include?(:month)
- @options[:discard_day] ||= true if @options[:discard_month] || !order.include?(:day)
- @options[:discard_minute] ||= true if @options[:discard_hour]
- @options[:discard_second] ||= true unless @options[:include_seconds] && !@options[:discard_minute]
-
- # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
- # valid (otherwise it could be 31 and february wouldn't be a valid date)
- if @datetime && @options[:discard_day] && !@options[:discard_month]
- @datetime = @datetime.change(:day => 1)
- end
-
+ else
[:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
order += [:hour, :minute, :second] unless @options[:discard_hour]
build_selects_from_types(order)
- else
- "#{select_date}#{@options[:datetime_separator]}#{select_time}".html_safe
end
end
def select_date
order = date_order.dup
- # TODO: Remove tag conditional
- if @options[:tag]
- @options[:discard_hour] = true
- @options[:discard_minute] = true
- @options[:discard_second] = true
+ @options[:discard_hour] = true
+ @options[:discard_minute] = true
+ @options[:discard_second] = true
- @options[:discard_year] ||= true unless order.include?(:year)
- @options[:discard_month] ||= true unless order.include?(:month)
- @options[:discard_day] ||= true if @options[:discard_month] || !order.include?(:day)
+ @options[:discard_year] ||= true unless order.include?(:year)
+ @options[:discard_month] ||= true unless order.include?(:month)
+ @options[:discard_day] ||= true if @options[:discard_month] || !order.include?(:day)
- # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
- # valid (otherwise it could be 31 and february wouldn't be a valid date)
- if @datetime && @options[:discard_day] && !@options[:discard_month]
- @datetime = @datetime.change(:day => 1)
- end
+ # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
+ # valid (otherwise it could be 31 and february wouldn't be a valid date)
+ if @datetime && @options[:discard_day] && !@options[:discard_month]
+ @datetime = @datetime.change(:day => 1)
end
[:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
@@ -649,15 +643,12 @@ def select_date
def select_time
order = []
- # TODO: Remove tag conditional
- if @options[:tag]
- @options[:discard_month] = true
- @options[:discard_year] = true
- @options[:discard_day] = true
- @options[:discard_second] ||= true unless @options[:include_seconds]
+ @options[:discard_month] = true
+ @options[:discard_year] = true
+ @options[:discard_day] = true
+ @options[:discard_second] ||= true unless @options[:include_seconds]
- order += [:year, :month, :day] unless @options[:ignore_date]
- end
+ order += [:year, :month, :day] unless @options[:ignore_date]
order += [:hour, :minute]
order << :second if @options[:include_seconds]
@@ -937,10 +928,8 @@ def datetime_selector(options, html_options)
options[:include_position] = true
options[:prefix] ||= @object_name
options[:index] = @auto_index if @auto_index && !options.has_key?(:index)
- options[:datetime_separator] ||= ' &mdash; '
- options[:time_separator] ||= ' : '
- DateTimeSelector.new(datetime, options.merge(:tag => true), html_options)
+ DateTimeSelector.new(datetime, options, html_options)
end
def default_datetime(options)
View
2 actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -767,7 +767,7 @@ def each_slice(variable, number, &block)
end
def grep(variable, pattern, &block)
- enumerate :grep, :variable => variable, :return => true, :method_args => [pattern], :yield_args => %w(value index), &block
+ enumerate :grep, :variable => variable, :return => true, :method_args => [::ActiveSupport::JSON::Variable.new(pattern.inspect)], :yield_args => %w(value index), &block
end
def in_groups_of(variable, number, fill_with = nil)
View
31 actionpack/test/controller/caching_test.rb
@@ -265,49 +265,57 @@ def teardown
def test_simple_action_cache
get :index
+ assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test')
reset!
get :index
+ assert_response :success
assert_equal cached_time, @response.body
end
def test_simple_action_not_cached
get :destroy
+ assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert !fragment_exist?('hostname.com/action_caching_test/destroy')
reset!
get :destroy
+ assert_response :success
assert_not_equal cached_time, @response.body
end
include RackTestUtils
def test_action_cache_with_layout
get :with_layout
+ assert_response :success
cached_time = content_to_cache
assert_not_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test/with_layout')
reset!
get :with_layout
+ assert_response :success
assert_not_equal cached_time, @response.body
body = body_to_string(read_fragment('hostname.com/action_caching_test/with_layout'))
assert_equal @response.body, body
end
def test_action_cache_with_layout_and_layout_cache_false
get :layout_false
+ assert_response :success
cached_time = content_to_cache
assert_not_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test/layout_false')
reset!
get :layout_false
+ assert_response :success
assert_not_equal cached_time, @response.body
body = body_to_string(read_fragment('hostname.com/action_caching_test/layout_false'))
@@ -317,6 +325,7 @@ def test_action_cache_with_layout_and_layout_cache_false
def test_action_cache_conditional_options
@request.env['HTTP_ACCEPT'] = 'application/json'
get :index
+ assert_response :success
assert !fragment_exist?('hostname.com/action_caching_test')
end
@@ -325,41 +334,50 @@ def test_action_cache_with_store_options
@controller.expects(:read_fragment).with('hostname.com/action_caching_test', :expires_in => 1.hour).once
@controller.expects(:write_fragment).with('hostname.com/action_caching_test', '12345.0', :expires_in => 1.hour).once
get :index
+ assert_response :success
end
def test_action_cache_with_custom_cache_path
get :show
+ assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?('test.host/custom/show')
reset!
get :show
+ assert_response :success
assert_equal cached_time, @response.body
end
def test_action_cache_with_custom_cache_path_in_block
get :edit
+ assert_response :success
assert fragment_exist?('test.host/edit')
reset!
get :edit, :id => 1
+ assert_response :success
assert fragment_exist?('test.host/1;edit')
end
def test_cache_expiration
get :index
+ assert_response :success
cached_time = content_to_cache
reset!
get :index
+ assert_response :success
assert_equal cached_time, @response.body
reset!
get :expire
+ assert_response :success
reset!
get :index
+ assert_response :success
new_cached_time = content_to_cache
assert_not_equal cached_time, @response.body
reset!
@@ -376,35 +394,41 @@ def test_cache_expiration_isnt_affected_by_request_format
@request.request_uri = "/action_caching_test/expire.xml"
get :expire, :format => :xml
+ assert_response :success
reset!
get :index
+ assert_response :success
new_cached_time = content_to_cache
assert_not_equal cached_time, @response.body
end
def test_cache_is_scoped_by_subdomain
@request.host = 'jamis.hostname.com'
get :index
+ assert_response :success
jamis_cache = content_to_cache
reset!
@request.host = 'david.hostname.com'
get :index
+ assert_response :success
david_cache = content_to_cache
assert_not_equal jamis_cache, @response.body
reset!
@request.host = 'jamis.hostname.com'
get :index
+ assert_response :success
assert_equal jamis_cache, @response.body
reset!
@request.host = 'david.hostname.com'
get :index
+ assert_response :success
assert_equal david_cache, @response.body
end
@@ -433,20 +457,24 @@ def test_xml_version_of_resource_is_treated_as_different_cache
end
get :index, :format => 'xml'
+ assert_response :success
cached_time = content_to_cache
assert_equal cached_time, @response.body
assert fragment_exist?('hostname.com/action_caching_test/index.xml')
reset!
get :index, :format => 'xml'
+ assert_response :success
assert_equal cached_time, @response.body
assert_equal 'application/xml', @response.content_type
reset!
get :expire_xml
+ assert_response :success
reset!
get :index, :format => 'xml'
+ assert_response :success
assert_not_equal cached_time, @response.body
end
end
@@ -455,20 +483,23 @@ def test_correct_content_type_is_returned_for_cache_hit
# run it twice to cache it the first time
get :index, :id => 'content-type', :format => 'xml'
get :index, :id => 'content-type', :format => 'xml'
+ assert_response :success
assert_equal 'application/xml', @response.content_type
end
def test_correct_content_type_is_returned_for_cache_hit_on_action_with_string_key
# run it twice to cache it the first time
get :show, :format => 'xml'
get :show, :format => 'xml'
+ assert_response :success
assert_equal 'application/xml', @response.content_type
end
def test_correct_content_type_is_returned_for_cache_hit_on_action_with_string_key_from_proc
# run it twice to cache it the first time
get :edit, :id => 1, :format => 'xml'
get :edit, :id => 1, :format => 'xml'
+ assert_response :success
assert_equal 'application/xml', @response.content_type
end
View
101 actionpack/test/template/date_helper_test.rb
@@ -669,19 +669,11 @@ def test_select_date_with_order
end
def test_select_date_with_incomplete_order
- # NOTE: modified this test because of minimal API change
- expected = %(<select id="date_first_year" name="date[first][year]">\n)
- expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n)
- expected << "</select>\n"
-
- expected << %(<select id="date_first_month" name="date[first][month]">\n)
- expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n)
- expected << "</select>\n"
-
- expected << %(<select id="date_first_day" name="date[first][day]">\n)
- expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
- expected << "</select>\n"
-
+ # Since the order is incomplete nothing will be shown
+ expected = %(<input id="date_first_year" name="date[first][year]" type="hidden" value="2003" />\n)
+ expected << %(<input id="date_first_month" name="date[first][month]" type="hidden" value="8" />\n)
+ expected << %(<input id="date_first_day" name="date[first][day]" type="hidden" value="16" />\n)
+
assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), :start_year => 2003, :end_year => 2005, :prefix => "date[first]", :order => [:day])
end
@@ -903,10 +895,14 @@ def test_select_datetime
expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
expected << "</select>\n"
+ expected << " &mdash; "
+
expected << %(<select id="date_first_hour" name="date[first][hour]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_first_minute" name="date[first][minute]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -955,10 +951,14 @@ def test_select_datetime_with_nil_value_and_no_start_and_end_year
expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
expected << "</select>\n"
+ expected << " &mdash; "
+
expected << %(<select id="date_first_hour" name="date[first][hour]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_first_minute" name="date[first][minute]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -971,6 +971,7 @@ def test_select_datetime_with_html_options
expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n)
expected << "</select>\n"
+
expected << %(<select id="date_first_month" name="date[first][month]" class="selector">\n)
expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n)
expected << "</select>\n"
@@ -979,10 +980,14 @@ def test_select_datetime_with_html_options
expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
expected << "</select>\n"
+ expected << " &mdash; "
+
expected << %(<select id="date_first_hour" name="date[first][hour]" class="selector">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_first_minute" name="date[first][minute]" class="selector">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -1039,10 +1044,14 @@ def test_select_datetime_with_default_prompt
expected << %(<option value="">Day</option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
expected << "</select>\n"
+ expected << " &mdash; "
+
expected << %(<select id="date_first_hour" name="date[first][hour]">\n)
expected << %(<option value="">Hour</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_first_minute" name="date[first][minute]">\n)
expected << %(<option value="">Minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -1065,10 +1074,14 @@ def test_select_datetime_with_custom_prompt
expected << %(<option value="">Choose day</option>\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
expected << "</select>\n"
+ expected << " &mdash; "
+
expected << %(<select id="date_first_hour" name="date[first][hour]">\n)
expected << %(<option value="">Choose hour</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_first_minute" name="date[first][minute]">\n)
expected << %(<option value="">Choose minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -1078,10 +1091,16 @@ def test_select_datetime_with_custom_prompt
end
def test_select_time
- expected = %(<select id="date_hour" name="date[hour]">\n)
+ expected = %(<input name="date[year]" id="date_year" value="2003" type="hidden" />\n)
+ expected << %(<input name="date[month]" id="date_month" value="8" type="hidden" />\n)
+ expected << %(<input name="date[day]" id="date_day" value="16" type="hidden" />\n)
+
+ expected << %(<select id="date_hour" name="date[hour]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_minute" name="date[minute]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -1091,7 +1110,10 @@ def test_select_time
end
def test_select_time_with_separator
- expected = %(<select id="date_hour" name="date[hour]">\n)
+ expected = %(<input name="date[year]" id="date_year" value="2003" type="hidden" />\n)
+ expected << %(<input name="date[month]" id="date_month" value="8" type="hidden" />\n)
+ expected << %(<input name="date[day]" id="date_day" value="16" type="hidden" />\n)
+ expected << %(<select id="date_hour" name="date[hour]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
@@ -1106,14 +1128,22 @@ def test_select_time_with_separator
end
def test_select_time_with_seconds
- expected = %(<select id="date_hour" name="date[hour]">\n)
+ expected = %(<input name="date[year]" id="date_year" value="2003" type="hidden" />\n)
+ expected << %(<input name="date[month]" id="date_month" value="8" type="hidden" />\n)
+ expected << %(<input name="date[day]" id="date_day" value="16" type="hidden" />\n)
+
+ expected << %(<select id="date_hour" name="date[hour]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << ' : '
+
expected << %(<select id="date_minute" name="date[minute]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
+ expected << ' : '
+
expected << %(<select id="date_second" name="date[second]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -1122,7 +1152,11 @@ def test_select_time_with_seconds
end
def test_select_time_with_seconds_and_separator
- expected = %(<select id="date_hour" name="date[hour]">\n)
+ expected = %(<input name="date[year]" id="date_year" value="2003" type="hidden" />\n)
+ expected << %(<input name="date[month]" id="date_month" value="8" type="hidden" />\n)
+ expected << %(<input name="date[day]" id="date_day" value="16" type="hidden" />\n)
+
+ expected << %(<select id="date_hour" name="date[hour]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
@@ -1142,10 +1176,16 @@ def test_select_time_with_seconds_and_separator
end
def test_select_time_with_html_options
- expected = %(<select id="date_hour" name="date[hour]" class="selector">\n)
+ expected = %(<input name="date[year]" id="date_year" value="2003" type="hidden" />\n)
+ expected << %(<input name="date[month]" id="date_month" value="8" type="hidden" />\n)
+ expected << %(<input name="date[day]" id="date_day" value="16" type="hidden" />\n)
+
+ expected << %(<select id="date_hour" name="date[hour]" class="selector">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_minute" name="date[minute]" class="selector">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -1159,14 +1199,22 @@ def test_select_time_should_work_with_date
end
def test_select_time_with_default_prompt
- expected = %(<select id="date_hour" name="date[hour]">\n)
+ expected = %(<input name="date[year]" id="date_year" value="2003" type="hidden" />\n)
+ expected << %(<input name="date[month]" id="date_month" value="8" type="hidden" />\n)
+ expected << %(<input name="date[day]" id="date_day" value="16" type="hidden" />\n)
+
+ expected << %(<select id="date_hour" name="date[hour]">\n)
expected << %(<option value="">Hour</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+
+ expected << " : "
expected << %(<select id="date_minute" name="date[minute]">\n)
expected << %(<option value="">Minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_second" name="date[second]">\n)
expected << %(<option value="">Seconds</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -1175,15 +1223,22 @@ def test_select_time_with_default_prompt
end
def test_select_time_with_custom_prompt
-
- expected = %(<select id="date_hour" name="date[hour]">\n)
+ expected = %(<input name="date[year]" id="date_year" value="2003" type="hidden" />\n)
+ expected << %(<input name="date[month]" id="date_month" value="8" type="hidden" />\n)
+ expected << %(<input name="date[day]" id="date_day" value="16" type="hidden" />\n)
+
+ expected << %(<select id="date_hour" name="date[hour]">\n)
expected << %(<option value="">Choose hour</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08" selected="selected">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_minute" name="date[minute]">\n)
expected << %(<option value="">Choose minute</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04" selected="selected">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_second" name="date[second]">\n)
expected << %(<option value="">Choose seconds</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
@@ -2006,10 +2061,14 @@ def test_datetime_select_with_nil_value_and_no_start_and_end_year
expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
expected << "</select>\n"
+ expected << " &mdash; "
+
expected << %(<select id="date_first_hour" name="date[first][hour]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n)
expected << "</select>\n"
+ expected << " : "
+
expected << %(<select id="date_first_minute" name="date[first][minute]">\n)
expected << %(<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n)
expected << "</select>\n"
View
162 activemodel/lib/active_model/serializers/xml.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/attribute_accessors'
+require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/hash/conversions'
require 'active_support/core_ext/hash/slice'
@@ -15,65 +16,29 @@ class Attribute #:nodoc:
def initialize(name, serializable, raw_value=nil)
@name, @serializable = name, serializable
- @raw_value = raw_value || @serializable.send(name)
-
+ @value = value || @serializable.send(name)
@type = compute_type
- @value = compute_value
- end
-
- # There is a significant speed improvement if the value
- # does not need to be escaped, as <tt>tag!</tt> escapes all values
- # to ensure that valid XML is generated. For known binary
- # values, it is at least an order of magnitude faster to
- # Base64 encode binary values and directly put them in the
- # output XML than to pass the original value or the Base64
- # encoded value to the <tt>tag!</tt> method. It definitely makes
- # no sense to Base64 encode the value and then give it to
- # <tt>tag!</tt>, since that just adds additional overhead.
- def needs_encoding?
- ![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type)
end
- def decorations(include_types = true)
+ def decorations
decorations = {}
-
- if type == :binary
- decorations[:encoding] = 'base64'
- end
-
- if include_types && type != :string
- decorations[:type] = type
- end
-
- if value.nil?
- decorations[:nil] = true
- end
-
+ decorations[:encoding] = 'base64' if type == :binary
+ decorations[:type] = type unless type == :string
+ decorations[:nil] = true if value.nil?
decorations
end
- protected
- def compute_type
- type = Hash::XML_TYPE_NAMES[@raw_value.class.name]
- type ||= :string if @raw_value.respond_to?(:to_str)
- type ||= :yaml
- type
- end
+ protected
- def compute_value
- if formatter = Hash::XML_FORMATTING[type.to_s]
- @raw_value ? formatter.call(@raw_value) : nil
- else
- @raw_value
- end
- end
+ def compute_type
+ type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name]
+ type ||= :string if value.respond_to?(:to_str)
+ type ||= :yaml
+ type
+ end
end
class MethodAttribute < Attribute #:nodoc:
- protected
- def compute_type
- Hash::XML_TYPE_NAMES[@raw_value.class.name] || :string
- end
end
attr_reader :options
@@ -92,7 +57,7 @@ def initialize(serializable, options = nil)
# then because <tt>:except</tt> is set to a default value, the second
# level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
# <tt>:only</tt> is set, always delete <tt>:except</tt>.
- def serializable_attributes_hash
+ def attributes_hash
attributes = @serializable.attributes
if options[:only].any?
attributes.slice(*options[:only])
@@ -104,91 +69,66 @@ def serializable_attributes_hash
end
def serializable_attributes
- serializable_attributes_hash.map { |name, value| self.class::Attribute.new(name, @serializable, value) }
+ attributes_hash.map do |name, value|
+ self.class::Attribute.new(name, @serializable, value)
+ end
end
- def serializable_method_attributes
+ def serializable_methods
Array.wrap(options[:methods]).inject([]) do |methods, name|
methods << self.class::MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
methods
end
end
def serialize
- args = [root]
-
- if options[:namespace]
- args << {:xmlns => options[:namespace]}
- end
+ require 'builder' unless defined? ::Builder
- if options[:type]
- args << {:type => options[:type]}
- end
-
- builder.tag!(*args) do
- add_attributes
- procs = options.delete(:procs)
- options[:procs] = procs
- add_procs
- yield builder if block_given?
- end
- end
+ options[:indent] ||= 2
+ options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
- private
- def builder
- @builder ||= begin
- require 'builder' unless defined? ::Builder
- options[:indent] ||= 2
- builder = options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
+ @builder = options[:builder]
+ @builder.instruct! unless options[:skip_instruct]
- unless options[:skip_instruct]
- builder.instruct!
- options[:skip_instruct] = true
- end
+ root = (options[:root] || @serializable.class.model_name.singular).to_s
+ root = ActiveSupport::XmlMini.rename_key(root, options)
- builder
- end
- end
-
- def root
- root = (options[:root] || @serializable.class.model_name.singular).to_s
- reformat_name(root)
- end
+ args = [root]
+ args << {:xmlns => options[:namespace]} if options[:namespace]
+ args << {:type => options[:type]} if options[:type] && !options[:skip_types]
- def dasherize?
- !options.has_key?(:dasherize) || options[:dasherize]
+ @builder.tag!(*args) do
+ add_attributes_and_methods
+ add_extra_behavior
+ add_procs
+ yield @builder if block_given?
end
+ end
- def camelize?
- options.has_key?(:camelize) && options[:camelize]
- end
+ private
- def reformat_name(name)
- name = name.camelize if camelize?
- dasherize? ? name.dasherize : name
- end
+ def add_extra_behavior
+ end
- def add_attributes
- (serializable_attributes + serializable_method_attributes).each do |attribute|
- builder.tag!(
- reformat_name(attribute.name),
- attribute.value.to_s,
- attribute.decorations(!options[:skip_types])
- )
- end
+ def add_attributes_and_methods
+ (serializable_attributes + serializable_methods).each do |attribute|
+ key = ActiveSupport::XmlMini.rename_key(attribute.name, options)
+ ActiveSupport::XmlMini.to_tag(key, attribute.value,
+ options.merge(attribute.decorations))
end
+ end
- def add_procs
- if procs = options.delete(:procs)
- [ *procs ].each do |proc|
- if proc.arity > 1
- proc.call(options, @serializable)
- else
- proc.call(options)
- end
+ def add_procs
+ if procs = options.delete(:procs)
+ Array.wrap(procs).each do |proc|
+ if proc.arity == 1
+ proc.call(options)
+ else
+ proc.call(options, @serializable)
end
end
end
+ end
end
def to_xml(options = {}, &block)
View
3 activemodel/lib/active_model/validations.rb
@@ -133,6 +133,9 @@ def validators_on(attribute)
_validators[attribute.to_sym]
end
+ def attribute_method?(attribute)
+ method_defined?(attribute)
+ end
private
def _merge_attributes(attr_names)
View
6 activemodel/lib/active_model/validations/acceptance.rb
@@ -14,8 +14,10 @@ def validate_each(record, attribute, value)
def setup(klass)
# Note: instance_methods.map(&:to_s) is important for 1.9 compatibility
# as instance_methods returns symbols unlike 1.8 which returns strings.
- new_attributes = attributes.reject { |name| klass.instance_methods.map(&:to_s).include?("#{name}=") }
- klass.send(:attr_accessor, *new_attributes)
+ attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
+ attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
+ klass.send(:attr_reader, *attr_readers)
+ klass.send(:attr_writer, *attr_writers)
end
end
View
15 activemodel/test/cases/serializeration/xml_serialization_test.rb
@@ -1,6 +1,7 @@
require 'cases/helper'
require 'models/contact'
require 'active_support/core_ext/object/instance_variables'
+require 'ostruct'
class Contact
extend ActiveModel::Naming
@@ -23,7 +24,9 @@ def setup
@contact.age = 25
@contact.created_at = Time.utc(2006, 8, 1)
@contact.awesome = false
- @contact.preferences = { :gem => 'ruby' }
+ customer = OpenStruct.new
+ customer.name = "John"
+ @contact.preferences = customer
end
test "should serialize default root" do
@@ -92,8 +95,16 @@ def setup
assert_match %r{<awesome type=\"boolean\">false</awesome>}, @contact.to_xml
end
+ test "should serialize array" do
+ assert_match %r{<social type=\"array\">\s*<social>twitter</social>\s*<social>github</social>\s*</social>}, @contact.to_xml(:methods => :social)
+ end
+
+ test "should serialize hash" do
+ assert_match %r{<network>\s*<git type=\"symbol\">github</git>\s*</network>}, @contact.to_xml(:methods => :network)
+ end
+
test "should serialize yaml" do
- assert_match %r{<preferences type=\"yaml\">--- \n:gem: ruby\n</preferences>}, @contact.to_xml
+ assert_match %r{<preferences type=\"yaml\">--- !ruby/object:OpenStruct \ntable:\s*:name: John\n</preferences>}, @contact.to_xml
end
test "should call proc on object" do
View
8 activemodel/test/models/contact.rb
@@ -3,6 +3,14 @@ class Contact
attr_accessor :id, :name, :age, :created_at, :awesome, :preferences
+ def social
+ %w(twitter github)
+ end
+
+ def network
+ {:git => :github}
+ end
+
def initialize(options = {})
options.each { |name, value| send("#{name}=", value) }
end
View
6 activerecord/CHANGELOG
@@ -1,5 +1,11 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
+* New callbacks: after_commit and after_rollback. Do expensive operations like image thumbnailing after_commit instead of after_save. #2991 [Brian Durand]
+
+* Serialized attributes are not converted to YAML if they are any of the formats that can be serialized to XML (like Hash, Array and Strings). [José Valim]
+
+* Destroy uses optimistic locking. If lock_version on the record you're destroying doesn't match lock_version in the database, a StaleObjectError is raised. #1966 [Curtis Hawthorne]
+
* PostgreSQL: drop support for old postgres driver. Use pg 0.9.0 or later. [Jeremy Kemper]
* Observers can prevent records from saving by returning false, just like before_save and friends. #4087 [Mislav Marohnić]
View
88 activerecord/lib/active_record/associations.rb
@@ -1500,7 +1500,16 @@ def configure_dependency_for_has_many(reflection, extra_conditions = nil)
when :destroy
method_name = "has_many_dependent_destroy_for_#{reflection.name}".to_sym
define_method(method_name) do
- send(reflection.name).each { |o| o.destroy }
+ send(reflection.name).each do |o|
+ # No point in executing the counter update since we're going to destroy the parent anyway
+ counter_method = ('belongs_to_counter_cache_before_destroy_for_' + self.class.name.downcase).to_sym
+ if(o.respond_to? counter_method) then
+ class << o
+ self
+ end.send(:define_method, counter_method, Proc.new {})
+ end
+ o.destroy
+ end
end
before_destroy method_name
when :delete_all
@@ -1728,6 +1737,14 @@ def initialize(base, associations, joins)
build(associations)
end
+ def graft(*associations)
+ associations.each do |association|
+ join_associations.detect {|a| association == a} ||
+ build(association.reflection.name, association.find_parent_in(self), association.join_class)
+ end
+ self
+ end
+
def join_associations
@joins[1..-1].to_a
end
@@ -1736,6 +1753,16 @@ def join_base
@joins[0]
end
+ def count_aliases_from_table_joins(name)
+ quoted_name = join_base.active_record.connection.quote_table_name(name.downcase)
+ join_sql = join_base.table_joins.to_s.downcase
+ join_sql.blank? ? 0 :
+ # Table names
+ join_sql.scan(/join(?:\s+\w+)?\s+#{quoted_name}\son/).size +
+ # Table aliases
+ join_sql.scan(/join(?:\s+\w+)?\s+\S+\s+#{quoted_name}\son/).size
+ end
+
def instantiate(rows)
rows.each_with_index do |row, i|
primary_id = join_base.record_id(row)
@@ -1780,22 +1807,22 @@ def remove_duplicate_results!(base, records, associations)
end
protected
- def build(associations, parent = nil)
+ def build(associations, parent = nil, join_class = Arel::InnerJoin)
parent ||= @joins.last
case associations
when Symbol, String
reflection = parent.reflections[associations.to_s.intern] or
raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?"
@reflections << reflection
- @joins << build_join_association(reflection, parent)
+ @joins << build_join_association(reflection, parent).with_join_class(join_class)
when Array
associations.each do |association|
- build(association, parent)
+ build(association, parent, join_class)
end
when Hash
associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
- build(name, parent)
- build(associations[name])
+ build(name, parent, join_class)
+ build(associations[name], nil, join_class)
end
else
raise ConfigurationError, associations.inspect
@@ -1872,6 +1899,12 @@ def initialize(active_record, joins = nil)
@table_joins = joins
end
+ def ==(other)
+ other.is_a?(JoinBase) &&
+ other.active_record == active_record &&
+ other.table_joins == table_joins
+ end
+
def aliased_prefix
"t0"
end
@@ -1937,6 +1970,27 @@ def initialize(reflection, join_dependency, parent = nil)
end
end
+ def ==(other)
+ other.is_a?(JoinAssociation) &&
+ other.reflection == reflection &&
+ other.parent == parent
+ end
+
+ def find_parent_in(other_join_dependency)
+ other_join_dependency.joins.detect do |join|
+ self.parent == join
+ end
+ end
+
+ def join_class
+ @join_class ||= Arel::InnerJoin
+ end
+
+ def with_join_class(join_class)
+ @join_class = join_class
+ self
+ end
+
def association_join
return @join if @join
@@ -2036,27 +2090,25 @@ def relation
end
def join_relation(joining_relation, join = nil)
- if (relations = relation).is_a?(Array)
- joining_relation.joins(Relation::JoinOperation.new(relations.first, Arel::OuterJoin, association_join.first)).
- joins(Relation::JoinOperation.new(relations.last, Arel::OuterJoin, association_join.last))
- else
- joining_relation.joins(Relation::JoinOperation.new(relations, Arel::OuterJoin, association_join))
- end
+ joining_relation.joins(self.with_join_class(Arel::OuterJoin))
end
protected
def aliased_table_name_for(name, suffix = nil)
- if !parent.table_joins.blank? && parent.table_joins.to_s.downcase =~ %r{join(\s+\w+)?\s+#{active_record.connection.quote_table_name name.downcase}\son}
- @join_dependency.table_aliases[name] += 1
+ if @join_dependency.table_aliases[name].zero?
+ @join_dependency.table_aliases[name] = @join_dependency.count_aliases_from_table_joins(name)
end
- unless @join_dependency.table_aliases[name].zero?
- # if the table name has been used, then use an alias
+ if !@join_dependency.table_aliases[name].zero? # We need an alias
name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}#{suffix}"
- table_index = @join_dependency.table_aliases[name]
@join_dependency.table_aliases[name] += 1
- name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index+1}" if table_index > 0
+ if @join_dependency.table_aliases[name] == 1 # First time we've seen this name
+ # Also need to count the aliases from the table_aliases to avoid incorrect count
+ @join_dependency.table_aliases[name] += @join_dependency.count_aliases_from_table_joins(name)
+ end
+ table_index = @join_dependency.table_aliases[name]
+ name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index}" if table_index > 1
else
@join_dependency.table_aliases[name] += 1
end
View
4 activerecord/lib/active_record/base.rb
@@ -931,6 +931,10 @@ def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodo
subclasses.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information }
end
+ def attribute_method?(attribute)
+ super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, '')))
+ end
+
# Set the lookup ancestors for ActiveModel.
def lookup_ancestors #:nodoc:
klass = self
View
56 activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -122,6 +122,8 @@ def transaction(options = {})
requires_new = options[:requires_new] || !last_transaction_joinable
transaction_open = false
+ @_current_transaction_records ||= []
+
begin
if block_given?
if requires_new || open_transactions == 0
@@ -132,6 +134,7 @@ def transaction(options = {})
end
increment_open_transactions
transaction_open = true
+ @_current_transaction_records.push([])
end
yield
end
@@ -141,8 +144,10 @@ def transaction(options = {})
decrement_open_transactions
if open_transactions == 0
rollback_db_transaction
+ rollback_transaction_records(true)
else
rollback_to_savepoint
+ rollback_transaction_records(false)
end
end
raise unless database_transaction_rollback.is_a?(ActiveRecord::Rollback)
@@ -157,20 +162,35 @@ def transaction(options = {})
begin
if open_transactions == 0
commit_db_transaction
+ commit_transaction_records
else
release_savepoint
+ save_point_records = @_current_transaction_records.pop
+ unless save_point_records.blank?
+ @_current_transaction_records.push([]) if @_current_transaction_records.empty?
+ @_current_transaction_records.last.concat(save_point_records)
+ end
end
rescue Exception => database_transaction_rollback
if open_transactions == 0
rollback_db_transaction
+ rollback_transaction_records(true)
else
rollback_to_savepoint
+ rollback_transaction_records(false)
end
raise
end
end
end
+ # Register a record with the current transaction so that its after_commit and after_rollback callbacks
+ # can be called.
+ def add_transaction_record(record)
+ last_batch = @_current_transaction_records.last
+ last_batch << record if last_batch
+ end
+
# Begins the transaction (and turns off auto-committing).
def begin_db_transaction() end
@@ -268,6 +288,42 @@ def sanitize_limit(limit)
limit.to_i
end
end
+
+ # Send a rollback message to all records after they have been rolled back. If rollback
+ # is false, only rollback records since the last save point.
+ def rollback_transaction_records(rollback) #:nodoc
+ if rollback
+ records = @_current_transaction_records.flatten
+ @_current_transaction_records.clear
+ else
+ records = @_current_transaction_records.pop
+ end
+
+ unless records.blank?
+ records.uniq.each do |record|
+ begin
+ record.rolledback!(rollback)
+ rescue Exception => e
+ record.logger.error(e) if record.respond_to?(:logger)
+ end
+ end
+ end
+ end
+
+ # Send a commit message to all records after they have been committed.
+ def commit_transaction_records #:nodoc
+ records = @_current_transaction_records.flatten
+ @_current_transaction_records.clear
+ unless records.blank?
+ records.uniq.each do |record|
+ begin
+ record.committed!
+ rescue Exception => e
+ record.logger.error(e) if record.respond_to?(:logger)
+ end
+ end
+ end
+ end
end
end
end
View
35 activerecord/lib/active_record/locking/optimistic.rb
@@ -23,6 +23,16 @@ module Locking
# p2.first_name = "should fail"
# p2.save # Raises a ActiveRecord::StaleObjectError
#
+ # Optimistic locking will also check for stale data when objects are destroyed. Example:
+ #
+ # p1 = Person.find(1)
+ # p2 = Person.find(1)
+ #
+ # p1.first_name = "Michael"
+ # p1.save
+ #
+ # p2.destroy # Raises a ActiveRecord::StaleObjectError
+ #
# You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging,
# or otherwise apply the business logic needed to resolve the conflict.
#
@@ -39,6 +49,7 @@ module Optimistic
self.lock_optimistically = true
alias_method_chain :update, :lock
+ alias_method_chain :destroy, :lock
alias_method_chain :attributes_from_column_definition, :lock
class << self
@@ -88,7 +99,7 @@ def update_with_lock(attribute_names = @attributes.keys) #:nodoc:
unless affected_rows == 1
- raise ActiveRecord::StaleObjectError, "Attempted to update a stale object"
+ raise ActiveRecord::StaleObjectError, "Attempted to update a stale object: #{self.class.name}"
end
affected_rows
@@ -100,6 +111,28 @@ def update_with_lock(attribute_names = @attributes.keys) #:nodoc:
end
end
+ def destroy_with_lock #:nodoc:
+ return destroy_without_lock unless locking_enabled?
+
+ unless new_record?
+ lock_col = self.class.locking_column
+ previous_value = send(lock_col).to_i
+
+ affected_rows = connection.delete(
+ "DELETE FROM #{self.class.quoted_table_name} " +
+ "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quoted_id} " +
+ "AND #{self.class.quoted_locking_column} = #{quote_value(previous_value)}",
+ "#{self.class.name} Destroy"
+ )
+
+ unless affected_rows == 1
+ raise ActiveRecord::StaleObjectError, "Attempted to delete a stale object: #{self.class.name}"
+ end
+ end
+
+ freeze
+ end
+
module ClassMethods
DEFAULT_LOCKING_COLUMN = 'lock_version'
View
10 activerecord/lib/active_record/migration.rb
@@ -384,9 +384,13 @@ class Migrator#:nodoc:
class << self
def migrate(migrations_path, target_version = nil)
case
- when target_version.nil? then up(migrations_path, target_version)
- when current_version > target_version then down(migrations_path, target_version)
- else up(migrations_path, target_version)
+ when target_version.nil?
+ up(migrations_path, target_version)
+ when current_version == 0 && target_version == 0
+ when current_version > target_version
+ down(migrations_path, target_version)
+ else
+ up(migrations_path, target_version)
end
end
View
9 activerecord/lib/active_record/railtie.rb
@@ -61,13 +61,8 @@ class Railtie < Rails::Railtie
# Setup database middleware after initializers have run
initializer "active_record.initialize_database_middleware", :after => "action_controller.set_configs" do |app|
middleware = app.config.middleware
- if middleware.include?("ActiveRecord::SessionStore")
- middleware.insert_before "ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement
- middleware.insert_before "ActiveRecord::SessionStore", ActiveRecord::QueryCache
- else
- middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
- middleware.use ActiveRecord::QueryCache
- end
+ middleware.insert_after "::ActionDispatch::Callbacks", ActiveRecord::QueryCache
+ middleware.insert_after "::ActionDispatch::Callbacks", ActiveRecord::ConnectionAdapters::ConnectionManagement
end
initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
View
1 activerecord/lib/active_record/relation/finder_methods.rb
@@ -188,7 +188,6 @@ def find_with_associations
def construct_relation_for_association_calculations
including = (@eager_load_values + @includes_values).uniq
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, arel.joins(arel))
-
relation = except(:includes, :eager_load, :preload)
apply_join_dependency(relation, join_dependency)
end
View
73 activerecord/lib/active_record/relation/query_methods.rb
@@ -80,6 +80,26 @@ def arel
@arel ||= build_arel
end
+ def custom_join_sql(*joins)
+ arel = table
+ joins.each do |join|
+ next if join.blank?
+
+ @implicit_readonly = true
+
+ case join
+ when Hash, Array, Symbol
+ if array_of_strings?(join)
+ join_string = join.join(' ')
+ arel = arel.join(join_string)
+ end
+ else
+ arel = arel.join(join)
+ end
+ end
+ arel.joins(arel)
+ end
+
def build_arel
arel = table
@@ -88,50 +108,41 @@ def build_arel
joins = @joins_values.map {|j| j.respond_to?(:strip) ? j.strip : j}.uniq
- # Build association joins first
joins.each do |join|
association_joins << join if [Hash, Array, Symbol].include?(join.class) && !array_of_strings?(join)
end
- if association_joins.any?
- join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins.uniq, nil)
- to_join = []
+ stashed_association_joins = joins.select {|j| j.is_a?(ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation)}
- join_dependency.join_associations.each do |association|
- if (association_relation = association.relation).is_a?(Array)
- to_join << [association_relation.first, association.association_join.first]
- to_join << [association_relation.last, association.association_join.last]
- else
- to_join << [association_relation, association.association_join]
- end
- end
+ non_association_joins = (joins - association_joins - stashed_association_joins).reject {|j| j.blank?}
+ custom_joins = custom_join_sql(*non_association_joins)
- to_join.each do |tj|
- unless joined_associations.detect {|ja| ja[0] == tj[0] && ja[1] == tj[1] }
- joined_associations << tj
- arel = arel.join(tj[0]).on(*tj[1])
- end
- end
- end
+ join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, association_joins, custom_joins)
- joins.each do |join|
- next if join.blank?
+ join_dependency.graft(*stashed_association_joins)
- @implicit_readonly = true
+ @implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
- case join
- when Relation::JoinOperation
- arel = arel.join(join.relation, join.join_class).on(*join.on)
- when Hash, Array, Symbol
- if array_of_strings?(join)
- join_string = join.join(' ')
- arel = arel.join(join_string)
- end
+ to_join = []
+
+ join_dependency.join_associations.each do |association|
+ if (association_relation = association.relation).is_a?(Array)
+ to_join << [association_relation.first, association.join_class, association.association_join.first]
+ to_join << [association_relation.last, association.join_class, association.association_join.last]
else
- arel = arel.join(join)
+ to_join << [association_relation, association.join_class, association.association_join]
end
end
+ to_join.each do |tj|
+ unless joined_associations.detect {|ja| ja[0] == tj[0] && ja[1] == tj[1] && ja[2] == tj[2] }
+ joined_associations << tj
+ arel = arel.join(tj[0], tj[1]).on(*tj[2])
+ end
+ end
+
+ arel = arel.join(custom_joins)
+
@where_values.uniq.each do |where|
next if where.blank?
View
85 activerecord/lib/active_record/serializers/xml_serializer.rb
@@ -182,16 +182,31 @@ def initialize(*args)
options[:except] |= Array.wrap(@serializable.class.inheritance_column)
end
+ def add_extra_behavior
+ add_includes
+ end
+
+ def add_includes
+ procs = options.delete(:procs)
+ @serializable.send(:serializable_add_includes, options) do |association, records, opts|
+ add_associations(association, records, opts)
+ end
+ options[:procs] = procs
+ end
+
+ # TODO This can likely be cleaned up to simple use ActiveSupport::XmlMini.to_tag as well.
def add_associations(association, records, opts)
+ association_name = association.to_s.singularize
+ merged_options = options.merge(opts).merge!(:root => association_name, :skip_instruct => true)
+
if records.is_a?(Enumerable)
- tag = reformat_name(association.to_s)
- type = options[:skip_types] ? {} : {:type => "array"}
+ tag = ActiveSupport::XmlMini.rename_key(association.to_s, options)
+ type = options[:skip_types] ? { } : {:type => "array"}
if records.empty?
- builder.tag!(tag, type)
+ @builder.tag!(tag, type)
else
- builder.tag!(tag, type) do
- association_name = association.to_s.singularize
+ @builder.tag!(tag, type) do
records.each do |record|
if options[:skip_types]
record_type = {}
@@ -200,60 +215,30 @@ def add_associations(association, records, opts)
record_type = {:type => record_class}
end
- record.to_xml opts.merge(:root => association_name).merge(record_type)
+ record.to_xml merged_options.merge(record_type)
end
end
end
- else
- if record = @serializable.send(association)
- record.to_xml(opts.merge(:root => association))
- end
- end
- end
-
- def serialize
- args = [root]
- if options[:namespace]
- args << {:xmlns=>options[:namespace]}
- end
-
- if options[:type]
- args << {:type=>options[:type]}
- end
-
- builder.tag!(*args) do
- add_attributes
- procs = options.delete(:procs)
- @serializable.send(:serializable_add_includes, options) { |association, records, opts|
- add_associations(association, records, opts)
- }
- options[:procs] = procs
- add_procs
- yield builder if block_given?
+ elsif record = @serializable.send(association)
+ record.to_xml(merged_options)
end
end
class Attribute < ActiveModel::Serializers::Xml::Serializer::Attribute #:nodoc:
- protected
- def compute_type
- type = @serializable.class.serialized_attributes.has_key?(name) ? :yaml : @serializable.class.columns_hash[name].type
-
- case type
- when :text
- :string
- when :time
- :datetime
- else
- type
- end
- end
- end
+ def compute_type
+ type = @serializable.class.serialized_attributes.has_key?(name) ?
+ super : @serializable.class.columns_hash[name].type
- class MethodAttribute < Attribute #:nodoc:
- protected
- def compute_type
- Hash::XML_TYPE_NAMES[@serializable.send(name).class.name] || :string
+ case type
+ when :text
+ :string
+ when :time
+ :datetime
+ else
+ type
end
+ end
+ protected :compute_type
end
end
end
View
126 activerecord/lib/active_record/transactions.rb
@@ -12,6 +12,9 @@ class TransactionError < ActiveRecordError # :nodoc:
[:destroy, :save, :save!].each do |method|
alias_method_chain method, :transactions
end
+
+ define_model_callbacks :commit, :commit_on_update, :commit_on_create, :commit_on_destroy, :only => :after
+ define_model_callbacks :rollback, :rollback_on_update, :rollback_on_create, :rollback_on_destroy
end
# Transactions are protective blocks where SQL statements are only permanent