activerecord 2.0.2 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (53) hide show
  1. data/CHANGELOG +25 -0
  2. data/README +0 -0
  3. data/Rakefile +5 -3
  4. data/lib/active_record.rb +0 -0
  5. data/lib/active_record/associations.rb +232 -193
  6. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +14 -14
  7. data/lib/active_record/associations/has_many_association.rb +2 -2
  8. data/lib/active_record/associations/has_many_through_association.rb +25 -6
  9. data/lib/active_record/attribute_methods.rb +4 -3
  10. data/lib/active_record/base.rb +75 -41
  11. data/lib/active_record/calculations.rb +2 -1
  12. data/lib/active_record/callbacks.rb +0 -0
  13. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +1 -1
  14. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -6
  15. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +12 -11
  16. data/lib/active_record/connection_adapters/abstract_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -0
  18. data/lib/active_record/connection_adapters/postgresql_adapter.rb +3 -3
  19. data/lib/active_record/connection_adapters/sqlite_adapter.rb +13 -6
  20. data/lib/active_record/fixtures.rb +29 -31
  21. data/lib/active_record/migration.rb +4 -5
  22. data/lib/active_record/observer.rb +1 -1
  23. data/lib/active_record/transactions.rb +3 -5
  24. data/lib/active_record/validations.rb +5 -3
  25. data/lib/active_record/version.rb +1 -1
  26. data/test/abstract_unit.rb +0 -0
  27. data/test/active_schema_test_mysql.rb +5 -2
  28. data/test/adapter_test.rb +1 -0
  29. data/test/all.sh +0 -0
  30. data/test/associations/callbacks_test.rb +1 -1
  31. data/test/associations/eager_test.rb +5 -0
  32. data/test/associations/join_model_test.rb +11 -3
  33. data/test/associations_test.rb +36 -6
  34. data/test/attribute_methods_test.rb +0 -0
  35. data/test/base_test.rb +92 -10
  36. data/test/calculations_test.rb +9 -1
  37. data/test/debug.log +358 -0
  38. data/test/deprecated_finder_test.rb +0 -0
  39. data/test/fixtures/author.rb +1 -1
  40. data/test/fixtures/company.rb +0 -0
  41. data/test/fixtures/fixture_database.sqlite3 +0 -0
  42. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  43. data/test/fixtures/reply.rb +0 -0
  44. data/test/fixtures/topic.rb +0 -0
  45. data/test/fixtures_test.rb +20 -12
  46. data/test/inheritance_test.rb +0 -0
  47. data/test/lifecycle_test.rb +0 -0
  48. data/test/migration_test.rb +46 -0
  49. data/test/query_cache_test.rb +22 -2
  50. data/test/readonly_test.rb +0 -0
  51. data/test/unconnected_test.rb +0 -0
  52. data/test/validations_test.rb +50 -38
  53. metadata +8 -4
@@ -89,7 +89,7 @@ module ActiveRecord
89
89
  # See also TableDefinition#column for details on how to create columns.
90
90
  def create_table(table_name, options = {})
91
91
  table_definition = TableDefinition.new(self)
92
- table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false
92
+ table_definition.primary_key(options[:primary_key] || Base.get_primary_key(table_name)) unless options[:id] == false
93
93
 
94
94
  yield table_definition
95
95
 
@@ -255,26 +255,27 @@ module ActiveRecord
255
255
  def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
256
256
  if native = native_database_types[type]
257
257
  column_type_sql = native.is_a?(Hash) ? native[:name] : native
258
+
258
259
  if type == :decimal # ignore limit, use precision and scale
259
- precision ||= native[:precision]
260
260
  scale ||= native[:scale]
261
- if precision
261
+
262
+ if precision ||= native[:precision]
262
263
  if scale
263
264
  column_type_sql << "(#{precision},#{scale})"
264
265
  else
265
266
  column_type_sql << "(#{precision})"
266
267
  end
267
- else
268
- raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified" if scale
268
+ elsif scale
269
+ raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified"
269
270
  end
