Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into adequaterecord

* master: (96 commits)
  clarify CHANGELOG [ci skip].
  Fix Generation of proper migration when   ActiveRecord::Base.pluralize_table_names = false.
  update comments to reflect that options support is not available
  synchronize changelogs and 4.1 release notes. [ci skip]
  do not rely on method_missing hitting arel
  use ARel factory methods for building AST nodes
  Fix date_select option overwriting html classes
  - Rename `increment_or_decrement` to an apt `set_cache_value` since it actually doesn't increment/decrement in localstore.
  Check if any sqlite files are not included in the gitignore
  Remove sqlite3 lines from .gitignore if the application is not using sqlite3.
  Adding active_model in Rails::Info
  Clean up tables after each test.
  Swapped parameters of assert_equal in assert_select
  Update test helper to use latest Digestor API
  Digestor should just rely on the finder to know about the format and the variant -- trying to pass it back in makes a mess of things (oh, and doesnt work)
  Log the full path, including variant, that the digestor is trying to find
  Fix for digestor to consider variants for partials -- this still needs more testing!!
  fix log_tags request object grammar
  Extract with_example_table into helper method.
  test for structure:dump without schema information table. refs eafec46
  ...

Conflicts:
	activerecord/test/cases/relation/where_chain_test.rb
  • Loading branch information...
commit 30b94a876f32f5024f841a6de9b5b20a014a41d3 2 parents 23ffd03 + 9a976ab
@tenderlove tenderlove authored
Showing with 1,277 additions and 639 deletions.
  1. +4 −4 actionmailer/test/base_test.rb
  2. +15 −0 actionpack/CHANGELOG.md
  3. +11 −10 actionpack/lib/action_controller/metal/live.rb
  4. +2 −2 actionpack/lib/action_controller/test_case.rb
  5. +1 −1  actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
  6. +5 −1 actionpack/lib/action_dispatch/routing/mapper.rb
  7. +1 −1  actionpack/lib/action_dispatch/testing/assertions/selector.rb
  8. +28 −7 actionpack/test/controller/caching_test.rb
  9. +19 −0 actionpack/test/controller/live_stream_test.rb
  10. +34 −7 actionpack/test/dispatch/request/session_test.rb
  11. +36 −0 actionpack/test/dispatch/routing_test.rb
  12. +2 −1  actionpack/test/dispatch/session/mem_cache_store_test.rb
  13. +3 −0  actionpack/test/fixtures/functional_caching/formatted_fragment_cached_with_variant.html+phone.erb
  14. +15 −0 actionview/CHANGELOG.md
  15. +29 −61 actionview/lib/action_view/digestor.rb
  16. +4 −4 actionview/lib/action_view/helpers/cache_helper.rb
  17. +1 −1  actionview/lib/action_view/helpers/date_helper.rb
  18. +7 −3 actionview/lib/action_view/helpers/tags/collection_check_boxes.rb
  19. +10 −10 actionview/lib/action_view/helpers/url_helper.rb
  20. +8 −1 actionview/lib/action_view/lookup_context.rb
  21. +2 −1  actionview/lib/action_view/template.rb
  22. +10 −7 actionview/lib/action_view/template/resolver.rb
  23. +8 −4 actionview/lib/action_view/testing/resolvers.rb
  24. +1 −0  actionview/test/fixtures/test/hello_world.html+phone.erb
  25. +1 −0  actionview/test/fixtures/test/hello_world.text+phone.erb
  26. +16 −0 actionview/test/template/date_helper_test.rb
  27. +22 −14 actionview/test/template/digestor_test.rb
  28. +7 −0 actionview/test/template/form_collections_helper_test.rb
  29. +14 −0 actionview/test/template/lookup_context_test.rb
  30. +3 −0  actionview/test/template/number_helper_test.rb
  31. +65 −6 activerecord/CHANGELOG.md
  32. +1 −1  activerecord/lib/active_record/associations.rb
  33. +1 −2  activerecord/lib/active_record/associations/collection_association.rb
  34. +28 −28 activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
  35. +9 −12 activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
  36. +1 −0  activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
  37. +6 −14 activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
  38. +2 −2 activerecord/lib/active_record/connection_adapters/connection_specification.rb
  39. +1 −0  activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
  40. +6 −5 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  41. +2 −1  activerecord/lib/active_record/fixtures.rb
  42. +12 −9 activerecord/lib/active_record/persistence.rb
  43. +2 −1  activerecord/lib/active_record/railties/databases.rake
  44. +2 −0  activerecord/lib/active_record/relation/query_methods.rb
  45. +7 −3 activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
  46. +1 −1  activerecord/test/cases/adapter_test.rb
  47. +1 −1  activerecord/test/cases/adapters/mysql/active_schema_test.rb
  48. +41 −39 activerecord/test/cases/adapters/mysql/connection_test.rb
  49. +55 −53 activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
  50. +1 −1  activerecord/test/cases/adapters/mysql/reserved_word_test.rb
  51. +1 −1  activerecord/test/cases/adapters/mysql2/active_schema_test.rb
  52. +1 −1  activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
  53. +1 −1  activerecord/test/cases/adapters/postgresql/active_schema_test.rb
  54. +1 −1  activerecord/test/cases/adapters/postgresql/array_test.rb
  55. +1 −1  activerecord/test/cases/adapters/postgresql/bytea_test.rb
  56. +1 −1  activerecord/test/cases/adapters/postgresql/citext_test.rb
  57. +1 −1  activerecord/test/cases/adapters/postgresql/composite_test.rb
  58. +31 −0 activerecord/test/cases/adapters/postgresql/connection_test.rb
  59. +1 −1  activerecord/test/cases/adapters/postgresql/datatype_test.rb
  60. +1 −1  activerecord/test/cases/adapters/postgresql/enum_test.rb
  61. +1 −1  activerecord/test/cases/adapters/postgresql/hstore_test.rb
  62. +1 −1  activerecord/test/cases/adapters/postgresql/json_test.rb
  63. +1 −1  activerecord/test/cases/adapters/postgresql/ltree_test.rb
  64. +50 −6 activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
  65. +1 −1  activerecord/test/cases/adapters/postgresql/range_test.rb
  66. +1 −1  activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
  67. +1 −1  activerecord/test/cases/adapters/postgresql/schema_test.rb
  68. +1 −1  activerecord/test/cases/adapters/postgresql/view_test.rb
  69. +1 −1  activerecord/test/cases/adapters/postgresql/xml_test.rb
  70. +1 −1  activerecord/test/cases/ar_schema_test.rb
  71. +11 −0 activerecord/test/cases/associations/belongs_to_associations_test.rb
  72. +2 −2 activerecord/test/cases/associations/eager_load_nested_include_test.rb
  73. +1 −1  activerecord/test/cases/associations/eager_singularization_test.rb
  74. +10 −0 activerecord/test/cases/associations/eager_test.rb
  75. +24 −0 activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
  76. +1 −1  activerecord/test/cases/attribute_methods_test.rb
  77. +1 −1  activerecord/test/cases/bind_parameter_test.rb
  78. +0 −6 activerecord/test/cases/connection_adapters/abstract_adapter_test.rb
  79. +7 −1 activerecord/test/cases/connection_adapters/connection_handler_test.rb
  80. +17 −15 activerecord/test/cases/connection_pool_test.rb
  81. +1 −1  activerecord/test/cases/defaults_test.rb
  82. +1 −1  activerecord/test/cases/disconnected_test.rb
  83. +1 −1  activerecord/test/cases/explain_subscriber_test.rb
  84. +12 −0 activerecord/test/cases/finder_test.rb
  85. +4 −0 activerecord/test/cases/fixtures_test.rb
  86. +1 −1  activerecord/test/cases/inheritance_test.rb
  87. +1 −1  activerecord/test/cases/invalid_connection_test.rb
  88. +1 −1  activerecord/test/cases/invertible_migration_test.rb
  89. +1 −2  activerecord/test/cases/migration/change_schema_test.rb
  90. +1 −1  activerecord/test/cases/migration/change_table_test.rb
  91. +1 −2  activerecord/test/cases/migration/column_positioning_test.rb
  92. +1 −2  activerecord/test/cases/migration/create_join_table_test.rb
  93. +1 −2  activerecord/test/cases/migration/index_test.rb
  94. +1 −2  activerecord/test/cases/migration/logger_test.rb
  95. +1 −2  activerecord/test/cases/migration/references_index_test.rb
  96. +2 −2 activerecord/test/cases/migration_test.rb
  97. +1 −2  activerecord/test/cases/migrator_test.rb
  98. +1 −1  activerecord/test/cases/modules_test.rb
  99. +13 −29 activerecord/test/cases/nested_attributes_test.rb
  100. +1 −1  activerecord/test/cases/pooled_connections_test.rb
  101. +8 −0 activerecord/test/cases/query_cache_test.rb
  102. +12 −8 activerecord/test/cases/reaper_test.rb
  103. +2 −2 activerecord/test/cases/relation/predicate_builder_test.rb
  104. +4 −4 activerecord/test/cases/relation/where_chain_test.rb
  105. +8 −0 activerecord/test/cases/relations_test.rb
  106. +3 −2 activerecord/test/cases/scoping/relation_scoping_test.rb
  107. +1 −2  activerecord/test/cases/serialized_attribute_test.rb
  108. +12 −0 activerecord/test/cases/timestamp_test.rb
  109. +1 −1  activerecord/test/cases/unconnected_test.rb
  110. +1 −1  activerecord/test/cases/validations/i18n_validation_test.rb
  111. +3 −0  activerecord/test/fixtures/pirates.yml
  112. +13 −0 activerecord/test/models/person.rb
  113. +1 −0  activerecord/test/models/treasure.rb
  114. +8 −0 activerecord/test/support/ddl_helper.rb
  115. +9 −0 activesupport/CHANGELOG.md
  116. +5 −4 activesupport/lib/active_support/cache/strategy/local_cache.rb
  117. +3 −5 activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
  118. +4 −0 activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
  119. +1 −2  activesupport/lib/active_support/core_ext/hash/conversions.rb
  120. +1 −1  activesupport/lib/active_support/core_ext/object/json.rb
  121. +1 −1  activesupport/lib/active_support/core_ext/object/to_json.rb
  122. +1 −2  activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
  123. +28 −6 activesupport/test/core_ext/class/delegating_attributes_test.rb
  124. +33 −10 activesupport/test/json/encoding_test.rb
  125. +3 −0  activesupport/test/number_helper_test.rb
  126. +12 −4 guides/source/4_1_release_notes.md
  127. +24 −0 guides/source/action_controller_overview.md
  128. +1 −1  guides/source/active_record_querying.md
  129. +7 −1 guides/source/command_line.md
  130. +1 −1  guides/source/configuring.md
  131. +29 −12 guides/source/getting_started.md
  132. +24 −0 guides/source/upgrading_ruby_on_rails.md
  133. +12 −0 railties/CHANGELOG.md
  134. +4 −0 railties/lib/rails/application/configuration.rb
  135. +1 −1  railties/lib/rails/commands/commands_tasks.rb
  136. +1 −1  railties/lib/rails/generators/actions/create_migration.rb
  137. +5 −1 railties/lib/rails/generators/app_base.rb
  138. +4 −0 railties/lib/rails/generators/generated_attribute.rb
  139. +1 −1  railties/lib/rails/generators/rails/app/app_generator.rb
  140. +2 −0  railties/lib/rails/generators/rails/app/templates/gitignore
  141. +1 −1  railties/lib/rails/info.rb
  142. +22 −15 railties/lib/rails/source_annotation_extractor.rb
  143. +10 −0 railties/test/application/configuration_test.rb
  144. +37 −40 railties/test/application/rake/dbs_test.rb
  145. +48 −77 railties/test/application/rake/notes_test.rb
  146. +25 −1 railties/test/generators/app_generator_test.rb
  147. +50 −0 railties/test/generators/migration_generator_test.rb
  148. +4 −4 railties/test/generators/plugin_generator_test.rb
  149. +3 −3 tasks/release.rb
