activerecord 4.0.4 → 4.1.16
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1632 -1797
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +49 -29
- data/lib/active_record/associations/association.rb +9 -17
- data/lib/active_record/associations/association_scope.rb +59 -49
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +6 -1
- data/lib/active_record/associations/builder/association.rb +84 -54
- data/lib/active_record/associations/builder/belongs_to.rb +90 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +119 -25
- data/lib/active_record/associations/builder/has_many.rb +3 -3
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +121 -111
- data/lib/active_record/associations/collection_proxy.rb +73 -18
- data/lib/active_record/associations/has_many_association.rb +14 -11
- data/lib/active_record/associations/has_many_through_association.rb +33 -6
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +46 -104
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_dependency.rb +208 -168
- data/lib/active_record/associations/preloader/association.rb +69 -27
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/preloader.rb +63 -49
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +30 -9
- data/lib/active_record/associations.rb +116 -42
- data/lib/active_record/attribute_assignment.rb +6 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +35 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -1
- data/lib/active_record/attribute_methods/read.rb +56 -29
- data/lib/active_record/attribute_methods/serialization.rb +44 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +13 -1
- data/lib/active_record/attribute_methods/write.rb +59 -26
- data/lib/active_record/attribute_methods.rb +82 -43
- data/lib/active_record/autosave_association.rb +209 -194
- data/lib/active_record/base.rb +6 -2
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +14 -24
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -13
- data/lib/active_record/connection_adapters/abstract/quoting.rb +6 -3
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +90 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +45 -70
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -96
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +74 -66
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +231 -43
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -5
- data/lib/active_record/connection_adapters/mysql_adapter.rb +24 -17
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +22 -15
- data/lib/active_record/connection_adapters/postgresql/cast.rb +12 -4
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -44
- data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -14
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +37 -12
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +20 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +98 -52
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -60
- data/lib/active_record/connection_handling.rb +39 -5
- data/lib/active_record/core.rb +38 -54
- data/lib/active_record/counter_cache.rb +9 -10
- data/lib/active_record/dynamic_matchers.rb +6 -2
- data/lib/active_record/enum.rb +199 -0
- data/lib/active_record/errors.rb +22 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +173 -76
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +23 -9
- data/lib/active_record/integration.rb +54 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +6 -13
- data/lib/active_record/migration/command_recorder.rb +8 -2
- data/lib/active_record/migration.rb +91 -56
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +25 -13
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +26 -6
- data/lib/active_record/persistence.rb +23 -29
- data/lib/active_record/querying.rb +15 -12
- data/lib/active_record/railtie.rb +12 -61
- data/lib/active_record/railties/databases.rake +37 -56
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +230 -79
- data/lib/active_record/relation/batches.rb +74 -24
- data/lib/active_record/relation/calculations.rb +52 -48
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +210 -67
- data/lib/active_record/relation/merger.rb +15 -12
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder.rb +81 -40
- data/lib/active_record/relation/query_methods.rb +185 -108
- data/lib/active_record/relation/spawn_methods.rb +8 -5
- data/lib/active_record/relation.rb +79 -84
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +4 -4
- data/lib/active_record/schema_dumper.rb +18 -6
- data/lib/active_record/schema_migration.rb +31 -18
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +14 -29
- data/lib/active_record/scoping.rb +5 -0
- data/lib/active_record/store.rb +67 -18
- data/lib/active_record/tasks/database_tasks.rb +66 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -10
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/transactions.rb +10 -12
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +19 -9
- data/lib/active_record/version.rb +4 -7
- data/lib/active_record.rb +5 -7
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- data/lib/rails/generators/active_record.rb +2 -8
- metadata +18 -30
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/join_helper.rb +0 -45
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -96
@@ -119,6 +119,23 @@ module ActiveRecord
|
|
119
119
|
# perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
|
120
120
|
# in fixtures are to be considered a code smell.
|
121
121
|
#
|
122
|
+
# Helper methods defined in a fixture will not be available in other fixtures, to prevent against
|
123
|
+
# unwanted inter-test dependencies. Methods used by multiple fixtures should be defined in a module
|
124
|
+
# that is included in <tt>ActiveRecord::FixtureSet.context_class</tt>.
|
125
|
+
#
|
126
|
+
# - define a helper method in `test_helper.rb`
|
127
|
+
# module FixtureFileHelpers
|
128
|
+
# def file_sha(path)
|
129
|
+
# Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
|
130
|
+
# end
|
131
|
+
# end
|
132
|
+
# ActiveRecord::FixtureSet.context_class.send :include, FixtureFileHelpers
|
133
|
+
#
|
134
|
+
# - use the helper method in a fixture
|
135
|
+
# photo:
|
136
|
+
# name: kitten.png
|
137
|
+
# sha: <%= file_sha 'files/kitten.png' %>
|
138
|
+
#
|
122
139
|
# = Transactional Fixtures
|
123
140
|
#
|
124
141
|
# Test cases can use begin+rollback to isolate their changes to the database instead of having to
|
@@ -379,22 +396,16 @@ module ActiveRecord
|
|
379
396
|
|
380
397
|
@@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
|
381
398
|
|
382
|
-
def self.
|
383
|
-
|
384
|
-
"ActiveRecord::Fixtures.find_table_name is deprecated and shall be removed from future releases. Use ActiveRecord::Fixtures.default_fixture_model_name instead.")
|
385
|
-
default_fixture_model_name(fixture_set_name)
|
386
|
-
end
|
387
|
-
|
388
|
-
def self.default_fixture_model_name(fixture_set_name) # :nodoc:
|
389
|
-
ActiveRecord::Base.pluralize_table_names ?
|
399
|
+
def self.default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
400
|
+
config.pluralize_table_names ?
|
390
401
|
fixture_set_name.singularize.camelize :
|
391
402
|
fixture_set_name.camelize
|
392
403
|
end
|
393
404
|
|
394
|
-
def self.default_fixture_table_name(fixture_set_name) # :nodoc:
|
395
|
-
"#{
|
405
|
+
def self.default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
406
|
+
"#{ config.table_name_prefix }"\
|
396
407
|
"#{ fixture_set_name.tr('/', '_') }"\
|
397
|
-
"#{
|
408
|
+
"#{ config.table_name_suffix }".to_sym
|
398
409
|
end
|
399
410
|
|
400
411
|
def self.reset_cache
|
@@ -442,9 +453,47 @@ module ActiveRecord
|
|
442
453
|
cattr_accessor :all_loaded_fixtures
|
443
454
|
self.all_loaded_fixtures = {}
|
444
455
|
|
445
|
-
|
456
|
+
class ClassCache
|
457
|
+
def initialize(class_names, config)
|
458
|
+
@class_names = class_names.stringify_keys
|
459
|
+
@config = config
|
460
|
+
|
461
|
+
# Remove string values that aren't constants or subclasses of AR
|
462
|
+
@class_names.delete_if { |k,klass|
|
463
|
+
unless klass.is_a? Class
|
464
|
+
klass = klass.safe_constantize
|
465
|
+
ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `set_fixture_class` will be removed in Rails 4.2. Use the class itself instead.")
|
466
|
+
end
|
467
|
+
!insert_class(@class_names, k, klass)
|
468
|
+
}
|
469
|
+
end
|
470
|
+
|
471
|
+
def [](fs_name)
|
472
|
+
@class_names.fetch(fs_name) {
|
473
|
+
klass = default_fixture_model(fs_name, @config).safe_constantize
|
474
|
+
insert_class(@class_names, fs_name, klass)
|
475
|
+
}
|
476
|
+
end
|
477
|
+
|
478
|
+
private
|
479
|
+
|
480
|
+
def insert_class(class_names, name, klass)
|
481
|
+
# We only want to deal with AR objects.
|
482
|
+
if klass && klass < ActiveRecord::Base
|
483
|
+
class_names[name] = klass
|
484
|
+
else
|
485
|
+
class_names[name] = nil
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
def default_fixture_model(fs_name, config)
|
490
|
+
ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
|
446
495
|
fixture_set_names = Array(fixture_set_names).map(&:to_s)
|
447
|
-
class_names = class_names
|
496
|
+
class_names = ClassCache.new class_names, config
|
448
497
|
|
449
498
|
# FIXME: Apparently JK uses this.
|
450
499
|
connection = block_given? ? yield : ActiveRecord::Base.connection
|
@@ -458,10 +507,12 @@ module ActiveRecord
|
|
458
507
|
fixtures_map = {}
|
459
508
|
|
460
509
|
fixture_sets = files_to_read.map do |fs_name|
|
510
|
+
klass = class_names[fs_name]
|
511
|
+
conn = klass ? klass.connection : connection
|
461
512
|
fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
|
462
|
-
|
513
|
+
conn,
|
463
514
|
fs_name,
|
464
|
-
|
515
|
+
klass,
|
465
516
|
::File.join(fixtures_directory, fs_name))
|
466
517
|
end
|
467
518
|
|
@@ -481,12 +532,10 @@ module ActiveRecord
|
|
481
532
|
conn.insert_fixture(row, fixture_set_name)
|
482
533
|
end
|
483
534
|
end
|
484
|
-
end
|
485
535
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
connection.reset_pk_sequence!(fs.table_name)
|
536
|
+
# Cap primary key sequences to max(pk).
|
537
|
+
if conn.respond_to?(:reset_pk_sequence!)
|
538
|
+
conn.reset_pk_sequence!(fs.table_name)
|
490
539
|
end
|
491
540
|
end
|
492
541
|
end
|
@@ -503,27 +552,36 @@ module ActiveRecord
|
|
503
552
|
Zlib.crc32(label.to_s) % MAX_ID
|
504
553
|
end
|
505
554
|
|
506
|
-
|
555
|
+
# Superclass for the evaluation contexts used by ERB fixtures.
|
556
|
+
def self.context_class
|
557
|
+
@context_class ||= Class.new
|
558
|
+
end
|
559
|
+
|
560
|
+
attr_reader :table_name, :name, :fixtures, :model_class, :config
|
507
561
|
|
508
|
-
def initialize(connection, name, class_name, path)
|
509
|
-
@fixtures = {} # Ordered hash
|
562
|
+
def initialize(connection, name, class_name, path, config = ActiveRecord::Base)
|
510
563
|
@name = name
|
511
564
|
@path = path
|
565
|
+
@config = config
|
566
|
+
@model_class = nil
|
567
|
+
|
568
|
+
if class_name.is_a?(String)
|
569
|
+
ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `FixtureSet.new` will be removed in Rails 4.2. Use the class itself instead.")
|
570
|
+
end
|
512
571
|
|
513
572
|
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
|
514
573
|
@model_class = class_name
|
515
574
|
else
|
516
|
-
@model_class = class_name.
|
575
|
+
@model_class = class_name.safe_constantize if class_name
|
517
576
|
end
|
518
577
|
|
519
|
-
@connection =
|
520
|
-
model_class.connection : connection )
|
578
|
+
@connection = connection
|
521
579
|
|
522
580
|
@table_name = ( model_class.respond_to?(:table_name) ?
|
523
581
|
model_class.table_name :
|
524
|
-
self.class.default_fixture_table_name(name) )
|
582
|
+
self.class.default_fixture_table_name(name, config) )
|
525
583
|
|
526
|
-
read_fixture_files
|
584
|
+
@fixtures = read_fixture_files path, @model_class
|
527
585
|
end
|
528
586
|
|
529
587
|
def [](x)
|
@@ -542,10 +600,10 @@ module ActiveRecord
|
|
542
600
|
fixtures.size
|
543
601
|
end
|
544
602
|
|
545
|
-
#
|
603
|
+
# Returns a hash of rows to be inserted. The key is the table, the value is
|
546
604
|
# a list of rows to insert to that table.
|
547
605
|
def table_rows
|
548
|
-
now =
|
606
|
+
now = config.default_timezone == :utc ? Time.now.utc : Time.now
|
549
607
|
now = now.to_s(:db)
|
550
608
|
|
551
609
|
# allow a standard key to be used for doing defaults in YAML
|
@@ -557,7 +615,7 @@ module ActiveRecord
|
|
557
615
|
rows[table_name] = fixtures.map do |label, fixture|
|
558
616
|
row = fixture.to_hash
|
559
617
|
|
560
|
-
if model_class
|
618
|
+
if model_class
|
561
619
|
# fill in timestamp columns if they aren't specified and the model is set to record_timestamps
|
562
620
|
if model_class.record_timestamps
|
563
621
|
timestamp_column_names.each do |c_name|
|
@@ -567,7 +625,7 @@ module ActiveRecord
|
|
567
625
|
|
568
626
|
# interpolate the fixture label
|
569
627
|
row.each do |key, value|
|
570
|
-
row[key] = label if
|
628
|
+
row[key] = label if "$LABEL" == value
|
571
629
|
end
|
572
630
|
|
573
631
|
# generate a primary key if necessary
|
@@ -583,7 +641,7 @@ module ActiveRecord
|
|
583
641
|
model_class
|
584
642
|
end
|
585
643
|
|
586
|
-
reflection_class.
|
644
|
+
reflection_class._reflections.values.each do |association|
|
587
645
|
case association.macro
|
588
646
|
when :belongs_to
|
589
647
|
# Do not replace association name with association foreign key if they are named the same
|
@@ -597,14 +655,9 @@ module ActiveRecord
|
|
597
655
|
|
598
656
|
row[fk_name] = ActiveRecord::FixtureSet.identify(value)
|
599
657
|
end
|
600
|
-
when :
|
601
|
-
if
|
602
|
-
|
603
|
-
table_name = association.join_table
|
604
|
-
rows[table_name].concat targets.map { |target|
|
605
|
-
{ association.foreign_key => row[primary_key_name],
|
606
|
-
association.association_foreign_key => ActiveRecord::FixtureSet.identify(target) }
|
607
|
-
}
|
658
|
+
when :has_many
|
659
|
+
if association.options[:through]
|
660
|
+
add_join_records(rows, row, HasManyThroughProxy.new(association))
|
608
661
|
end
|
609
662
|
end
|
610
663
|
end
|
@@ -615,11 +668,54 @@ module ActiveRecord
|
|
615
668
|
rows
|
616
669
|
end
|
617
670
|
|
671
|
+
class ReflectionProxy # :nodoc:
|
672
|
+
def initialize(association)
|
673
|
+
@association = association
|
674
|
+
end
|
675
|
+
|
676
|
+
def join_table
|
677
|
+
@association.join_table
|
678
|
+
end
|
679
|
+
|
680
|
+
def name
|
681
|
+
@association.name
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
class HasManyThroughProxy < ReflectionProxy # :nodoc:
|
686
|
+
def rhs_key
|
687
|
+
@association.foreign_key
|
688
|
+
end
|
689
|
+
|
690
|
+
def lhs_key
|
691
|
+
@association.through_reflection.foreign_key
|
692
|
+
end
|
693
|
+
|
694
|
+
def join_table
|
695
|
+
@association.through_reflection.table_name
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
618
699
|
private
|
619
700
|
def primary_key_name
|
620
701
|
@primary_key_name ||= model_class && model_class.primary_key
|
621
702
|
end
|
622
703
|
|
704
|
+
def add_join_records(rows, row, association)
|
705
|
+
# This is the case when the join table has no fixtures file
|
706
|
+
if (targets = row.delete(association.name.to_s))
|
707
|
+
table_name = association.join_table
|
708
|
+
lhs_key = association.lhs_key
|
709
|
+
rhs_key = association.rhs_key
|
710
|
+
|
711
|
+
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
|
712
|
+
rows[table_name].concat targets.map { |target|
|
713
|
+
{ lhs_key => row[primary_key_name],
|
714
|
+
rhs_key => ActiveRecord::FixtureSet.identify(target) }
|
715
|
+
}
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
623
719
|
def has_primary_key_column?
|
624
720
|
@has_primary_key_column ||= primary_key_name &&
|
625
721
|
model_class.columns.any? { |c| c.name == primary_key_name }
|
@@ -638,12 +734,12 @@ module ActiveRecord
|
|
638
734
|
@column_names ||= @connection.columns(@table_name).collect { |c| c.name }
|
639
735
|
end
|
640
736
|
|
641
|
-
def read_fixture_files
|
642
|
-
yaml_files = Dir["#{
|
737
|
+
def read_fixture_files(path, model_class)
|
738
|
+
yaml_files = Dir["#{path}/{**,*}/*.yml"].select { |f|
|
643
739
|
::File.file?(f)
|
644
|
-
} + [yaml_file_path]
|
740
|
+
} + [yaml_file_path(path)]
|
645
741
|
|
646
|
-
yaml_files.
|
742
|
+
yaml_files.each_with_object({}) do |file, fixtures|
|
647
743
|
FixtureSet::File.open(file) do |fh|
|
648
744
|
fh.each do |fixture_name, row|
|
649
745
|
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
|
@@ -652,8 +748,8 @@ module ActiveRecord
|
|
652
748
|
end
|
653
749
|
end
|
654
750
|
|
655
|
-
def yaml_file_path
|
656
|
-
"#{
|
751
|
+
def yaml_file_path(path)
|
752
|
+
"#{path}.yml"
|
657
753
|
end
|
658
754
|
|
659
755
|
end
|
@@ -696,7 +792,7 @@ module ActiveRecord
|
|
696
792
|
|
697
793
|
def find
|
698
794
|
if model_class
|
699
|
-
model_class.find(fixture[model_class.primary_key])
|
795
|
+
model_class.unscoped.find(fixture[model_class.primary_key])
|
700
796
|
else
|
701
797
|
raise FixtureClassNotFound, "No class attached to find."
|
702
798
|
end
|
@@ -725,14 +821,16 @@ module ActiveRecord
|
|
725
821
|
class_attribute :use_transactional_fixtures
|
726
822
|
class_attribute :use_instantiated_fixtures # true, false, or :no_instances
|
727
823
|
class_attribute :pre_loaded_fixtures
|
824
|
+
class_attribute :config
|
728
825
|
|
729
826
|
self.fixture_table_names = []
|
730
827
|
self.use_transactional_fixtures = true
|
731
828
|
self.use_instantiated_fixtures = false
|
732
829
|
self.pre_loaded_fixtures = false
|
830
|
+
self.config = ActiveRecord::Base
|
733
831
|
|
734
832
|
self.fixture_class_names = Hash.new do |h, fixture_set_name|
|
735
|
-
h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name)
|
833
|
+
h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name, self.config)
|
736
834
|
end
|
737
835
|
end
|
738
836
|
|
@@ -745,13 +843,6 @@ module ActiveRecord
|
|
745
843
|
# 'namespaced/fixture' => Another::Model
|
746
844
|
#
|
747
845
|
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
748
|
-
#--
|
749
|
-
# It is also possible to pass the class name instead of the class:
|
750
|
-
# set_fixture_class 'some_fixture' => 'SomeModel'
|
751
|
-
# I think this option is redundant, i propose to deprecate it.
|
752
|
-
# Isn't it easier to always pass the class itself?
|
753
|
-
# (2011-12-20 alexeymuranov)
|
754
|
-
#++
|
755
846
|
def set_fixture_class(class_names = {})
|
756
847
|
self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys)
|
757
848
|
end
|
@@ -765,22 +856,22 @@ module ActiveRecord
|
|
765
856
|
end
|
766
857
|
|
767
858
|
self.fixture_table_names |= fixture_set_names
|
768
|
-
require_fixture_classes(fixture_set_names)
|
859
|
+
require_fixture_classes(fixture_set_names, self.config)
|
769
860
|
setup_fixture_accessors(fixture_set_names)
|
770
861
|
end
|
771
862
|
|
772
863
|
def try_to_load_dependency(file_name)
|
773
864
|
require_dependency file_name
|
774
865
|
rescue LoadError => e
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
866
|
+
unless fixture_class_names.key?(file_name.pluralize)
|
867
|
+
if ActiveRecord::Base.logger
|
868
|
+
ActiveRecord::Base.logger.warn("Unable to load #{file_name}, make sure you added it to ActiveSupport::TestCase.set_fixture_class")
|
869
|
+
ActiveRecord::Base.logger.warn("underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
|
870
|
+
end
|
780
871
|
end
|
781
872
|
end
|
782
873
|
|
783
|
-
def require_fixture_classes(fixture_set_names = nil)
|
874
|
+
def require_fixture_classes(fixture_set_names = nil, config = ActiveRecord::Base)
|
784
875
|
if fixture_set_names
|
785
876
|
fixture_set_names = fixture_set_names.map { |n| n.to_s }
|
786
877
|
else
|
@@ -788,7 +879,7 @@ module ActiveRecord
|
|
788
879
|
end
|
789
880
|
|
790
881
|
fixture_set_names.each do |file_name|
|
791
|
-
file_name = file_name.singularize if
|
882
|
+
file_name = file_name.singularize if config.pluralize_table_names
|
792
883
|
try_to_load_dependency(file_name)
|
793
884
|
end
|
794
885
|
end
|
@@ -840,9 +931,7 @@ module ActiveRecord
|
|
840
931
|
!self.class.uses_transaction?(method_name)
|
841
932
|
end
|
842
933
|
|
843
|
-
def setup_fixtures
|
844
|
-
return if ActiveRecord::Base.configurations.blank?
|
845
|
-
|
934
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
846
935
|
if pre_loaded_fixtures && !use_transactional_fixtures
|
847
936
|
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
|
848
937
|
end
|
@@ -856,7 +945,7 @@ module ActiveRecord
|
|
856
945
|
if @@already_loaded_fixtures[self.class]
|
857
946
|
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
858
947
|
else
|
859
|
-
@loaded_fixtures = load_fixtures
|
948
|
+
@loaded_fixtures = load_fixtures(config)
|
860
949
|
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
861
950
|
end
|
862
951
|
@fixture_connections = enlist_fixture_connections
|
@@ -867,16 +956,14 @@ module ActiveRecord
|
|
867
956
|
else
|
868
957
|
ActiveRecord::FixtureSet.reset_cache
|
869
958
|
@@already_loaded_fixtures[self.class] = nil
|
870
|
-
@loaded_fixtures = load_fixtures
|
959
|
+
@loaded_fixtures = load_fixtures(config)
|
871
960
|
end
|
872
961
|
|
873
962
|
# Instantiate fixtures for every test if requested.
|
874
|
-
instantiate_fixtures if use_instantiated_fixtures
|
963
|
+
instantiate_fixtures(config) if use_instantiated_fixtures
|
875
964
|
end
|
876
965
|
|
877
966
|
def teardown_fixtures
|
878
|
-
return if ActiveRecord::Base.configurations.blank?
|
879
|
-
|
880
967
|
# Rollback changes if a transaction is active.
|
881
968
|
if run_in_transaction?
|
882
969
|
@fixture_connections.each do |connection|
|
@@ -895,19 +982,19 @@ module ActiveRecord
|
|
895
982
|
end
|
896
983
|
|
897
984
|
private
|
898
|
-
def load_fixtures
|
899
|
-
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
|
985
|
+
def load_fixtures(config)
|
986
|
+
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
|
900
987
|
Hash[fixtures.map { |f| [f.name, f] }]
|
901
988
|
end
|
902
989
|
|
903
990
|
# for pre_loaded_fixtures, only require the classes once. huge speed improvement
|
904
991
|
@@required_fixture_classes = false
|
905
992
|
|
906
|
-
def instantiate_fixtures
|
993
|
+
def instantiate_fixtures(config)
|
907
994
|
if pre_loaded_fixtures
|
908
995
|
raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
909
996
|
unless @@required_fixture_classes
|
910
|
-
self.class.require_fixture_classes ActiveRecord::FixtureSet.all_loaded_fixtures.keys
|
997
|
+
self.class.require_fixture_classes ActiveRecord::FixtureSet.all_loaded_fixtures.keys, config
|
911
998
|
@@required_fixture_classes = true
|
912
999
|
end
|
913
1000
|
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
@@ -924,3 +1011,13 @@ module ActiveRecord
|
|
924
1011
|
end
|
925
1012
|
end
|
926
1013
|
end
|
1014
|
+
|
1015
|
+
class ActiveRecord::FixtureSet::RenderContext # :nodoc:
|
1016
|
+
def self.create_subclass
|
1017
|
+
Class.new ActiveRecord::FixtureSet.context_class do
|
1018
|
+
def get_binding
|
1019
|
+
binding()
|
1020
|
+
end
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
# Returns the version of the currently loaded ActiveRecord as a <tt>Gem::Version</tt>
|
3
|
+
def self.gem_version
|
4
|
+
Gem::Version.new VERSION::STRING
|
5
|
+
end
|
6
|
+
|
7
|
+
module VERSION
|
8
|
+
MAJOR = 4
|
9
|
+
MINOR = 1
|
10
|
+
TINY = 16
|
11
|
+
PRE = nil
|
12
|
+
|
13
|
+
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
14
|
+
end
|
15
|
+
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
#
|
8
|
+
# Determines whether to store the full constant name including namespace when using STI.
|
9
9
|
class_attribute :store_full_sti_class, instance_writer: false
|
10
10
|
self.store_full_sti_class = true
|
11
11
|
end
|
@@ -13,10 +13,10 @@ module ActiveRecord
|
|
13
13
|
module ClassMethods
|
14
14
|
# Determines if one of the attributes passed in is the inheritance column,
|
15
15
|
# and if the inheritance column is attr accessible, it initializes an
|
16
|
-
# instance of the given subclass instead of the base class
|
16
|
+
# instance of the given subclass instead of the base class.
|
17
17
|
def new(*args, &block)
|
18
18
|
if abstract_class? || self == Base
|
19
|
-
raise NotImplementedError, "#{self} is an abstract class and
|
19
|
+
raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
|
20
20
|
end
|
21
21
|
|
22
22
|
attrs = args.first
|
@@ -31,7 +31,8 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
#
|
34
|
+
# Returns +true+ if this does not need STI type condition. Returns
|
35
|
+
# +false+ if STI type condition needs to be applied.
|
35
36
|
def descends_from_active_record?
|
36
37
|
if self == Base
|
37
38
|
false
|
@@ -48,10 +49,12 @@ module ActiveRecord
|
|
48
49
|
end
|
49
50
|
|
50
51
|
def symbolized_base_class
|
52
|
+
ActiveSupport::Deprecation.warn("ActiveRecord::Base.symbolized_base_class is deprecated and will be removed without replacement.")
|
51
53
|
@symbolized_base_class ||= base_class.to_s.to_sym
|
52
54
|
end
|
53
55
|
|
54
56
|
def symbolized_sti_name
|
57
|
+
ActiveSupport::Deprecation.warn("ActiveRecord::Base.symbolized_sti_name is deprecated and will be removed without replacement.")
|
55
58
|
@symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
|
56
59
|
end
|
57
60
|
|
@@ -120,13 +123,14 @@ module ActiveRecord
|
|
120
123
|
begin
|
121
124
|
constant = ActiveSupport::Dependencies.constantize(candidate)
|
122
125
|
return constant if candidate == constant.to_s
|
123
|
-
|
124
|
-
|
125
|
-
raise
|
126
|
+
# We don't want to swallow NoMethodError < NameError errors
|
127
|
+
rescue NoMethodError
|
128
|
+
raise
|
129
|
+
rescue NameError
|
126
130
|
end
|
127
131
|
end
|
128
132
|
|
129
|
-
raise NameError
|
133
|
+
raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
|
130
134
|
end
|
131
135
|
end
|
132
136
|
|
@@ -162,7 +166,7 @@ module ActiveRecord
|
|
162
166
|
end
|
163
167
|
|
164
168
|
def type_condition(table = arel_table)
|
165
|
-
sti_column = table[inheritance_column
|
169
|
+
sti_column = table[inheritance_column]
|
166
170
|
sti_names = ([self] + descendants).map { |model| model.sti_name }
|
167
171
|
|
168
172
|
sti_column.in(sti_names)
|
@@ -191,8 +195,18 @@ module ActiveRecord
|
|
191
195
|
end
|
192
196
|
end
|
193
197
|
|
198
|
+
def initialize_dup(other)
|
199
|
+
super
|
200
|
+
ensure_proper_type
|
201
|
+
end
|
202
|
+
|
194
203
|
private
|
195
204
|
|
205
|
+
def initialize_internals_callback
|
206
|
+
super
|
207
|
+
ensure_proper_type
|
208
|
+
end
|
209
|
+
|
196
210
|
# Sets the attribute used for single table inheritance to this class name if this is not the
|
197
211
|
# ActiveRecord::Base descendant.
|
198
212
|
# Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/string/filters'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Integration
|
3
5
|
extend ActiveSupport::Concern
|
@@ -45,10 +47,19 @@ module ActiveRecord
|
|
45
47
|
# Product.new.cache_key # => "products/new"
|
46
48
|
# Product.find(5).cache_key # => "products/5" (updated_at not available)
|
47
49
|
# Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
|
48
|
-
|
50
|
+
#
|
51
|
+
# You can also pass a list of named timestamps, and the newest in the list will be
|
52
|
+
# used to generate the key:
|
53
|
+
#
|
54
|
+
# Person.find(5).cache_key(:updated_at, :last_reviewed_at)
|
55
|
+
def cache_key(*timestamp_names)
|
49
56
|
case
|
50
57
|
when new_record?
|
51
58
|
"#{self.class.model_name.cache_key}/new"
|
59
|
+
when timestamp_names.any?
|
60
|
+
timestamp = max_updated_column_timestamp(timestamp_names)
|
61
|
+
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
62
|
+
"#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
|
52
63
|
when timestamp = max_updated_column_timestamp
|
53
64
|
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
54
65
|
"#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
|
@@ -56,5 +67,47 @@ module ActiveRecord
|
|
56
67
|
"#{self.class.model_name.cache_key}/#{id}"
|
57
68
|
end
|
58
69
|
end
|
70
|
+
|
71
|
+
module ClassMethods
|
72
|
+
# Defines your model's +to_param+ method to generate "pretty" URLs
|
73
|
+
# using +method_name+, which can be any attribute or method that
|
74
|
+
# responds to +to_s+.
|
75
|
+
#
|
76
|
+
# class User < ActiveRecord::Base
|
77
|
+
# to_param :name
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# user = User.find_by(name: 'Fancy Pants')
|
81
|
+
# user.id # => 123
|
82
|
+
# user_path(user) # => "/users/123-fancy-pants"
|
83
|
+
#
|
84
|
+
# Values longer than 20 characters will be truncated. The value
|
85
|
+
# is truncated word by word.
|
86
|
+
#
|
87
|
+
# user = User.find_by(name: 'David HeinemeierHansson')
|
88
|
+
# user.id # => 125
|
89
|
+
# user_path(user) # => "/users/125-david"
|
90
|
+
#
|
91
|
+
# Because the generated param begins with the record's +id+, it is
|
92
|
+
# suitable for passing to +find+. In a controller, for example:
|
93
|
+
#
|
94
|
+
# params[:id] # => "123-fancy-pants"
|
95
|
+
# User.find(params[:id]).id # => 123
|
96
|
+
def to_param(method_name = nil)
|
97
|
+
if method_name.nil?
|
98
|
+
super()
|
99
|
+
else
|
100
|
+
define_method :to_param do
|
101
|
+
if (default = super()) &&
|
102
|
+
(result = send(method_name).to_s).present? &&
|
103
|
+
(param = result.squish.truncate(20, separator: /\s/, omission: nil).parameterize).present?
|
104
|
+
"#{default}-#{param}"
|
105
|
+
else
|
106
|
+
default
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
59
112
|
end
|
60
113
|
end
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
send(lock_col + '=', previous_lock_value + 1)
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
69
|
+
def _update_record(attribute_names = @attributes.keys) #:nodoc:
|
70
70
|
return super unless locking_enabled?
|
71
71
|
return 0 if attribute_names.empty?
|
72
72
|
|
@@ -84,7 +84,10 @@ module ActiveRecord
|
|
84
84
|
relation.table[self.class.primary_key].eq(id).and(
|
85
85
|
relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
|
86
86
|
)
|
87
|
-
).arel.compile_update(
|
87
|
+
).arel.compile_update(
|
88
|
+
arel_attributes_with_values_for_update(attribute_names),
|
89
|
+
self.class.primary_key
|
90
|
+
)
|
88
91
|
|
89
92
|
affected_rows = self.class.connection.update stmt
|
90
93
|
|
@@ -138,6 +141,7 @@ module ActiveRecord
|
|
138
141
|
|
139
142
|
# Set the column to use for optimistic locking. Defaults to +lock_version+.
|
140
143
|
def locking_column=(value)
|
144
|
+
@column_defaults = nil
|
141
145
|
@locking_column = value.to_s
|
142
146
|
end
|
143
147
|
|
@@ -149,6 +153,7 @@ module ActiveRecord
|
|
149
153
|
|
150
154
|
# Quote the column name used for optimistic locking.
|
151
155
|
def quoted_locking_column
|
156
|
+
ActiveSupport::Deprecation.warn "ActiveRecord::Base.quoted_locking_column is deprecated and will be removed in Rails 4.2 or later."
|
152
157
|
connection.quote_column_name(locking_column)
|
153
158
|
end
|
154
159
|
|