270
- column_type_sql
271
- else
272
- limit ||= native[:limit]
273
- column_type_sql << "(#{limit})" if limit
274
- column_type_sql
271
+
272
+ elsif limit ||= native.is_a?(Hash) && native[:limit]
273
+ column_type_sql << "(#{limit})"
275
274
  end
275
+
276
+ column_type_sql
276
277
  else
277
- column_type_sql = type
278
+ type
278
279
  end
279
280
  end
280
281
 
@@ -30,6 +30,7 @@ module ActiveRecord
30
30
  @connection, @logger = connection, logger
31
31
  @runtime = 0
32
32
  @last_verification = 0
33
+ @query_cache_enabled = false
33
34
  end
34
35
 
35
36
  # Returns the human-readable name of the adapter. Use mixed case - one
@@ -346,7 +346,7 @@ module ActiveRecord
346
346
  # There are some incorrectly compiled postgres drivers out there
347
347
  # that don't define PGconn.escape.
348
348
  self.class.instance_eval do
349
- undef_method(:quote_string)
349
+ remove_method(:quote_string)
350
350
  end
351
351
  end
352
352
  quote_string(s)
@@ -386,8 +386,8 @@ module ActiveRecord
386
386
 
387
387
  # Executes an INSERT query and returns the new record's ID
388
388
  def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
389
- table = sql.split(" ", 4)[2]
390
- super || last_insert_id(table, sequence_name || default_sequence_name(table, pk))
389
+ table = sql.split(" ", 4)[2].gsub('"', '')
390
+ super || pk && last_insert_id(table, sequence_name || default_sequence_name(table, pk))
391
391
  end
392
392
 
393
393
  # Queries the database and returns the results in an Array or nil otherwise.
@@ -304,13 +304,13 @@ module ActiveRecord
304
304
  yield @definition if block_given?
305
305
  end
306
306
 
307
- copy_table_indexes(from, to)
307
+ copy_table_indexes(from, to, options[:rename] || {})
308
308
  copy_table_contents(from, to,
309
309
  @definition.columns.map {|column| column.name},
310
310
  options[:rename] || {})
311
311
  end
312
312
 
313
- def copy_table_indexes(from, to) #:nodoc:
313
+ def copy_table_indexes(from, to, rename = {}) #:nodoc:
314
314
  indexes(from).each do |index|
315
315
  name = index.name
316
316
  if to == "altered_#{from}"
@@ -319,10 +319,17 @@ module ActiveRecord
319
319
  name = name[5..-1]
320
320
  end
321
321
 
322
- # index name can't be the same
323
- opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
324
- opts[:unique] = true if index.unique
325
- add_index(to, index.columns, opts)
322
+ to_column_names = columns(to).map(&:name)
323
+ columns = index.columns.map {|c| rename[c] || c }.select do |column|
324
+ to_column_names.include?(column)
325
+ end
326
+
327
+ unless columns.empty?
328
+ # index name can't be the same
329
+ opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
330
+ opts[:unique] = true if index.unique
331
+ add_index(to, columns, opts)
332
+ end
326
333
  end
327
334
  end
328
335
 
@@ -438,7 +438,7 @@ end
438
438
  #
439
439
  # Any fixture labeled "DEFAULTS" is safely ignored.
440
440
 
441
- class Fixtures < YAML::Omap
441
+ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
442
442
  DEFAULT_FILTER_RE = /\.ya?ml$/
443
443
 
444
444
  @@all_cached_fixtures = {}
@@ -467,7 +467,7 @@ class Fixtures < YAML::Omap
467
467
  end
468
468
 
469
469
  def self.cache_fixtures(connection, fixtures)
470
- cache_for_connection(connection).update(fixtures.index_by(&:table_name))
470
+ cache_for_connection(connection).update(fixtures.index_by { |f| f.table_name })
471
471
  end
472
472
 
473
473
  def self.instantiate_fixtures(object, table_name, fixtures, load_instances = true)
@@ -644,8 +644,16 @@ class Fixtures < YAML::Omap
644
644
  end
645
645
 
646
646
  def model_class
647
- @model_class ||= @class_name.is_a?(Class) ?
648
- @class_name : @class_name.constantize rescue nil
647
+ unless defined?(@model_class)
648
+ @model_class =
649
+ if @class_name.nil? || @class_name.is_a?(Class)
650
+ @class_name
651
+ else
652
+ @class_name.constantize rescue nil
653
+ end
654
+ end
655
+
656
+ @model_class
649
657
  end