View
8 actionmailer/test/base_test.rb
@@ -594,7 +594,7 @@ def welcome
test "you can register a preview interceptor to the mail object that gets passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptor(MyInterceptor)
mail = BaseMailer.welcome
- BaseMailerPreview.stubs(:welcome).returns(mail)
+ BaseMailerPreview.any_instance.stubs(:welcome).returns(mail)
MyInterceptor.expects(:previewing_email).with(mail)
BaseMailerPreview.call(:welcome)
end
@@ -602,7 +602,7 @@ def welcome
test "you can register a preview interceptor using its stringified name to the mail object that gets passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptor("BaseTest::MyInterceptor")
mail = BaseMailer.welcome
- BaseMailerPreview.stubs(:welcome).returns(mail)
+ BaseMailerPreview.any_instance.stubs(:welcome).returns(mail)
MyInterceptor.expects(:previewing_email).with(mail)
BaseMailerPreview.call(:welcome)
end
@@ -610,7 +610,7 @@ def welcome
test "you can register an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptor(:"base_test/my_interceptor")
mail = BaseMailer.welcome
- BaseMailerPreview.stubs(:welcome).returns(mail)
+ BaseMailerPreview.any_instance.stubs(:welcome).returns(mail)
MyInterceptor.expects(:previewing_email).with(mail)
BaseMailerPreview.call(:welcome)
end
@@ -618,7 +618,7 @@ def welcome
test "you can register multiple preview interceptors to the mail object that both get passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptors("BaseTest::MyInterceptor", MySecondInterceptor)
mail = BaseMailer.welcome
- BaseMailerPreview.stubs(:welcome).returns(mail)
+ BaseMailerPreview.any_instance.stubs(:welcome).returns(mail)
MyInterceptor.expects(:previewing_email).with(mail)
MySecondInterceptor.expects(:previewing_email).with(mail)
BaseMailerPreview.call(:welcome)
View
15 actionpack/CHANGELOG.md
@@ -1,3 +1,18 @@
+* Swapped the parameters of assert_equal in `assert_select` so that the
+ proper values were printed correctly
+
+ Fixes #14422.
+
+ *Vishal Lal*
+
+* The method `shallow?` returns false if the parent resource is a singleton so
+ we need to check if we're not inside a nested scope before copying the :path
+ and :as options to their shallow equivalents.
+
+ Fixes #14388.
+
+ *Andrew White*
+
* Make logging of CSRF failures optional (but on by default) with the
`log_warning_on_csrf_failure` configuration setting in
`ActionController::RequestForgeryProtection`.
View
21 actionpack/lib/action_controller/metal/live.rb
@@ -228,18 +228,19 @@ def process(name)
begin
super(name)
rescue => e
- unless @_response.committed?
+ if @_response.committed?
+ begin
+ @_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html
+ @_response.stream.call_on_error
+ rescue => exception
+ log_error(exception)
+ ensure
+ log_error(e)
+ @_response.stream.close
+ end
+ else
error = e
end
- begin
- @_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html
- @_response.stream.call_on_error
- rescue => exception
- log_error(exception)
- ensure
- log_error(e)
- @_response.stream.close
- end
ensure
@_response.commit!
end
View
4 actionpack/lib/action_controller/test_case.rb
@@ -486,8 +486,8 @@ def prepare_controller_class(new_class)
# - +session+: A hash of parameters to store in the session. This may be +nil+.
# - +flash+: A hash of parameters to store in the flash. This may be +nil+.
#
- # You can also simulate POST, PATCH, PUT, DELETE, HEAD, and OPTIONS requests with
- # +post+, +patch+, +put+, +delete+, +head+, and +options+.
+ # You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
+ # +post+, +patch+, +put+, +delete+, and +head+.
#
# Note that the request method is not verified. The different methods are
# available to make the tests more expressive.
View
2  actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -51,7 +51,7 @@ module Session
# decode signed cookies generated by your app in external applications or
# Javascript before upgrading.
#
- # Note that changing digest or secret invalidates all existing sessions!
+ # Note that changing the secret key will invalidate all existing sessions!
class CookieStore < Rack::Session::Abstract::ID
include Compatibility
include StaleSessionCheck
View
6 actionpack/lib/action_dispatch/routing/mapper.rb
@@ -707,7 +707,7 @@ def scope(*args)
options[:path] = args.flatten.join('/') if args.any?
options[:constraints] ||= {}
- unless shallow?
+ unless nested_scope?
options[:shallow_path] ||= options[:path] if options.key?(:path)
options[:shallow_prefix] ||= options[:as] if options.key?(:as)
end
@@ -1547,6 +1547,10 @@ def resource_method_scope? #:nodoc:
RESOURCE_METHOD_SCOPES.include? @scope[:scope_level]
end
+ def nested_scope? #:nodoc:
+ @scope[:scope_level] == :nested
+ end
+
def with_exclusive_scope
begin
old_name_prefix, old_path = @scope[:as], @scope[:path]
View
2  actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -291,7 +291,7 @@ def assert_select(*args, &block)
# so is this custom message really needed?
message = message || %(Expected #{count_description(min, max, count)} matching "#{selector.to_s}", found #{matches.size}.)
if count
- assert_equal matches.size, count, message
+ assert_equal count, matches.size, message
else
assert_operator matches.size, :>=, min, message if min
assert_operator matches.size, :<=, max, message if max
View
35 actionpack/test/controller/caching_test.rb
@@ -164,6 +164,13 @@ def formatted_fragment_cached
end
end
+ def formatted_fragment_cached_with_variant
+ respond_to do |format|
+ format.html.phone
+ format.html
+ end
+ end
+
def fragment_cached_without_digest
end
end
@@ -190,7 +197,7 @@ def test_fragment_caching
assert_equal expected_body, @response.body
assert_equal "This bit's fragment cached",
- @store.read("views/test.host/functional_caching/fragment_cached/#{template_digest("functional_caching/fragment_cached", "html")}")
+ @store.read("views/test.host/functional_caching/fragment_cached/#{template_digest("functional_caching/fragment_cached")}")
end
def test_fragment_caching_in_partials
@@ -199,7 +206,7 @@ def test_fragment_caching_in_partials
assert_match(/Old fragment caching in a partial/, @response.body)
assert_match("Old fragment caching in a partial",
- @store.read("views/test.host/functional_caching/html_fragment_cached_with_partial/#{template_digest("functional_caching/_partial", "html")}"))
+ @store.read("views/test.host/functional_caching/html_fragment_cached_with_partial/#{template_digest("functional_caching/_partial")}"))
end
def test_skipping_fragment_cache_digesting
@@ -217,7 +224,7 @@ def test_render_inline_before_fragment_caching
assert_match(/Some inline content/, @response.body)
assert_match(/Some cached content/, @response.body)
assert_match("Some cached content",
- @store.read("views/test.host/functional_caching/inline_fragment_cached/#{template_digest("functional_caching/inline_fragment_cached", "html")}"))
+ @store.read("views/test.host/functional_caching/inline_fragment_cached/#{template_digest("functional_caching/inline_fragment_cached")}"))
end
def test_html_formatted_fragment_caching
@@ -228,7 +235,7 @@ def test_html_formatted_fragment_caching
assert_equal expected_body, @response.body
assert_equal "<p>ERB</p>",
- @store.read("views/test.host/functional_caching/formatted_fragment_cached/#{template_digest("functional_caching/formatted_fragment_cached", "html")}")
+ @store.read("views/test.host/functional_caching/formatted_fragment_cached/#{template_digest("functional_caching/formatted_fragment_cached")}")
end
def test_xml_formatted_fragment_caching
@@ -239,12 +246,26 @@ def test_xml_formatted_fragment_caching
assert_equal expected_body, @response.body
assert_equal " <p>Builder</p>\n",
- @store.read("views/test.host/functional_caching/formatted_fragment_cached/#{template_digest("functional_caching/formatted_fragment_cached", "xml")}")
+ @store.read("views/test.host/functional_caching/formatted_fragment_cached/#{template_digest("functional_caching/formatted_fragment_cached")}")
+ end
+
+
+ def test_fragment_caching_with_variant
+ @request.variant = :phone
+
+ get :formatted_fragment_cached_with_variant, :format => "html"
+ assert_response :success
+ expected_body = "<body>\n<p>PHONE</p>\n</body>\n"
+
+ assert_equal expected_body, @response.body
+
+ assert_equal "<p>PHONE</p>",
+ @store.read("views/test.host/functional_caching/formatted_fragment_cached_with_variant/#{template_digest("functional_caching/formatted_fragment_cached_with_variant")}")
end
private
- def template_digest(name, format, variant = nil)
- ActionView::Digestor.digest(name: name, format: format, variant: variant, finder: @controller.lookup_context)
+ def template_digest(name)
+ ActionView::Digestor.digest(name: name, finder: @controller.lookup_context)
end
end
View
19 actionpack/test/controller/live_stream_test.rb
@@ -153,6 +153,11 @@ def exception_in_view
render 'doesntexist'
end
+ def exception_in_view_after_commit
+ response.stream.write ""
+ render 'doesntexist'
+ end
+
def exception_with_callback
response.headers['Content-Type'] = 'text/event-stream'
@@ -269,6 +274,13 @@ def test_exception_handling_html
assert_raises(ActionView::MissingTemplate) do
get :exception_in_view
end
+
+ capture_log_output do |output|
+ get :exception_in_view_after_commit
+ assert_match %r((window\.location = "/500\.html"</script></html>)$), response.body
+ assert_match 'Missing template test/doesntexist', output.rewind && output.read
+ assert_stream_closed
+ end
assert response.body
assert_stream_closed
end
@@ -277,6 +289,13 @@ def test_exception_handling_plain_text
assert_raises(ActionView::MissingTemplate) do
get :exception_in_view, format: :json
end
+
+ capture_log_output do |output|
+ get :exception_in_view_after_commit, format: :json
+ assert_equal '', response.body
+ assert_match 'Missing template test/doesntexist', output.rewind && output.read
+ assert_stream_closed
+ end
end
def test_exception_callback_when_committed
View
41 actionpack/test/dispatch/request/session_test.rb
@@ -36,29 +36,55 @@ def test_find
assert_equal s, Session.find(env)
end
+ def test_destroy
+ s = Session.create(store, {}, {})
+ s['rails'] = 'ftw'
+
+ s.destroy
+
+ assert_empty s
+ end
+
def test_keys
- env = {}
- s = Session.create(store, env, {})
+ s = Session.create(store, {}, {})
s['rails'] = 'ftw'
s['adequate'] = 'awesome'
assert_equal %w[rails adequate], s.keys
end
def test_values
- env = {}
- s = Session.create(store, env, {})
+ s = Session.create(store, {}, {})
s['rails'] = 'ftw'
s['adequate'] = 'awesome'
assert_equal %w[ftw awesome], s.values
end
def test_clear
- env = {}
- s = Session.create(store, env, {})
+ s = Session.create(store, {}, {})
s['rails'] = 'ftw'
s['adequate'] = 'awesome'
+
s.clear
- assert_equal([], s.values)
+ assert_empty(s.values)
+ end
+
+ def test_update
+ s = Session.create(store, {}, {})
+ s['rails'] = 'ftw'
+
+ s.update(:rails => 'awesome')
+
+ assert_equal(['rails'], s.keys)
+ assert_equal('awesome', s['rails'])
+ end
+
+ def test_delete
+ s = Session.create(store, {}, {})
+ s['rails'] = 'ftw'
+
+ s.delete('rails')
+
+ assert_empty(s.keys)
end
def test_fetch
@@ -82,6 +108,7 @@ def store
Class.new {
def load_session(env); [1, {}]; end
def session_exists?(env); true; end
+ def destroy_session(env, id, options); 123; end
}.new
end
end
View
36 actionpack/test/dispatch/routing_test.rb
@@ -1958,6 +1958,42 @@ def test_shallow_nested_resources
assert_equal '/comments/3/preview', preview_comment_path(:id => '3')
end
+ def test_shallow_nested_resources_inside_resource
+ draw do
+ resource :membership, shallow: true do
+ resources :cards
+ end
+ end
+
+ get '/membership/cards'
+ assert_equal 'cards#index', @response.body
+ assert_equal '/membership/cards', membership_cards_path
+
+ get '/membership/cards/new'
+ assert_equal 'cards#new', @response.body
+ assert_equal '/membership/cards/new', new_membership_card_path
+
+ post '/membership/cards'
+ assert_equal 'cards#create', @response.body
+
+ get '/cards/1'
+ assert_equal 'cards#show', @response.body
+ assert_equal '/cards/1', card_path('1')
+
+ get '/cards/1/edit'
+ assert_equal 'cards#edit', @response.body
+ assert_equal '/cards/1/edit', edit_card_path('1')
+
+ put '/cards/1'
+ assert_equal 'cards#update', @response.body
+
+ patch '/cards/1'
+ assert_equal 'cards#update', @response.body
+
+ delete '/cards/1'
+ assert_equal 'cards#destroy', @response.body
+ end
+
def test_shallow_nested_resources_within_scope
draw do
scope '/hello' do
View
3  actionpack/test/dispatch/session/mem_cache_store_test.rb
@@ -1,4 +1,5 @@
require 'abstract_unit'
+require 'securerandom'
# You need to start a memcached server inorder to run these tests
class MemCacheStoreTest < ActionDispatch::IntegrationTest
@@ -172,7 +173,7 @@ def with_test_route_set
end
@app = self.class.build_app(set) do |middleware|
- middleware.use ActionDispatch::Session::MemCacheStore, :key => '_session_id'
+ middleware.use ActionDispatch::Session::MemCacheStore, :key => '_session_id', :namespace => "mem_cache_store_test:#{SecureRandom.hex(10)}"
middleware.delete "ActionDispatch::ShowExceptions"
end
View
3  actionpack/test/fixtures/functional_caching/formatted_fragment_cached_with_variant.html+phone.erb
@@ -0,0 +1,3 @@
+<body>
+<%= cache do %><p>PHONE</p><% end %>
+</body>
View
15 actionview/CHANGELOG.md
@@ -1,3 +1,18 @@
+* `date_select` helper with option `with_css_classes: true` does not overwrite other classes.
+
+ *Izumi Wong-Horiuchi*
+
+* `number_to_percentage` does not crash with `Float::NAN` or `Float::INFINITY`
+ as input.
+
+ Fixes #14405.
+
+ *Yves Senn*
+
+* Add `include_hidden` option to `collection_check_boxes` helper.
+
+ *Vasiliy Ermolovich*
+
* Fixed a problem where the default options for the `button_tag` helper is not
applied correctly.
View
90 actionview/lib/action_view/digestor.rb
@@ -12,22 +12,13 @@ class << self
# Supported options:
#
# * <tt>name</tt> - Template name
- # * <tt>format</tt> - Template format
- # * <tt>variant</tt> - Variant of +format+ (optional)
# * <tt>finder</tt> - An instance of ActionView::LookupContext
# * <tt>dependencies</tt> - An array of dependent views
# * <tt>partial</tt> - Specifies whether the template is a partial
- def digest(*args)
- options = _setup_options(*args)
+ def digest(options)
+ options.assert_valid_keys(:name, :finder, :dependencies, :partial)
- name = options[:name]
- format = options[:format]
- variant = options[:variant]
- finder = options[:finder]
-
- details_key = finder.details_key.hash
- dependencies = Array.wrap(options[:dependencies])
- cache_key = ([name, details_key, format, variant].compact + dependencies).join('.')
+ cache_key = ([ options[:name], options[:finder].details_key.hash ].compact + Array.wrap(options[:dependencies])).join('.')
# this is a correctly done double-checked locking idiom
# (ThreadSafe::Cache's lookups have volatile semantics)
@@ -38,63 +29,41 @@ def digest(*args)
end
end
- def _setup_options(*args)
- unless args.first.is_a?(Hash)
- ActiveSupport::Deprecation.warn("Arguments to ActionView::Digestor should be provided as a hash. The support for regular arguments will be removed in Rails 5.0 or later")
-
- {
- name: args.first,
- format: args.second,
- finder: args.third,
- }.merge(args.fourth || {})
- else
- options = args.first
- options.assert_valid_keys(:name, :format, :variant, :finder, :dependencies, :partial)
-
- options
- end
- end
-
private
+ def compute_and_store_digest(cache_key, options) # called under @@digest_monitor lock
+ klass = if options[:partial] || options[:name].include?("/_")
+ # Prevent re-entry or else recursive templates will blow the stack.
+ # There is no need to worry about other threads seeing the +false+ value,
+ # as they will then have to wait for this thread to let go of the @@digest_monitor lock.
+ pre_stored = @@cache.put_if_absent(cache_key, false).nil? # put_if_absent returns nil on insertion
+ PartialDigestor
+ else
+ Digestor
+ end
- def compute_and_store_digest(cache_key, options) # called under @@digest_monitor lock
- klass = if options[:partial] || options[:name].include?("/_")
- # Prevent re-entry or else recursive templates will blow the stack.
- # There is no need to worry about other threads seeing the +false+ value,
- # as they will then have to wait for this thread to let go of the @@digest_monitor lock.
- pre_stored = @@cache.put_if_absent(cache_key, false).nil? # put_if_absent returns nil on insertion
- PartialDigestor
- else
- Digestor
+ digest = klass.new(options).digest
+ # Store the actual digest if config.cache_template_loading is true
+ @@cache[cache_key] = stored_digest = digest if ActionView::Resolver.caching?
+ digest
+ ensure
+ # something went wrong or ActionView::Resolver.caching? is false, make sure not to corrupt the @@cache
+ @@cache.delete_pair(cache_key, false) if pre_stored && !stored_digest
end
-
- digest = klass.new(options).digest
- # Store the actual digest if config.cache_template_loading is true
- @@cache[cache_key] = stored_digest = digest if ActionView::Resolver.caching?
- digest
- ensure
- # something went wrong or ActionView::Resolver.caching? is false, make sure not to corrupt the @@cache
- @@cache.delete_pair(cache_key, false) if pre_stored && !stored_digest
- end
end
- attr_reader :name, :format, :variant, :finder, :options
+ attr_reader :name, :finder, :options
- def initialize(*args)
- @options = self.class._setup_options(*args)
-
- @name = @options.delete(:name)
- @format = @options.delete(:format)
- @variant = @options.delete(:variant)
- @finder = @options.delete(:finder)
+ def initialize(options)
+ @name, @finder = options.values_at(:name, :finder)
+ @options = options.except(:name, :finder)
end
def digest
Digest::MD5.hexdigest("#{source}-#{dependency_digest}").tap do |digest|
- logger.try :info, "Cache digest for #{name}.#{format}: #{digest}"
+ logger.try :info, " Cache digest for #{template.inspect}: #{digest}"
end
rescue ActionView::MissingTemplate
- logger.try :error, "Couldn't find template for digesting: #{name}.#{format}"
+ logger.try :error, " Couldn't find template for digesting: #{name}"
''
end
@@ -106,13 +75,12 @@ def dependencies
def nested_dependencies
dependencies.collect do |dependency|
- dependencies = PartialDigestor.new(name: dependency, format: format, finder: finder).nested_dependencies
+ dependencies = PartialDigestor.new(name: dependency, finder: finder).nested_dependencies
dependencies.any? ? { dependency => dependencies } : dependency
end
end
private
-
def logger
ActionView::Base.logger
end
@@ -126,7 +94,7 @@ def partial?
end
def template
- @template ||= finder.find(logical_name, [], partial?, formats: [ format ], variants: [ variant ])
+ @template ||= finder.disable_cache { finder.find(logical_name, [], partial?) }
end
def source
@@ -135,7 +103,7 @@ def source
def dependency_digest
template_digests = dependencies.collect do |template_name|
- Digestor.digest(name: template_name, format: format, finder: finder, partial: true)
+ Digestor.digest(name: template_name, finder: finder, partial: true)
end
(template_digests + injected_dependencies).join("-")
View
8 actionview/lib/action_view/helpers/cache_helper.rb
@@ -165,10 +165,10 @@ def cache_fragment_name(name = {}, options = nil)
def fragment_name_with_digest(name) #:nodoc:
if @virtual_path
- [
- *Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name),
- Digestor.digest(name: @virtual_path, format: formats.last.to_sym, variant: request.variant, finder: lookup_context, dependencies: view_cache_dependencies)
- ]
+ names = Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name)
+ digest = Digestor.digest name: @virtual_path, finder: lookup_context, dependencies: view_cache_dependencies
+
+ [ *names, digest ]
else
name
end
View
2  actionview/lib/action_view/helpers/date_helper.rb
@@ -965,7 +965,7 @@ def build_select(type, select_options_as_html)
:name => input_name_from_type(type)
}.merge!(@html_options)
select_options[:disabled] = 'disabled' if @options[:disabled]
- select_options[:class] = type if @options[:with_css_classes]
+ select_options[:class] = [select_options[:class], type].compact.join(' ') if @options[:with_css_classes]
select_html = "\n"
select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
View
10 actionview/lib/action_view/helpers/tags/collection_check_boxes.rb
@@ -27,10 +27,14 @@ def render(&block)
# Append a hidden field to make sure something will be sent back to the
# server if all check boxes are unchecked.
- hidden_name = @html_options[:name] || "#{tag_name}[]"
- hidden = @template_object.hidden_field_tag(hidden_name, "", :id => nil)
+ if @options.fetch(:include_hidden, true)
+ hidden_name = @html_options[:name] || "#{tag_name}[]"
+ hidden = @template_object.hidden_field_tag(hidden_name, "", :id => nil)
- rendered_collection + hidden
+ rendered_collection + hidden
+ else
+ rendered_collection
+ end
end
private
View
20 actionview/lib/action_view/helpers/url_helper.rb
@@ -389,15 +389,7 @@ def link_to_unless_current(name, options = {}, html_options = {}, &block)
# # If not...
# # => <a href="/accounts/signup">Reply</a>
def link_to_unless(condition, name, options = {}, html_options = {}, &block)
- if condition
- if block_given?
- block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
- else
- ERB::Util.html_escape(name)
- end
- else
- link_to(name, options, html_options)
- end
+ link_to_if !condition, name, options, html_options, &block
end
# Creates a link tag of the given +name+ using a URL created by the set of
@@ -421,7 +413,15 @@ def link_to_unless(condition, name, options = {}, html_options = {}, &block)
# # If they are logged in...
# # => <a href="/accounts/show/3">my_username</a>
def link_to_if(condition, name, options = {}, html_options = {}, &block)
- link_to_unless !condition, name, options, html_options, &block
+ if condition
+ link_to(name, options, html_options)
+ else
+ if block_given?
+ block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
+ else
+ ERB::Util.html_escape(name)
+ end
+ end
end
# Creates a mailto link tag to the specified +email_address+, which is
View
9 actionview/lib/action_view/lookup_context.rb
@@ -159,7 +159,14 @@ def args_for_lookup(name, prefixes, partial, keys, details_options) #:nodoc:
def detail_args_for(options)
return @details, details_key if options.empty? # most common path.
user_details = @details.merge(options)
- [user_details, DetailsKey.get(user_details)]
+
+ if @cache
+ details_key = DetailsKey.get(user_details)
+ else
+ details_key = nil
+ end
+
+ [user_details, details_key]
end
# Support legacy foo.erb names even though we now ignore .erb
View
3  actionview/lib/action_view/template.rb
@@ -97,7 +97,7 @@ class Template
extend Template::Handlers
- attr_accessor :locals, :formats, :virtual_path
+ attr_accessor :locals, :formats, :variants, :virtual_path
attr_reader :source, :identifier, :handler, :original_encoding, :updated_at
@@ -123,6 +123,7 @@ def initialize(source, identifier, handler, details)
@virtual_path = details[:virtual_path]
@updated_at = details[:updated_at] || Time.now
@formats = Array(format).map { |f| f.respond_to?(:ref) ? f.ref : f }
+ @variants = [details[:variant]]
@compile_mutex = Mutex.new
end
View
17 actionview/lib/action_view/template/resolver.rb
@@ -154,7 +154,8 @@ def decorate(templates, path_info, details, locals) #:nodoc:
cached = nil
templates.each do |t|
t.locals = locals
- t.formats = details[:formats] || [:html] if t.formats.empty?
+ t.formats = details[:formats] || [:html] if t.formats.empty?
+ t.variants = details[:variants] || [] if t.variants.empty?
t.virtual_path ||= (cached ||= build_path(*path_info))
end
end
@@ -189,13 +190,15 @@ def query(path, details, formats)
}
template_paths.map { |template|
- handler, format = extract_handler_and_format(template, formats)
- contents = File.binread template
+ handler, format, variant = extract_handler_and_format_and_variant(template, formats)
+ contents = File.binread(template)
Template.new(contents, File.expand_path(template), handler,
:virtual_path => path.virtual,
:format => format,
- :updated_at => mtime(template))
+ :variant => variant,
+ :updated_at => mtime(template)
+ )
}
end
@@ -228,7 +231,7 @@ def mtime(p)
# Extract handler and formats from path. If a format cannot be a found neither
# from the path, or the handler, we should return the array of formats given
# to the resolver.
- def extract_handler_and_format(path, default_formats)
+ def extract_handler_and_format_and_variant(path, default_formats)
pieces = File.basename(path).split(".")
pieces.shift
@@ -240,10 +243,10 @@ def extract_handler_and_format(path, default_formats)
end
handler = Template.handler_for_extension(extension)
- format = pieces.last && pieces.last.split(EXTENSIONS[:variants], 2).first # remove variant from format
+ format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last
format &&= Template::Types[format]
- [handler, format]
+ [handler, format, variant]
end
end
View
12 actionview/lib/action_view/testing/resolvers.rb
@@ -30,9 +30,13 @@ def query(path, exts, formats)
@hash.each do |_path, array|
source, updated_at = array
next unless _path =~ query
- handler, format = extract_handler_and_format(_path, formats)
+ handler, format, variant = extract_handler_and_format_and_variant(_path, formats)
templates << Template.new(source, _path, handler,
- :virtual_path => path.virtual, :format => format, :updated_at => updated_at)
+ :virtual_path => path.virtual,
+ :format => format,
+ :variant => variant,
+ :updated_at => updated_at
+ )
end
templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
@@ -41,8 +45,8 @@ def query(path, exts, formats)
class NullResolver < PathResolver
def query(path, exts, formats)
- handler, format = extract_handler_and_format(path, formats)
- [ActionView::Template.new("Template generated by Null Resolver", path, handler, :virtual_path => path, :format => format)]
+ handler, format, variant = extract_handler_and_format_and_variant(path, formats)
+ [ActionView::Template.new("Template generated by Null Resolver", path, handler, :virtual_path => path, :format => format, :variant => variant)]
end
end
View
1  actionview/test/fixtures/test/hello_world.html+phone.erb
@@ -0,0 +1 @@
+Hello phone!
View
1  actionview/test/fixtures/test/hello_world.text+phone.erb
@@ -0,0 +1 @@
+Hello texty phone!
View
16 actionview/test/template/date_helper_test.rb
@@ -1040,6 +1040,22 @@ def test_select_date_with_css_classes_option
assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), {:start_year => 2003, :end_year => 2005, :prefix => "date[first]", :with_css_classes => true})
end
+ def test_select_date_with_css_classes_option_and_html_class_option
+ expected = %(<select id="date_first_year" name="date[first][year]" class="datetime optional 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]" class="datetime optional 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]" class="datetime optional 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"
+
+ assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), {:start_year => 2003, :end_year => 2005, :prefix => "date[first]", :with_css_classes => true}, { class: 'datetime optional' })
+ end
+
def test_select_datetime
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)
View
36 actionview/test/template/digestor_test.rb
@@ -15,23 +15,31 @@ def initialize(template_path)
class FixtureFinder
FIXTURES_DIR = "#{File.dirname(__FILE__)}/../fixtures/digestor"
- attr_reader :details
+ attr_reader :details
+ attr_accessor :formats
+ attr_accessor :variants
def initialize
- @details = {}
+ @details = {}
+ @formats = []
+ @variants = []
end
def details_key
details.hash
end
- def find(logical_name, keys, partial, options)
- partial_name = partial ? logical_name.gsub(%r|/([^/]+)$|, '/_\1') : logical_name
- format = options[:formats].first.to_s
- format += "+#{options[:variants].first}" if options[:variants].any?
+ def find(name, prefixes = [], partial = false, keys = [], options = {})
+ partial_name = partial ? name.gsub(%r|/([^/]+)$|, '/_\1') : name
+ format = @formats.first.to_s
+ format += "+#{@variants.first}" if @variants.any?
FixtureTemplate.new("digestor/#{partial_name}.#{format}.erb")
end
+
+ def disable_cache(&block)
+ yield
+ end
end
class TemplateDigestorTest < ActionView::TestCase
@@ -92,13 +100,13 @@ def test_directory_depth_dependency
end
def test_logging_of_missing_template
- assert_logged "Couldn't find template for digesting: messages/something_missing.html" do
+ assert_logged "Couldn't find template for digesting: messages/something_missing" do
digest("messages/show")
end
end
def test_logging_of_missing_template_ending_with_number
- assert_logged "Couldn't find template for digesting: messages/something_missing_1.html" do
+ assert_logged "Couldn't find template for digesting: messages/something_missing_1" do
digest("messages/show")
end
end
@@ -199,7 +207,7 @@ def test_old_style_hash_in_render_invocation
end
def test_variants
- assert_digest_difference("messages/new", false, variant: :iphone) do
+ assert_digest_difference("messages/new", false, variants: [:iphone]) do
change_template("messages/new", :iphone)
change_template("messages/_header", :iphone)
end
@@ -253,10 +261,6 @@ def test_digest_cache_cleanup_with_recursion_and_template_caching_off
ActionView::Resolver.caching = resolver_before
end
- def test_arguments_deprecation
- assert_deprecated(/should be provided as a hash/) { ActionView::Digestor.digest('messages/show', :html, finder) }
- assert_deprecated(/should be provided as a hash/) { ActionView::Digestor.new('messages/show', :html, finder) }
- end
private
def assert_logged(message)
@@ -286,7 +290,11 @@ def assert_digest_difference(template_name, persistent = false, options = {})
def digest(template_name, options = {})
options = options.dup
- ActionView::Digestor.digest({ name: template_name, format: :html, finder: finder }.merge(options))
+
+ finder.formats = [:html]
+ finder.variants = options.delete(:variants) || []
+
+ ActionView::Digestor.digest({ name: template_name, finder: finder }.merge(options))
end
def finder
View
7 actionview/test/template/form_collections_helper_test.rb
@@ -204,6 +204,13 @@ def with_collection_check_boxes(*args, &block)
assert_select "input[type=hidden][name='user[other_category_ids][]'][value=]", :count => 1
end
+ test 'collection check boxes does not generate a hidden field if include_hidden option is false' do
+ collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
+ with_collection_check_boxes :user, :category_ids, collection, :id, :name, include_hidden: false
+
+ assert_select "input[type=hidden][name='user[category_ids][]'][value=]", :count => 0
+ end
+
test 'collection check boxes accepts a collection and generate a series of checkboxes with labels for label method' do
collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
with_collection_check_boxes :user, :category_ids, collection, :id, :name
View
14 actionview/test/template/lookup_context_test.rb
@@ -93,6 +93,20 @@ def teardown
assert_equal "Hey verden", template.source
end
+ test "find templates with given variants" do
+ @lookup_context.formats = [:html]
+ @lookup_context.variants = [:phone]
+
+ template = @lookup_context.find("hello_world", %w(test))
+ assert_equal "Hello phone!", template.source
+
+ @lookup_context.variants = [:phone]
+ @lookup_context.formats = [:text]
+
+ template = @lookup_context.find("hello_world", %w(test))
+ assert_equal "Hello texty phone!", template.source
+ end
+
test "found templates respects given formats if one cannot be found from template or handler" do
ActionView::Template::Handlers::Builder.expects(:default_format).returns(nil)
@lookup_context.formats = [:text]
View
3  actionview/test/template/number_helper_test.rb
@@ -32,6 +32,9 @@ def test_number_to_percentage
assert_equal "100%", number_to_percentage(100, precision: 0)
assert_equal "123.4%", number_to_percentage(123.400, precision: 3, strip_insignificant_zeros: true)
assert_equal "1.000,000%", number_to_percentage(1000, delimiter: ".", separator: ",")
+ assert_equal "98a%", number_to_percentage("98a")
+ assert_equal "NaN%", number_to_percentage(Float::NAN)
+ assert_equal "Inf%", number_to_percentage(Float::INFINITY)
end
def test_number_with_delimiter
View
71 activerecord/CHANGELOG.md
@@ -1,14 +1,73 @@
-* Passing an Active Record object to `find` is now deprecated. Call `.id`
- on the object first.
+* Use singular table name in generated migrations when
+ `ActiveRecord::Base.pluralize_table_names` is `false`.
-* Passing an Active Record object to `exists?` is now deprecated. Call `.id`
- on the object first.
+ Fixes #13426.
-* Only use BINARY for mysql case sensitive uniqueness check when column has a case insensitive collation.
+ *Kuldeep Aggarwal*
+
+* `touch` accepts many attributes to be touched at once.
+
+ Example:
+
+ # touches :signed_at, :sealed_at, and :updated_at/on attributes.
+ Photo.last.touch(:signed_at, :sealed_at)
+
+ *James Pinto*
+
+* `rake db:structure:dump` only dumps schema information if the schema
+ migration table exists.
+
+ Fixes #14217.
+
+ *Yves Senn*
+
+* Reap connections that were checked out by now-dead threads, instead
+ of waiting until they disconnect by themselves. Before this change,
+ a suitably constructed series of short-lived threads could starve
+ the connection pool, without ever having more than a couple alive at
+ the same time.
+
+ *Matthew Draper*
+
+* `pk_and_sequence_for` now ensures that only the pg_depend entries
+ pointing to pg_class, and thus only sequence objects, are considered.
+
+ *Josh Williams*
+
+* `where.not` adds `references` for `includes` like normal `where` calls do.
+
+ Fixes #14406.
+
+ *Yves Senn*
+
+* Extend fixture `$LABEL` replacement to allow string interpolation.
+
+ Example:
+
+ martin:
+ email: $LABEL@email.com
+
+ users(:martin).email # => martin@email.com
+
+ *Eric Steele*
+
+* Add support for `Relation` be passed as parameter on `QueryCache#select_all`.
+
+ Fixes #14361.
+
+ *arthurnn*
+
+* Passing an Active Record object to `find` is now deprecated. Call `.id`
+ on the object first.
+
+* Passing an Active Record object to `find` or `exists?` is now deprecated.
+ Call `.id` on the object first.
+
+* Only use BINARY for MySQL case sensitive uniqueness check when column has a case insensitive collation.
*Ryuta Kamizono*
-* Support for Mysql 5.6 Fractional Seconds.
+* Support for MySQL 5.6 fractional seconds.
*arthurnn*, *Tatsuhiko Miyagawa*
View
2  activerecord/lib/active_record/associations.rb
@@ -1584,7 +1584,7 @@ def destroy_associations
hm_options[:through] = middle_reflection.name
hm_options[:source] = join_model.right_reflection.name
- [:before_add, :after_add, :before_remove, :after_remove, :autosave].each do |k|
+ [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate].each do |k|
hm_options[k] = options[k] if options.key? k
end
View
3  activerecord/lib/active_record/associations/collection_association.rb
@@ -145,9 +145,8 @@ def create!(attributes = {}, &block)
# be chained. Since << flattens its argument list and inserts each record,
# +push+ and +concat+ behave identically.
def concat(*records)
- load_target if owner.new_record?
-
if owner.new_record?
+ load_target
concat_records(records)
else
transaction { concat_records(records) }
View
56 activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -58,13 +58,11 @@ module ConnectionAdapters
# * +checkout_timeout+: number of seconds to block and wait for a connection
# before giving up and raising a timeout error (default 5 seconds).
# * +reaping_frequency+: frequency in seconds to periodically run the
- # Reaper, which attempts to find and close dead connections, which can
- # occur if a programmer forgets to close a connection at the end of a
- # thread or a thread dies unexpectedly. (Default nil, which means don't
- # run the Reaper).
- # * +dead_connection_timeout+: number of seconds from last checkout
- # after which the Reaper will consider a connection reapable. (default
- # 5 seconds).
+ # Reaper, which attempts to find and recover connections from dead
+ # threads, which can occur if a programmer forgets to close a
+ # connection at the end of a thread or a thread dies unexpectedly.
+ # Regardless of this setting, the Reaper will be invoked before every
+ # blocking wait. (Default nil, which means don't schedule the Reaper).
class ConnectionPool
# Threadsafe, fair, FIFO queue. Meant to be used by ConnectionPool
# with which it shares a Monitor. But could be a generic Queue.
@@ -222,7 +220,7 @@ def run
include MonitorMixin
- attr_accessor :automatic_reconnect, :checkout_timeout, :dead_connection_timeout
+ attr_accessor :automatic_reconnect, :checkout_timeout
attr_reader :spec, :connections, :size, :reaper
# Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
@@ -237,7 +235,6 @@ def initialize(spec)
@spec = spec
@checkout_timeout = spec.config[:checkout_timeout] || 5
- @dead_connection_timeout = spec.config[:dead_connection_timeout] || 5
@reaper = Reaper.new self, spec.config[:reaping_frequency]
@reaper.run
@@ -361,11 +358,13 @@ def checkout
# calling +checkout+ on this pool.
def checkin(conn)
synchronize do
+ owner = conn.owner
+
conn.run_callbacks :checkin do
conn.expire
end
- release conn
+ release conn, owner
@available.add conn
end
@@ -378,22 +377,28 @@ def remove(conn)
@connections.delete conn
@available.delete conn
- # FIXME: we might want to store the key on the connection so that removing
- # from the reserved hash will be a little easier.
- release conn
+ release conn, conn.owner
@available.add checkout_new_connection if @available.any_waiting?
end
end
- # Removes dead connections from the pool. A dead connection can occur
- # if a programmer forgets to close a connection at the end of a thread
+ # Recover lost connections for the pool. A lost connection can occur if
+ # a programmer forgets to checkin a connection at the end of a thread
# or a thread dies unexpectedly.
def reap
- synchronize do
- stale = Time.now - @dead_connection_timeout
- connections.dup.each do |conn|
- if conn.in_use? && stale > conn.last_use && !conn.active_threadsafe?
+ stale_connections = synchronize do
+ @connections.select do |conn|
+ conn.in_use? && !conn.owner.alive?
+ end
+ end
+
+ stale_connections.each do |conn|
+ synchronize do
+ if conn.active?
+ conn.reset!
+ checkin conn
+ else
remove conn
end
end
@@ -415,20 +420,15 @@ def acquire_connection
elsif @connections.size < @size
checkout_new_connection
else
+ reap
@available.poll(@checkout_timeout)
end
end
- def release(conn)
- thread_id = if @reserved_connections[current_connection_id] == conn
- current_connection_id
- else
- @reserved_connections.keys.find { |k|
- @reserved_connections[k] == conn
- }
- end
+ def release(conn, owner)
+ thread_id = owner.object_id
- @reserved_connections.delete thread_id if thread_id
+ @reserved_connections.delete thread_id
end
def new_connection
View
21 activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -26,14 +26,7 @@ def cacheable_query(arel) # :nodoc:
# Returns an ActiveRecord::Result instance.
def select_all(arel, name = nil, binds = [])
- if arel.is_a?(Relation)
- relation = arel
- arel = relation.arel
- if !binds || binds.empty?
- binds = relation.bind_values
- end
- end
-
+ arel, binds = binds_from_relation arel, binds
select(to_sql(arel, binds), name, binds)
end
@@ -53,10 +46,7 @@ def select_value(arel, name = nil, binds = [])
# Returns an array of the values of the first column in a select:
# select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
def select_values(arel, name = nil)
- binds = []
- if arel.is_a?(Relation)
- arel, binds = arel.arel, arel.bind_values
- end
+ arel, binds = binds_from_relation arel, []
select_rows(to_sql(arel, binds), name, binds).map(&:first)
end
@@ -395,6 +385,13 @@ def last_inserted_id(result)
row = result.rows.first
row && row.first
end
+
+ def binds_from_relation(relation, binds)
+ if relation.is_a?(Relation) && binds.blank?
+ relation, binds = relation.arel, relation.bind_values
+ end
+ [relation, binds]
+ end
end
end
end
View
1  activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
@@ -63,6 +63,7 @@ def clear_query_cache
def select_all(arel, name = nil, binds = [])
if @query_cache_enabled && !locked?(arel)
+ arel, binds = binds_from_relation arel, binds
sql = to_sql(arel, binds)
cache_sql(sql, binds) { super(sql, name, binds) }
else
View
20 activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -71,8 +71,8 @@ class AbstractAdapter
define_callbacks :checkout, :checkin
attr_accessor :visitor, :pool
- attr_reader :schema_cache, :last_use, :in_use, :logger
- alias :in_use? :in_use
+ attr_reader :schema_cache, :owner, :logger
+ alias :in_use? :owner
def self.type_cast_config_to_integer(config)
if config =~ SIMPLE_INT
@@ -96,9 +96,8 @@ def initialize(connection, logger = nil, pool = nil) #:nodoc:
super()
@connection = connection
- @in_use = false
+ @owner = nil
@instrumenter = ActiveSupport::Notifications.instrumenter
- @last_use = false
@logger = logger
@pool = pool
@schema_cache = SchemaCache.new self
@@ -120,9 +119,8 @@ def schema_creation
def lease
synchronize do
- unless in_use
- @in_use = true
- @last_use = Time.now
+ unless in_use?
+ @owner = Thread.current
end
end
end
@@ -133,7 +131,7 @@ def schema_cache=(cache)
end
def expire
- @in_use = false
+ @owner = nil
end
def unprepared_visitor
@@ -268,12 +266,6 @@ def disable_referential_integrity
def active?
end
- # Adapter should redefine this if it needs a threadsafe way to approximate
- # if the connection is active
- def active_threadsafe?
- active?
- end
-
# Disconnects from the database if already connected, and establishes a
# new connection with the database. Implementors should call super if they
# override the default implementation.
View
4 activerecord/lib/active_record/connection_adapters/connection_specification.rb
@@ -237,8 +237,8 @@ def resolve_env_connection(spec)
# hash and merges with the rest of the hash.
# Connection details inside of the "url" key win any merge conflicts
def resolve_hash_connection(spec)
- if url = spec.delete("url")
- connection_hash = resolve_string_connection(url)
+ if spec["url"] && spec["url"] !~ /^jdbc:/
+ connection_hash = resolve_string_connection(spec.delete("url"))
spec.merge!(connection_hash)
end
spec
View
1  activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -327,6 +327,7 @@ def pk_and_sequence_for(table) #:nodoc:
AND attr.attrelid = cons.conrelid
AND attr.attnum = cons.conkey[1]
AND cons.contype = 'p'
+ AND dep.classid = 'pg_class'::regclass
AND dep.refobjid = '#{quote_table_name(table)}'::regclass
end_sql
View
11 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -603,10 +603,6 @@ def active?
false
end
- def active_threadsafe?
- @connection.connect_poll != PG::PGRES_POLLING_FAILED
- end
-
# Close then reopen the connection.
def reconnect!
super
@@ -616,7 +612,12 @@ def reconnect!
def reset!
clear_cache!
- super
+ reset_transaction
+ unless @connection.transaction_status == ::PG::PQTRANS_IDLE
+ @connection.query 'ROLLBACK'
+ end
+ @connection.query 'DISCARD ALL'
+ configure_connection
end
# Disconnects from the database if already connected. Otherwise, this
View
3  activerecord/lib/active_record/fixtures.rb
@@ -361,6 +361,7 @@ class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
# geeksomnia:
# name: Geeksomnia's Account
# subdomain: $LABEL
+ # email: $LABEL@email.com
#
# Also, sometimes (like when porting older join table fixtures) you'll need
# to be able to get a hold of the identifier for a given label. ERB
@@ -627,7 +628,7 @@ def table_rows
# interpolate the fixture label
row.each do |key, value|
- row[key] = label if "$LABEL" == value
+ row[key] = value.gsub("$LABEL", label) if value.is_a?(String)
end
# generate a primary key if necessary
View
21 activerecord/lib/active_record/persistence.rb
@@ -405,15 +405,18 @@ def reload(options = nil)
end
# Saves the record with the updated_at/on attributes set to the current time.
- # Please note that no validation is performed and only the +after_touch+
- # callback is executed.
- # If an attribute name is passed, that attribute is updated along with
- # updated_at/on attributes.
+ # Please note that no validation is performed and only the +after_touch+,
+ # +after_commit+ and +after_rollback+ callbacks are executed.
#
- # product.touch # updates updated_at/on
- # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
+ # If attribute names are passed, they are updated along with updated_at/on
+ # attributes.
#
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on associated object.
+ # product.touch # updates updated_at/on
+ # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
+ # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
+ #
+ # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
+ # associated object.
#
# class Brake < ActiveRecord::Base
# belongs_to :car, touch: true
@@ -432,11 +435,11 @@ def reload(options = nil)
# ball = Ball.new
# ball.touch(:updated_at) # => raises ActiveRecordError
#
- def touch(name = nil)
+ def touch(*names)
raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
attributes = timestamp_attributes_for_update_in_model
- attributes << name if name
+ attributes.concat(names)
unless attributes.empty?
current_time = current_time_from_proper_timezone
View
3  activerecord/lib/active_record/railties/databases.rake
@@ -268,7 +268,8 @@ db_namespace = namespace :db do
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
- if ActiveRecord::Base.connection.supports_migrations?
+ if ActiveRecord::Base.connection.supports_migrations? &&
+ ActiveRecord::SchemaMigration.table_exists?
File.open(filename, "a") do |f|
f.puts ActiveRecord::Base.connection.dump_schema_information
f.print "\n"
View
2  activerecord/lib/active_record/relation/query_methods.rb
@@ -49,6 +49,8 @@ def not(opts, *rest)
Arel::Nodes::Not.new(rel)
end
end
+
+ @scope.references!(PredicateBuilder.references(opts)) if Hash === opts
@scope.where_values += where_value
@scope
end
View
10 activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
@@ -23,16 +23,16 @@ def set_local_assigns!
case file_name
when /^(add|remove)_.*_(?:to|from)_(.*)/
@migration_action = $1
- @table_name = $2.pluralize
+ @table_name = normalize_table_name($2)
when /join_table/
if attributes.length == 2
@migration_action = 'join'
- @join_tables = attributes.map(&:plural_name)
+ @join_tables = pluralize_table_names? ? attributes.map(&:plural_name) : attributes.map(&:singular_name)
set_index_names
end
when /^create_(.+)/
- @table_name = $1.pluralize
+ @table_name = normalize_table_name($1)
@migration_template = "create_table_migration.rb"
end
end
@@ -61,6 +61,10 @@ def validate_file_name!
raise IllegalMigrationNameError.new(file_name)
end
end
+
+ def normalize_table_name(_table_name)
+ pluralize_table_names? ? _table_name.pluralize : _table_name.singularize
+ end
end
end
end
View
2  activerecord/test/cases/adapter_test.rb
@@ -218,7 +218,7 @@ def setup
@connection = Klass.connection
end
- def teardown
+ teardown do
Klass.remove_connection
end
View
2  activerecord/test/cases/adapters/mysql/active_schema_test.rb
@@ -11,7 +11,7 @@ def execute(sql, name = nil) return sql end
end
end
- def teardown
+ teardown do
ActiveRecord::Base.remove_connection
ActiveRecord::Base.establish_connection(@connection)
end
View
80 activerecord/test/cases/adapters/mysql/connection_test.rb
@@ -1,6 +1,9 @@
require "cases/helper"
+require 'support/ddl_helper'
class MysqlConnectionTest < ActiveRecord::TestCase
+ include DdlHelper
+
class Klass < ActiveRecord::Base
end
@@ -69,59 +72,50 @@ def test_bind_value_substitute
end
def test_exec_no_binds
- @connection.exec_query('drop table if exists ex')
- @connection.exec_query(<<-eosql)
- CREATE TABLE `ex` (`id` int(11) auto_increment PRIMARY KEY,
- `data` varchar(255))
- eosql
- result = @connection.exec_query('SELECT id, data FROM ex')
- assert_equal 0, result.rows.length
- assert_equal 2, result.columns.length
- assert_equal %w{ id data }, result.columns
+ with_example_table do
+ result = @connection.exec_query('SELECT id, data FROM ex')
+ assert_equal 0, result.rows.length
+ assert_equal 2, result.columns.length
+ assert_equal %w{ id data }, result.columns
- @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
+ @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
- # if there are no bind parameters, it will return a string (due to
- # the libmysql api)
- result = @connection.exec_query('SELECT id, data FROM ex')
- assert_equal 1, result.rows.length
- assert_equal 2, result.columns.length
+ # if there are no bind parameters, it will return a string (due to
+ # the libmysql api)
+ result = @connection.exec_query('SELECT id, data FROM ex')
+ assert_equal 1, result.rows.length
+ assert_equal 2, result.columns.length
- assert_equal [['1', 'foo']], result.rows
+ assert_equal [['1', 'foo']], result.rows
+ end
end
def test_exec_with_binds
- @connection.exec_query('drop table if exists ex')
- @connection.exec_query(<<-eosql)
- CREATE TABLE `ex` (`id` int(11) auto_increment PRIMARY KEY,
- `data` varchar(255))
- eosql
- @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
- result = @connection.exec_query(
- 'SELECT id, data FROM ex WHERE id = ?', nil, [[nil, 1]])
+ with_example_table do
+ @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
+ result = @connection.exec_query(
+ 'SELECT id, data FROM ex WHERE id = ?', nil, [[nil, 1]])
- assert_equal 1, result.rows.length
- assert_equal 2, result.columns.length
+ assert_equal 1, result.rows.length
+ assert_equal 2, result.columns.length
- assert_equal [[1, 'foo']], result.rows
+ assert_equal [[1, 'foo']], result.rows
+ end
end
def test_exec_typecasts_bind_vals
- @connection.exec_query('drop table if exists ex')
- @connection.exec_query(<<-eosql)
- CREATE TABLE `ex` (`id` int(11) auto_increment PRIMARY KEY,
- `data` varchar(255))
- eosql
- @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
- column = @connection.columns('ex').find { |col| col.name == 'id' }
+ with_example_table do
+ @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")')
+ column = @connection.columns('ex').find { |col| col.name == 'id' }
- result = @connection.exec_query(
- 'SELECT id, data FROM ex WHERE id = ?', nil, [[column, '1-fuu']])
+ result = @connection.exec_query(
+ 'SELECT id, data FROM ex WHERE id = ?', nil, [[column, '1-fuu']])
- assert_equal 1, result.rows.length
- assert_equal 2, result.columns.length
+ assert_equal 1, result.rows.length
+ assert_equal 2, result.columns.length
- assert_equal [[1, 'foo']], result.rows
+ assert_equal [[1, 'foo']], result.rows
+ end
end
# Test that MySQL allows multiple results for stored procedures
@@ -174,4 +168,12 @@ def run_without_connection
ActiveRecord::Base.establish_connection(original_connection)
end
end
+
+ def with_example_table(&block)
+ definition ||= <<-SQL
+ `id` int(11) auto_increment PRIMARY KEY,
+ `data` varchar(255)
+ SQL
+ super(@connection, 'ex', definition, &block)
+ end
end
View
108 activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
@@ -1,19 +1,15 @@
# encoding: utf-8
require "cases/helper"
+require 'support/ddl_helper'
module ActiveRecord
module ConnectionAdapters
class MysqlAdapterTest < ActiveRecord::TestCase
+ include DdlHelper
+
def setup
@conn = ActiveRecord::Base.connection
- @conn.exec_query('drop table if exists ex')
- @conn.exec_query(<<-eosql)
- CREATE TABLE `ex` (
- `id` int(11) auto_increment PRIMARY KEY,
- `number` integer,
- `data` varchar(255))
- eosql
end
def test_bad_connection_mysql
@@ -25,8 +21,10 @@ def test_bad_connection_mysql
end
def test_valid_column
- column = @conn.columns('ex').find { |col| col.name == 'id' }
- assert @conn.valid_type?(column.type)
+ with_example_table do
+ column = @conn.columns('ex').find { |col| col.name == 'id' }
+ assert @conn.valid_type?(column.type)
+ end
end
def test_invalid_column
@@ -38,31 +36,35 @@ def test_client_encoding
end
def test_exec_insert_number
- insert(@conn, 'number' => 10)
+ with_example_table do
+ insert(@conn, 'number' => 10)
- result = @conn.exec_query('SELECT number FROM ex WHERE number = 10')
+ result = @conn.exec_query('SELECT number FROM ex WHERE number = 10')
- assert_equal 1, result.rows.length
- # if there are no bind parameters, it will return a string (due to
- # the libmysql api)
- assert_equal '10', result.rows.last.last
+ assert_equal 1, result.rows.length
+ # if there are no bind parameters, it will return a string (due to
+ # the libmysql api)
+ assert_equal '10', result.rows.last.last
+ end
end
def test_exec_insert_string
- str = 'いただきます!'
- insert(@conn, 'number' => 10, 'data' => str)
+ with_example_table do
+ str = 'いただきます!'
+ insert(@conn, 'number' => 10, 'data' => str)
- result = @conn.exec_query('SELECT number, data FROM ex WHERE number = 10')
+ result = @conn.exec_query('SELECT number, data FROM ex WHERE number = 10')
- value = result.rows.last.last
+ value = result.rows.last.last
- # FIXME: this should probably be inside the mysql AR adapter?
- value.force_encoding(@conn.client_encoding)
+ # FIXME: this should probably be inside the mysql AR adapter?
+ value.force_encoding(@conn.client_encoding)
- # The strings in this file are utf-8, so transcode to utf-8
- value.encode!(Encoding::UTF_8)
+ # The strings in this file are utf-8, so transcode to utf-8
+ value.encode!(Encoding::UTF_8)
- assert_equal str, value
+ assert_equal str, value
+ end
end
def test_tables_quoting
@@ -74,46 +76,37 @@ def test_tables_quoting
end
def test_pk_and_sequence_for
- pk, seq = @conn.pk_and_sequence_for('ex')
- assert_equal 'id', pk
- assert_equal @conn.default_sequence_name('ex', 'id'), seq
+ with_example_table do
+ pk, seq = @conn.pk_and_sequence_for('ex')
+ assert_equal 'id', pk
+ assert_equal @conn.default_sequence_name('ex', 'id'), seq
+ end
end
def test_pk_and_sequence_for_with_non_standard_primary_key
- @conn.exec_query('drop table if exists ex_with_non_standard_pk')
- @conn.exec_query(<<-eosql)
- CREATE TABLE `ex_with_non_standard_pk` (
- `code` INT(11) auto_increment,
- PRIMARY KEY (`code`))
- eosql
- pk, seq = @conn.pk_and_sequence_for('ex_with_non_standard_pk')
- assert_equal 'code', pk
- assert_equal @conn.default_sequence_name('ex_with_non_standard_pk', 'code'), seq
+ with_example_table '`code` INT(11) auto_increment, PRIMARY KEY (`code`)' do
+ pk, seq = @conn.pk_and_sequence_for('ex')
+ assert_equal 'code', pk
+ assert_equal @conn.default_sequence_name('ex', 'code'), seq
+ end
end
def test_pk_and_sequence_for_with_custom_index_type_pk
- @conn.exec_query('drop table if exists ex_with_custom_index_type_pk')
- @conn.exec_query(<<-eosql)
- CREATE TABLE `ex_with_custom_index_type_pk` (
- `id` INT(11) auto_increment,
- PRIMARY KEY USING BTREE (`id`))
- eosql
- pk, seq = @conn.pk_and_sequence_for('ex_with_custom_index_type_pk')
- assert_equal 'id', pk
- assert_equal @conn.default_sequence_name('ex_with_custom_index_type_pk', 'id'), seq
+ with_example_table '`id` INT(11) auto_increment, PRIMARY KEY USING BTREE (`id`)' do
+ pk, seq = @conn.pk_and_sequence_for('ex')
+ assert_equal 'id', pk
+ assert_equal @conn.default_sequence_name('ex', 'id'), seq
+ end
end
def test_tinyint_integer_typecasting
- @conn.exec_query('drop table if exists ex_with_non_boolean_tinyint_column')
- @conn.exec_query(<<-eosql)
- CREATE TABLE `ex_with_non_boolean_tinyint_column` (
- `status` TINYINT(4))
- eosql
- insert(@conn, { 'status' => 2 }, 'ex_with_non_boolean_tinyint_column')
+ with_example_table '`status` TINYINT(4)' do
+ insert(@conn, { 'status' => 2 }, 'ex')
- result = @conn.exec_query('SELECT status FROM ex_with_non_boolean_tinyint_column')
+ result = @conn.exec_query('SELECT status FROM ex')
- assert_equal 2, result.column_types['status'].type_cast(result.last['status'])
+ assert_equal 2, result.column_types['status'].type_cast(result.last['status'])
+ end
end
def test_supports_extensions
@@ -140,6 +133,15 @@ def insert(ctx, data, table='ex')
ctx.exec_insert(sql, 'SQL', binds)
end
+
+ def with_example_table(definition = nil, &block)
+ definition ||= <<-SQL
+ `id` int(11) auto_increment PRIMARY KEY,
+ `number` integer,
+ `data` varchar(255)
+ SQL
+ super(@conn, 'ex', definition, &block)
+ end
end
end
end
View
2  activerecord/test/cases/adapters/mysql/reserved_word_test.rb
@@ -37,7 +37,7 @@ def setup
'distinct_select'=>'distinct_id int, select_id int'
end
- def teardown
+ teardown do
drop_tables_directly ['group', 'select', 'values', 'distinct', 'distinct_select', 'order']
end
View
2  activerecord/test/cases/adapters/mysql2/active_schema_test.rb
@@ -11,7 +11,7 @@ def execute(sql, name = nil) return sql end
end
end
- def teardown
+ teardown do
ActiveRecord::Base.remove_connection
ActiveRecord::Base.establish_connection(@connection)
end
View
2  activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
@@ -37,7 +37,7 @@ def setup
'distinct_select'=>'distinct_id int, select_id int'
end
- def teardown
+ teardown do
drop_tables_directly ['group', 'select', 'values', 'distinct', 'distinct_select', 'order']
end
View
2  activerecord/test/cases/adapters/postgresql/active_schema_test.rb
@@ -7,7 +7,7 @@ def execute(sql, name = nil) sql end
end
end
- def teardown
+ teardown do
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
remove_method :execute
end