diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2014-03-25 10:18:42 -0700 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2014-03-25 10:18:42 -0700 |
commit | 30b94a876f32f5024f841a6de9b5b20a014a41d3 (patch) | |
tree | 675481c76a279166a0ce4d1a1ac3b39e2be1e33d /activerecord/lib | |
parent | 23ffd03ede9b27a6cbc3154aa99c247b718ccdbc (diff) | |
parent | 9a976ab5756371dd434adda2ff01af3a83d0f63c (diff) | |
download | rails-30b94a876f32f5024f841a6de9b5b20a014a41d3.tar.gz rails-30b94a876f32f5024f841a6de9b5b20a014a41d3.tar.bz2 rails-30b94a876f32f5024f841a6de9b5b20a014a41d3.zip |
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
Diffstat (limited to 'activerecord/lib')
14 files changed, 80 insertions, 78 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index f725356cd9..860e76fa18 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1584,7 +1584,7 @@ module ActiveRecord 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 diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index ff0fbe932b..1f314e0677 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -145,9 +145,8 @@ module ActiveRecord # 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) } diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index fd185de589..db80c0faee 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -58,13 +58,11 @@ module ActiveRecord # * +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 @@ module ActiveRecord 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 @@ module ActiveRecord @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 @@ module ActiveRecord # 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 @@ module ActiveRecord @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 @@ module ActiveRecord 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 diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 9371d6f992..deea857a18 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -26,14 +26,7 @@ module ActiveRecord # 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 @@ module ActiveRecord # 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 @@ module ActiveRecord 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 diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index adc23a6674..4a4506c7f5 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -63,6 +63,7 @@ module ActiveRecord 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 diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 4828e45f62..2d45079168 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -71,8 +71,8 @@ module ActiveRecord 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 @@ module ActiveRecord 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 @@ module ActiveRecord 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 @@ module ActiveRecord end def expire - @in_use = false + @owner = nil end def unprepared_visitor @@ -268,12 +266,6 @@ module ActiveRecord 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. diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 3f8b14bf67..9a133168f8 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -237,8 +237,8 @@ module ActiveRecord # 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 diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index ae8ede4b42..e0afa989cd 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -327,6 +327,7 @@ module ActiveRecord 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 diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index e5f7913c70..bcad9f30d7 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -603,10 +603,6 @@ module ActiveRecord 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 @@ module ActiveRecord 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 diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 59467636d7..6f134bbef8 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -361,6 +361,7 @@ module ActiveRecord # 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 @@ module ActiveRecord # 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 diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 4e63206cf4..c20499d081 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -405,15 +405,18 @@ module ActiveRecord 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 @@ module ActiveRecord # 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 diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 1d5c80bc01..ff1f0f5911 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/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" diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index c5a695c91b..db4ad52592 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -49,6 +49,8 @@ module ActiveRecord Arel::Nodes::Not.new(rel) end end + + @scope.references!(PredicateBuilder.references(opts)) if Hash === opts @scope.where_values += where_value @scope end diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb index 3968acba64..d3c853cfea 100644 --- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb +++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb @@ -23,16 +23,16 @@ module ActiveRecord 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 @@ module ActiveRecord 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 |