650
658
 
651
659
  def primary_key_name
@@ -681,7 +689,7 @@ class Fixtures < YAML::Omap
681
689
  Dir.entries(@fixture_path).each do |file|
682
690
  path = File.join(@fixture_path, file)
683
691
  if File.file?(path) and file !~ @file_filter
684
- self[file] = Fixture.new(path, @class_name)
692
+ self[file] = Fixture.new(path, model_class)
685
693
  end
686
694
  end
687
695
  end
@@ -709,20 +717,20 @@ class Fixtures < YAML::Omap
709
717
  raise Fixture::FormatError, "Bad data for #{@class_name} fixture named #{name} (nil)"
710
718
  end
711
719
 
712
- self[name] = Fixture.new(data, @class_name)
720
+ self[name] = Fixture.new(data, model_class)
713
721
  end
714
722
  end
715
723
  end
716
724
  end
717
725
 
718
726
  def read_csv_fixture_files
719
- reader = CSV::Reader.create(erb_render(IO.read(csv_file_path)))
727
+ reader = CSV.parse(erb_render(IO.read(csv_file_path)))
720
728
  header = reader.shift
721
729
  i = 0
722
730
  reader.each do |row|
723
731
  data = {}
724
732
  row.each_with_index { |cell, j| data[header[j].to_s.strip] = cell.to_s.strip }
725
- self["#{Inflector::underscore(@class_name)}_#{i+=1}"]= Fixture.new(data, @class_name)
733
+ self["#{Inflector::underscore(@class_name)}_#{i+=1}"] = Fixture.new(data, model_class)
726
734
  end
727
735
  end
728
736
 
@@ -758,9 +766,9 @@ class Fixture #:nodoc:
758
766
  class FormatError < FixtureError #:nodoc:
759
767
  end
760
768
 
761
- attr_reader :class_name
769
+ attr_reader :model_class
762
770
 
763
- def initialize(fixture, class_name)
771
+ def initialize(fixture, model_class)
764
772
  case fixture
765
773
  when Hash, YAML::Omap
766
774
  @fixture = fixture
@@ -770,7 +778,11 @@ class Fixture #:nodoc:
770
778
  raise ArgumentError, "Bad fixture argument #{fixture.inspect} during creation of #{class_name} fixture"
771
779
  end
772
780
 
773
- @class_name = class_name
781
+ @model_class = model_class.is_a?(Class) ? model_class : model_class.constantize rescue nil
782
+ end
783
+
784
+ def class_name
785
+ @model_class.name if @model_class
774
786
  end
775
787
 
776
788
  def each
@@ -791,21 +803,18 @@ class Fixture #:nodoc:
791
803
  end
792
804
 
793
805
  def value_list
794
- klass = @class_name.constantize rescue nil
795
-
796
806
  list = @fixture.inject([]) do |fixtures, (key, value)|
797
- col = klass.columns_hash[key] if klass.respond_to?(:ancestors) && klass.ancestors.include?(ActiveRecord::Base)
807
+ col = model_class.columns_hash[key] if model_class.respond_to?(:ancestors) && model_class.ancestors.include?(ActiveRecord::Base)
798
808
  fixtures << ActiveRecord::Base.connection.quote(value, col).gsub('[^\]\\n', "\n").gsub('[^\]\\r', "\r")
799
809
  end
800
810
  list * ', '
801
811
  end
802
812
 
803
813
  def find
804
- klass = @class_name.is_a?(Class) ? @class_name : Object.const_get(@class_name) rescue nil
805
- if klass
806
- klass.find(self[klass.primary_key])
814
+ if model_class
815
+ model_class.find(self[model_class.primary_key])
807
816
  else
808
- raise FixtureClassNotFound, "The class #{@class_name.inspect} was not found."
817
+ raise FixtureClassNotFound, "No class attached to find."
809
818
  end
810
819
  end
811
820
 
@@ -916,8 +925,6 @@ module Test #:nodoc:
916
925
  end
917
926
 
