diff options
-rw-r--r-- | Gemfile | 1 | ||||
-rw-r--r-- | activerecord/CHANGELOG.md | 8 | ||||
-rw-r--r-- | activerecord/lib/active_record/attribute_methods.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/core.rb | 13 | ||||
-rw-r--r-- | activerecord/lib/active_record/migration.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/relation.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/relation/finder_methods.rb | 2 | ||||
-rw-r--r-- | activerecord/test/cases/base_test.rb | 57 | ||||
-rw-r--r-- | activerecord/test/cases/validations/uniqueness_validation_test.rb | 2 | ||||
-rw-r--r-- | guides/source/form_helpers.md | 26 |
10 files changed, 106 insertions, 9 deletions
@@ -8,6 +8,7 @@ gem 'bcrypt-ruby', '~> 3.0.0' gem 'jquery-rails', github: 'rails/jquery-rails' gem 'turbolinks' gem 'coffee-rails', '~> 4.0.0.beta1' +gem 'thor', github: 'wycats/thor' # This needs to be with require false to avoid # it being automatically loaded by sprockets diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 94d86f6550..3fe8d7ec2e 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,11 @@ ## Rails 4.0.0 (unreleased) ## +* Allow ActiveRecord::Base.connection_handler to have thread affinity and be + settable, this effectively allows ActiveRecord to be used in a multi threaded + setup with multiple connections to multiple dbs. + + *Sam Saffron* + * `rename_column` preserves auto_increment in mysql migrations. Fixes #3493. @@ -8,7 +14,7 @@ * PostgreSQL geometric type point is supported by ActiveRecord. Fixes #7324. *Martin Schuerrer* - + * Add suport for concurrent indexing in PostgreSQL adapter via the `algorithm: :concurrently` option diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 769e005c8f..22405c5d74 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -334,7 +334,7 @@ module ActiveRecord private # Returns a Hash of the Arel::Attributes and attribute values that have been - # type casted for use in an Arel insert/update method. + # typecasted for use in an Arel insert/update method. def arel_attributes_with_values(attribute_names) attrs = {} arel_table = self.class.arel_table diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 013f9b92b9..1ed05c1bd4 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -77,8 +77,17 @@ module ActiveRecord mattr_accessor :disable_implicit_join_references, instance_writer: false self.disable_implicit_join_references = false - class_attribute :connection_handler, instance_writer: false - self.connection_handler = ConnectionAdapters::ConnectionHandler.new + class_attribute :default_connection_handler, instance_writer: false + + def self.connection_handler + Thread.current[:active_record_connection_handler] || self.default_connection_handler + end + + def self.connection_handler=(handler) + Thread.current[:active_record_connection_handler] = handler + end + + self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new end module ClassMethods diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 27d37766b7..d3edcf3cdb 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -102,7 +102,7 @@ module ActiveRecord # table definition. # * <tt>drop_table(name)</tt>: Drops the table called +name+. # * <tt>change_table(name, options)</tt>: Allows to make column alterations to - # the table called +name+. It makes the table object availabe to a block that + # the table called +name+. It makes the table object available to a block that # can then add/remove columns, indexes or foreign keys to it. # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+ # to +new_name+. diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 037097d2dd..51f6d39201 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -603,7 +603,7 @@ module ActiveRecord "\n" \ " Post.includes(:comments).where(\"comments.title = 'foo'\")\n" \ "\n" \ - "Currently, Active Record recognises the table in the string, and knows to JOIN the " \ + "Currently, Active Record recognizes the table in the string, and knows to JOIN the " \ "comments table to the query, rather than loading comments in a separate query. " \ "However, doing this without writing a full-blown SQL parser is inherently flawed. " \ "Since we don't want to write an SQL parser, we are removing this functionality. " \ diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 14520381c9..e2685d0478 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -37,7 +37,7 @@ module ActiveRecord end # Finds the first record matching the specified conditions. There - # is no implied ording so if order matters, you should specify it + # is no implied ordering so if order matters, you should specify it # yourself. # # If no record is found, returns <tt>nil</tt>. diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index f9524bc6bd..69eef500f5 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1578,4 +1578,61 @@ class BasicsTest < ActiveRecord::TestCase klass = Class.new(ActiveRecord::Base) assert_equal ['foo'], klass.all.merge!(select: 'foo').select_values end + + test "connection_handler can be overriden" do + klass = Class.new(ActiveRecord::Base) + orig_handler = klass.connection_handler + new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new + thread_connection_handler = nil + + t = Thread.new do + klass.connection_handler = new_handler + thread_connection_handler = klass.connection_handler + end + t.join + + assert_equal klass.connection_handler, orig_handler + assert_equal thread_connection_handler, new_handler + end + + test "new threads get default the default connection handler" do + klass = Class.new(ActiveRecord::Base) + orig_handler = klass.connection_handler + handler = nil + + t = Thread.new do + handler = klass.connection_handler + end + t.join + + assert_equal handler, orig_handler + assert_equal klass.connection_handler, orig_handler + assert_equal klass.default_connection_handler, orig_handler + end + + test "changing a connection handler in a main thread does not poison the other threads" do + klass = Class.new(ActiveRecord::Base) + orig_handler = klass.connection_handler + new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new + after_handler = nil + is_set = false + + t = Thread.new do + klass.connection_handler = new_handler + is_set = true + Thread.stop + after_handler = klass.connection_handler + end + + while(!is_set) + Thread.pass + end + + klass.connection_handler = orig_handler + t.wakeup + t.join + + assert_equal after_handler, new_handler + assert_equal orig_handler, klass.connection_handler + end end diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb index 29b45944aa..57457359b1 100644 --- a/activerecord/test/cases/validations/uniqueness_validation_test.rb +++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb @@ -54,7 +54,7 @@ class UniquenessValidationTest < ActiveRecord::TestCase assert !t2.save, "Shouldn't save t2 as unique" assert_equal ["has already been taken"], t2.errors[:title] - t2.title = "Now Im really also unique" + t2.title = "Now I am really also unique" assert t2.save, "Should now save t2 as unique" end diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index b8681d493a..817a732051 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -906,7 +906,21 @@ If the associated object is already saved, `fields_for` autogenerates a hidden i ### The Controller -You do not need to write any specific controller code to use nested attributes. Create and update records as you would with a simple form. +As usual you need to +[whitelist the parameters](action_controller_overview.html#strong-parameters) in +the controller before you pass them to the model: + +```ruby +def create + @person = Person.new(person_params) + # ... +end + +private +def person_params + params.require(:person).permit(:name, addresses_attributes: [:id, :kind, :street]) +end +``` ### Removing Objects @@ -937,6 +951,16 @@ If the hash of attributes for an object contains the key `_destroy` with a value <% end %> ``` +Don't forget to update the whitelisted params in your controller to also include +the `_destroy` field: + +```ruby +def person_params + params.require(:person). + permit(:name, addresses_attributes: [:id, :kind, :street, :_destroy]) +end +``` + ### Preventing Empty Records It is often useful to ignore sets of fields that the user has not filled in. You can control this by passing a `:reject_if` proc to `accepts_nested_attributes_for`. This proc will be called with each hash of attributes submitted by the form. If the proc returns `false` then Active Record will not build an associated object for that hash. The example below only tries to build an address if the `kind` attribute is set. |