918
927
  def setup_with_fixtures
919
- return if @fixtures_setup
920
- @fixtures_setup = true
921
928
  return unless defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank?
922
929
 
923
930
  if pre_loaded_fixtures && !use_transactional_fixtures
@@ -949,8 +956,6 @@ module Test #:nodoc:
949
956
  alias_method :setup, :setup_with_fixtures
950
957
 
951
958
  def teardown_with_fixtures
952
- return if @fixtures_teardown
953
- @fixtures_teardown = true
954
959
  return unless defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank?
955
960
 
956
961
  unless use_transactional_fixtures?
@@ -967,31 +972,24 @@ module Test #:nodoc:
967
972
  alias_method :teardown, :teardown_with_fixtures
968
973
 
969
974
  def self.method_added(method)
970
- return if @__disable_method_added__
971
- @__disable_method_added__ = true
972
-
973
975
  case method.to_s
974
976
  when 'setup'
975
977
  unless method_defined?(:setup_without_fixtures)
976
978
  alias_method :setup_without_fixtures, :setup
977
- define_method(:full_setup) do
979
+ define_method(:setup) do
978
980
  setup_with_fixtures
979
981
  setup_without_fixtures
980
982
  end
981
983
  end
982
- alias_method :setup, :full_setup
983
984
  when 'teardown'
984
985
  unless method_defined?(:teardown_without_fixtures)
985
986
  alias_method :teardown_without_fixtures, :teardown
986
- define_method(:full_teardown) do
987
+ define_method(:teardown) do
987
988
  teardown_without_fixtures
988
989
  teardown_with_fixtures
989
990
  end
990
991
  end
991
- alias_method :teardown, :full_teardown
992
992
  end
993
-
994
- @__disable_method_added__ = false
995
993
  end
996
994
 
997
995
  private
@@ -230,7 +230,7 @@ module ActiveRecord
230
230
  # recursively. We use @ignore_new_methods as a guard to indicate whether
231
231
  # it is safe for the call to proceed.
232
232
  def singleton_method_added(sym) #:nodoc:
233
- return if @ignore_new_methods
233
+ return if defined?(@ignore_new_methods) && @ignore_new_methods
234
234
 
235
235
  begin
236
236
  @ignore_new_methods = true
@@ -356,15 +356,14 @@ module ActiveRecord
356
356
 
357
357
  private
358
358
  def migration_classes
359
- migrations = migration_files.inject([]) do |migrations, migration_file|
359
+ classes = migration_files.inject([]) do |migrations, migration_file|
360
360
  load(migration_file)
361
361
  version, name = migration_version_and_name(migration_file)
362
362
  assert_unique_migration_version(migrations, version.to_i)
363
363
  migrations << migration_class(name, version.to_i)
364
- end
364
+ end.sort_by(&:version)
365
365
 
366
- sorted = migrations.sort_by { |m| m.version }
367
- down? ? sorted.reverse : sorted
366
+ down? ? classes.reverse : classes
368
367
  end
369
368
 
370
369
  def assert_unique_migration_version(migrations, version)
@@ -170,7 +170,7 @@ module ActiveRecord
170
170
  end
171
171
 
172
172
  def observed_subclasses
173
- observed_classes.collect(&:subclasses).flatten
173
+ observed_classes.sum([]) { |klass| klass.send(:subclasses) }
174
174
  end
175
175
 
176
176
  def add_observer!(klass)
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  end
16
16
  end
17
17
 
18
- # Transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action.
18
+ # Transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action.
19
19
  # The classic example is a transfer between two accounts where you can only have a deposit if the withdrawal succeeded and
20
20
  # vice versa. Transactions enforce the integrity of the database and guard the data against program errors or database break-downs.
21
21
  # So basically you should use transaction blocks whenever you have a number of statements that must be executed together or
@@ -73,14 +73,12 @@ module ActiveRecord
73
73
  # trigger a ROLLBACK when raised, but not be re-raised by the transaction block.
74
74
  module ClassMethods
75
75
  def transaction(&block)
76
- previous_handler = trap('TERM') { raise TransactionError, "Transaction aborted" }
77
76
  increment_open_transactions
78
77
 
79
78
  begin
80
79
  connection.transaction(Thread.current['start_db_transaction'], &block)
81
80
  ensure
82
81
  decrement_open_transactions
83
- trap('TERM', previous_handler)
84
82
  end
85
83
  end
86
84
 
@@ -116,7 +114,7 @@ module ActiveRecord
116
114
  def rollback_active_record_state!
117
115
  id_present = has_attribute?(self.class.primary_key)
118
116
  previous_id = id
119
- previous_new_record = @new_record
117
+ previous_new_record = new_record?
120
118
  yield
121
119
  rescue Exception
122
120
  @new_record = previous_new_record
@@ -125,7 +123,7 @@ module ActiveRecord
125
123
  else
126
124
  @attributes.delete(self.class.primary_key)
127
125
  @attributes_cache.delete(self.class.primary_key)
128
- end
126
+ end
129
127
  raise
130
128
  end
131
129
  end
@@ -1,12 +1,12 @@
1
1
  module ActiveRecord
2
2
  # Raised by save! and create! when the record is invalid. Use the
3
- # record method to retrieve the record which did not validate.
3
+ # +record+ method to retrieve the record which did not validate.
4
4
  # begin
5
5
  # complex_operation_that_calls_save!_internally
6
6
  # rescue ActiveRecord::RecordInvalid => invalid
7
7
  # puts invalid.record.errors
8
8
  # end
9
- class RecordInvalid < ActiveRecordError #:nodoc:
9
+ class RecordInvalid < ActiveRecordError
10
10
  attr_reader :record
11
11
  def initialize(record)
12
12
  @record = record
@@ -633,7 +633,7 @@ module ActiveRecord
633
633
  #
634
634
  # Because this check is performed outside the database there is still a chance that duplicate values
635
635
  # will be inserted in two parallel transactions. To guarantee against this you should create a
636
- # unique index on the field. See +create_index+ for more information.
636
+ # unique index on the field. See +add_index+ for more information.
637
637
  #
638
638
  # Configuration options:
639
639
  # * <tt>message</tt> - Specifies a custom error message (default is: "has already been taken")
@@ -707,6 +707,8 @@ module ActiveRecord
707
707
  #
708
708
  # Configuration options:
709
709
  # * <tt>message</tt> - A custom error message (default is: "is invalid")
710
+ # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
711
+ # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false)
710
712
  # * <tt>with</tt> - The regular expression used to validate the format with (note: must be supplied!)
711
713
  # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
712
714
  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
@@ -2,7 +2,7 @@ module ActiveRecord
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 2
4
4
  MINOR = 0
5
- TINY = 2
5
+ TINY = 4
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
File without changes
@@ -3,13 +3,16 @@ require 'abstract_unit'
3
3
  class ActiveSchemaTest < Test::Unit::TestCase
4
4
  def setup
5
5
  ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
6
- alias_method :real_execute, :execute
6
+ alias_method :execute_without_stub, :execute
7
7
  def execute(sql, name = nil) return sql end
8
8
  end
9
9
  end
10
10
 
11
11
  def teardown
12
- ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:alias_method, :execute, :real_execute)
12
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
13
+ remove_method :execute
14
+ alias_method :execute, :execute_without_stub
15
+ end
13
16
  end
14
17
 
15
18
  def test_drop_table
@@ -76,6 +76,7 @@ class AdapterTest < Test::Unit::TestCase
76
76
  assert_equal 'dbo_posts', @connection.table_alias_for('dbo.posts')
77
77
 
78
78
  class << @connection
79
+ remove_method :table_alias_length
79
80
  alias_method :table_alias_length, :old_table_alias_length
80
81
  end
81
82
  end
File without changes
@@ -128,7 +128,7 @@ class AssociationCallbacksTest < Test::Unit::TestCase
128
128
  callback_log = ["before_adding<new>", "after_adding<new>"]
129
129
  assert_equal callback_log, project.developers_log
130
130
  assert project.save
131
- assert_equal 1, project.developers_with_callbacks.count
131
+ assert_equal 1, project.developers_with_callbacks.size
132
132
  assert_equal callback_log, project.developers_log
133
133
  end
134
134