activerecord 3.0.20 → 3.1.0.beta1
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.
- data/CHANGELOG +220 -91
- data/README.rdoc +3 -3
- data/examples/performance.rb +88 -109
- data/lib/active_record.rb +6 -2
- data/lib/active_record/aggregations.rb +22 -45
- data/lib/active_record/associations.rb +264 -991
- data/lib/active_record/associations/alias_tracker.rb +85 -0
- data/lib/active_record/associations/association.rb +231 -0
- data/lib/active_record/associations/association_scope.rb +120 -0
- data/lib/active_record/associations/belongs_to_association.rb +40 -60
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +15 -63
- data/lib/active_record/associations/builder/association.rb +53 -0
- data/lib/active_record/associations/builder/belongs_to.rb +85 -0
- data/lib/active_record/associations/builder/collection_association.rb +75 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +63 -0
- data/lib/active_record/associations/builder/has_many.rb +65 -0
- data/lib/active_record/associations/builder/has_one.rb +63 -0
- data/lib/active_record/associations/builder/singular_association.rb +32 -0
- data/lib/active_record/associations/collection_association.rb +524 -0
- data/lib/active_record/associations/collection_proxy.rb +125 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +27 -118
- data/lib/active_record/associations/has_many_association.rb +50 -79
- data/lib/active_record/associations/has_many_through_association.rb +98 -67
- data/lib/active_record/associations/has_one_association.rb +45 -115
- data/lib/active_record/associations/has_one_through_association.rb +21 -25
- data/lib/active_record/associations/join_dependency.rb +215 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +150 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
- data/lib/active_record/associations/join_helper.rb +56 -0
- data/lib/active_record/associations/preloader.rb +177 -0
- data/lib/active_record/associations/preloader/association.rb +126 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +67 -0
- data/lib/active_record/associations/singular_association.rb +55 -0
- data/lib/active_record/associations/through_association.rb +80 -0
- data/lib/active_record/attribute_methods.rb +19 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +9 -8
- data/lib/active_record/attribute_methods/dirty.rb +8 -2
- data/lib/active_record/attribute_methods/primary_key.rb +33 -13
- data/lib/active_record/attribute_methods/read.rb +17 -17
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -4
- data/lib/active_record/attribute_methods/write.rb +2 -1
- data/lib/active_record/autosave_association.rb +66 -45
- data/lib/active_record/base.rb +445 -273
- data/lib/active_record/callbacks.rb +24 -33
- data/lib/active_record/coders/yaml_column.rb +41 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +106 -13
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +16 -2
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -12
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +16 -16
- data/lib/active_record/connection_adapters/abstract/quoting.rb +61 -22
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +16 -273
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -42
- data/lib/active_record/connection_adapters/abstract_adapter.rb +44 -25
- data/lib/active_record/connection_adapters/column.rb +268 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +686 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +331 -88
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +295 -267
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -7
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +108 -26
- data/lib/active_record/counter_cache.rb +7 -4
- data/lib/active_record/fixtures.rb +174 -192
- data/lib/active_record/identity_map.rb +131 -0
- data/lib/active_record/locking/optimistic.rb +20 -14
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +24 -4
- data/lib/active_record/migration.rb +265 -144
- data/lib/active_record/migration/command_recorder.rb +103 -0
- data/lib/active_record/named_scope.rb +68 -25
- data/lib/active_record/nested_attributes.rb +58 -15
- data/lib/active_record/observer.rb +3 -7
- data/lib/active_record/persistence.rb +58 -38
- data/lib/active_record/query_cache.rb +25 -3
- data/lib/active_record/railtie.rb +21 -12
- data/lib/active_record/railties/console_sandbox.rb +6 -0
- data/lib/active_record/railties/databases.rake +147 -116
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/reflection.rb +176 -44
- data/lib/active_record/relation.rb +125 -49
- data/lib/active_record/relation/batches.rb +7 -5
- data/lib/active_record/relation/calculations.rb +50 -18
- data/lib/active_record/relation/finder_methods.rb +47 -26
- data/lib/active_record/relation/predicate_builder.rb +24 -21
- data/lib/active_record/relation/query_methods.rb +117 -101
- data/lib/active_record/relation/spawn_methods.rb +27 -20
- data/lib/active_record/result.rb +34 -0
- data/lib/active_record/schema.rb +5 -6
- data/lib/active_record/schema_dumper.rb +11 -13
- data/lib/active_record/serialization.rb +2 -2
- data/lib/active_record/serializers/xml_serializer.rb +10 -10
- data/lib/active_record/session_store.rb +8 -2
- data/lib/active_record/test_case.rb +9 -20
- data/lib/active_record/timestamp.rb +21 -9
- data/lib/active_record/transactions.rb +16 -15
- data/lib/active_record/validations.rb +21 -22
- data/lib/active_record/validations/associated.rb +3 -1
- data/lib/active_record/validations/uniqueness.rb +48 -58
- data/lib/active_record/version.rb +3 -3
- data/lib/rails/generators/active_record.rb +6 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +10 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -1
- data/lib/rails/generators/active_record/model/templates/migration.rb +6 -5
- data/lib/rails/generators/active_record/model/templates/model.rb +2 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +2 -0
- data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +2 -1
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +2 -2
- metadata +106 -77
- checksums.yaml +0 -7
- data/lib/active_record/association_preload.rb +0 -431
- data/lib/active_record/associations/association_collection.rb +0 -572
- data/lib/active_record/associations/association_proxy.rb +0 -304
- data/lib/active_record/associations/through_association_scope.rb +0 -160
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class Preloader
|
4
|
+
class HasMany < CollectionAssociation #:nodoc:
|
5
|
+
|
6
|
+
def association_key_name
|
7
|
+
reflection.foreign_key
|
8
|
+
end
|
9
|
+
|
10
|
+
def owner_key_name
|
11
|
+
reflection.active_record_primary_key
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class Preloader
|
4
|
+
class HasManyThrough < CollectionAssociation #:nodoc:
|
5
|
+
include ThroughAssociation
|
6
|
+
|
7
|
+
def associated_records_by_owner
|
8
|
+
super.each do |owner, records|
|
9
|
+
records.uniq! if options[:uniq]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class Preloader
|
4
|
+
class HasOne < SingularAssociation #:nodoc:
|
5
|
+
|
6
|
+
def association_key_name
|
7
|
+
reflection.foreign_key
|
8
|
+
end
|
9
|
+
|
10
|
+
def owner_key_name
|
11
|
+
reflection.active_record_primary_key
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def build_scope
|
17
|
+
super.order(preload_options[:order] || options[:order])
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class Preloader
|
4
|
+
class SingularAssociation < Association #:nodoc:
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def preload
|
9
|
+
associated_records_by_owner.each do |owner, associated_records|
|
10
|
+
record = associated_records.first
|
11
|
+
|
12
|
+
association = owner.association(reflection.name)
|
13
|
+
association.target = record
|
14
|
+
association.set_inverse_instance(record)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class Preloader
|
4
|
+
module ThroughAssociation #:nodoc:
|
5
|
+
|
6
|
+
def through_reflection
|
7
|
+
reflection.through_reflection
|
8
|
+
end
|
9
|
+
|
10
|
+
def source_reflection
|
11
|
+
reflection.source_reflection
|
12
|
+
end
|
13
|
+
|
14
|
+
def associated_records_by_owner
|
15
|
+
through_records = through_records_by_owner
|
16
|
+
|
17
|
+
ActiveRecord::Associations::Preloader.new(
|
18
|
+
through_records.values.flatten,
|
19
|
+
source_reflection.name, options
|
20
|
+
).run
|
21
|
+
|
22
|
+
through_records.each do |owner, records|
|
23
|
+
records.map! { |r| r.send(source_reflection.name) }.flatten!
|
24
|
+
records.compact!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def through_records_by_owner
|
31
|
+
ActiveRecord::Associations::Preloader.new(
|
32
|
+
owners, through_reflection.name,
|
33
|
+
through_options
|
34
|
+
).run
|
35
|
+
|
36
|
+
Hash[owners.map do |owner|
|
37
|
+
through_records = Array.wrap(owner.send(through_reflection.name))
|
38
|
+
|
39
|
+
# Dont cache the association - we would only be caching a subset
|
40
|
+
if reflection.options[:source_type] && through_reflection.collection?
|
41
|
+
owner.association(through_reflection.name).reset
|
42
|
+
end
|
43
|
+
|
44
|
+
[owner, through_records]
|
45
|
+
end]
|
46
|
+
end
|
47
|
+
|
48
|
+
def through_options
|
49
|
+
through_options = {}
|
50
|
+
|
51
|
+
if options[:source_type]
|
52
|
+
through_options[:conditions] = { reflection.foreign_type => options[:source_type] }
|
53
|
+
else
|
54
|
+
if options[:conditions]
|
55
|
+
through_options[:include] = options[:include] || options[:source]
|
56
|
+
through_options[:conditions] = options[:conditions]
|
57
|
+
end
|
58
|
+
|
59
|
+
through_options[:order] = options[:order]
|
60
|
+
end
|
61
|
+
|
62
|
+
through_options
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class SingularAssociation < Association #:nodoc:
|
4
|
+
# Implements the reader method, e.g. foo.bar for Foo.has_one :bar
|
5
|
+
def reader(force_reload = false)
|
6
|
+
if force_reload
|
7
|
+
klass.uncached { reload }
|
8
|
+
elsif !loaded? || stale_target?
|
9
|
+
reload
|
10
|
+
end
|
11
|
+
|
12
|
+
target
|
13
|
+
end
|
14
|
+
|
15
|
+
# Implements the writer method, e.g. foo.items= for Foo.has_many :items
|
16
|
+
def writer(record)
|
17
|
+
replace(record)
|
18
|
+
end
|
19
|
+
|
20
|
+
def create(attributes = {}, options = {})
|
21
|
+
new_record(:create, attributes, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create!(attributes = {}, options = {})
|
25
|
+
build(attributes, options).tap { |record| record.save! }
|
26
|
+
end
|
27
|
+
|
28
|
+
def build(attributes = {}, options = {})
|
29
|
+
new_record(:build, attributes, options)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def find_target
|
35
|
+
scoped.first.tap { |record| set_inverse_instance(record) }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Implemented by subclasses
|
39
|
+
def replace(record)
|
40
|
+
raise NotImplementedError, "Subclasses must implement a replace(record) method"
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_new_record(record)
|
44
|
+
replace(record)
|
45
|
+
end
|
46
|
+
|
47
|
+
def new_record(method, attributes, options)
|
48
|
+
attributes = scoped.scope_for_create.merge(attributes || {})
|
49
|
+
record = reflection.send("#{method}_association", attributes, options)
|
50
|
+
set_new_record(record)
|
51
|
+
record
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
# = Active Record Through Association
|
3
|
+
module Associations
|
4
|
+
module ThroughAssociation #:nodoc:
|
5
|
+
|
6
|
+
delegate :source_reflection, :through_reflection, :chain, :to => :reflection
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
# We merge in these scopes for two reasons:
|
11
|
+
#
|
12
|
+
# 1. To get the default_scope conditions for any of the other reflections in the chain
|
13
|
+
# 2. To get the type conditions for any STI models in the chain
|
14
|
+
def target_scope
|
15
|
+
scope = super
|
16
|
+
chain[1..-1].each do |reflection|
|
17
|
+
scope = scope.merge(reflection.klass.scoped)
|
18
|
+
end
|
19
|
+
scope
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Construct attributes for :through pointing to owner and associate. This is used by the
|
25
|
+
# methods which create and delete records on the association.
|
26
|
+
#
|
27
|
+
# We only support indirectly modifying through associations which has a belongs_to source.
|
28
|
+
# This is the "has_many :tags, :through => :taggings" situation, where the join model
|
29
|
+
# typically has a belongs_to on both side. In other words, associations which could also
|
30
|
+
# be represented as has_and_belongs_to_many associations.
|
31
|
+
#
|
32
|
+
# We do not support creating/deleting records on the association where the source has
|
33
|
+
# some other type, because this opens up a whole can of worms, and in basically any
|
34
|
+
# situation it is more natural for the user to just create or modify their join records
|
35
|
+
# directly as required.
|
36
|
+
def construct_join_attributes(*records)
|
37
|
+
if source_reflection.macro != :belongs_to
|
38
|
+
raise HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection)
|
39
|
+
end
|
40
|
+
|
41
|
+
join_attributes = {
|
42
|
+
source_reflection.foreign_key =>
|
43
|
+
records.map { |record|
|
44
|
+
record.send(source_reflection.association_primary_key)
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
if options[:source_type]
|
49
|
+
join_attributes[source_reflection.foreign_type] =
|
50
|
+
records.map { |record| record.class.base_class.name }
|
51
|
+
end
|
52
|
+
|
53
|
+
if records.count == 1
|
54
|
+
Hash[join_attributes.map { |k, v| [k, v.first] }]
|
55
|
+
else
|
56
|
+
join_attributes
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Note: this does not capture all cases, for example it would be crazy to try to
|
61
|
+
# properly support stale-checking for nested associations.
|
62
|
+
def stale_state
|
63
|
+
if through_reflection.macro == :belongs_to
|
64
|
+
owner[through_reflection.foreign_key].to_s
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def foreign_key_present?
|
69
|
+
through_reflection.macro == :belongs_to &&
|
70
|
+
!owner[through_reflection.foreign_key].nil?
|
71
|
+
end
|
72
|
+
|
73
|
+
def ensure_not_nested
|
74
|
+
if reflection.nested?
|
75
|
+
raise HasManyThroughNestedAssociationsAreReadonly.new(owner, reflection)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -10,7 +10,18 @@ module ActiveRecord
|
|
10
10
|
# Generates all the attribute related methods for columns in the database
|
11
11
|
# accessors, mutators and query methods.
|
12
12
|
def define_attribute_methods
|
13
|
-
|
13
|
+
return if attribute_methods_generated?
|
14
|
+
super(column_names)
|
15
|
+
@attribute_methods_generated = true
|
16
|
+
end
|
17
|
+
|
18
|
+
def attribute_methods_generated?
|
19
|
+
@attribute_methods_generated ||= false
|
20
|
+
end
|
21
|
+
|
22
|
+
def undefine_attribute_methods(*args)
|
23
|
+
super
|
24
|
+
@attribute_methods_generated = false
|
14
25
|
end
|
15
26
|
|
16
27
|
# Checks whether the method is defined in the model or any of its subclasses
|
@@ -18,7 +29,11 @@ module ActiveRecord
|
|
18
29
|
# method is defined by Active Record though.
|
19
30
|
def instance_method_already_implemented?(method_name)
|
20
31
|
method_name = method_name.to_s
|
21
|
-
|
32
|
+
index = ancestors.index(ActiveRecord::Base) || ancestors.length
|
33
|
+
@_defined_class_methods ||= ancestors.first(index).map { |m|
|
34
|
+
m.instance_methods(false) | m.private_instance_methods(false)
|
35
|
+
}.flatten.map {|m| m.to_s }.to_set
|
36
|
+
|
22
37
|
@@_defined_activerecord_methods ||= defined_activerecord_methods
|
23
38
|
raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord" if @@_defined_activerecord_methods.include?(method_name)
|
24
39
|
@_defined_class_methods.include?(method_name)
|
@@ -27,9 +42,8 @@ module ActiveRecord
|
|
27
42
|
def defined_activerecord_methods
|
28
43
|
active_record = ActiveRecord::Base
|
29
44
|
super_klass = ActiveRecord::Base.superclass
|
30
|
-
methods =
|
31
|
-
|
32
|
-
methods += active_record.protected_instance_methods - super_klass.protected_instance_methods
|
45
|
+
methods = (active_record.instance_methods - super_klass.instance_methods) +
|
46
|
+
(active_record.private_instance_methods - super_klass.private_instance_methods)
|
33
47
|
methods.map {|m| m.to_s }.to_set
|
34
48
|
end
|
35
49
|
end
|
@@ -13,18 +13,19 @@ module ActiveRecord
|
|
13
13
|
|
14
14
|
# Returns a hash of attributes before typecasting and deserialization.
|
15
15
|
def attributes_before_type_cast
|
16
|
-
|
16
|
+
@attributes
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
|
21
|
+
# Handle *_before_type_cast for method_missing.
|
22
|
+
def attribute_before_type_cast(attribute_name)
|
23
|
+
if attribute_name == 'id'
|
24
|
+
read_attribute_before_type_cast(self.class.primary_key)
|
25
|
+
else
|
26
|
+
read_attribute_before_type_cast(attribute_name)
|
27
27
|
end
|
28
|
+
end
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
1
2
|
require 'active_support/core_ext/object/blank'
|
2
3
|
|
3
4
|
module ActiveRecord
|
@@ -12,7 +13,7 @@ module ActiveRecord
|
|
12
13
|
raise "You cannot include Dirty after Timestamp"
|
13
14
|
end
|
14
15
|
|
15
|
-
|
16
|
+
class_attribute :partial_updates
|
16
17
|
self.partial_updates = true
|
17
18
|
end
|
18
19
|
|
@@ -21,6 +22,8 @@ module ActiveRecord
|
|
21
22
|
if status = super
|
22
23
|
@previously_changed = changes
|
23
24
|
@changed_attributes.clear
|
25
|
+
elsif IdentityMap.enabled?
|
26
|
+
IdentityMap.remove(self)
|
24
27
|
end
|
25
28
|
status
|
26
29
|
end
|
@@ -31,6 +34,9 @@ module ActiveRecord
|
|
31
34
|
@previously_changed = changes
|
32
35
|
@changed_attributes.clear
|
33
36
|
end
|
37
|
+
rescue
|
38
|
+
IdentityMap.remove(self) if IdentityMap.enabled?
|
39
|
+
raise
|
34
40
|
end
|
35
41
|
|
36
42
|
# <tt>reload</tt> the record and clears changed attributes.
|
@@ -88,7 +94,7 @@ module ActiveRecord
|
|
88
94
|
end
|
89
95
|
|
90
96
|
def clone_with_time_zone_conversion_attribute?(attr, old)
|
91
|
-
old.class.name == "Time" && time_zone_aware_attributes && !skip_time_zone_conversion_for_attributes.include?(attr.to_sym)
|
97
|
+
old.class.name == "Time" && time_zone_aware_attributes && !self.skip_time_zone_conversion_for_attributes.include?(attr.to_sym)
|
92
98
|
end
|
93
99
|
end
|
94
100
|
end
|
@@ -3,17 +3,18 @@ module ActiveRecord
|
|
3
3
|
module PrimaryKey
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
# Returns this record's primary key value wrapped in an Array
|
7
|
-
#
|
6
|
+
# Returns this record's primary key value wrapped in an Array or nil if
|
7
|
+
# the record is not persisted? or has just been destroyed.
|
8
8
|
def to_key
|
9
|
-
|
9
|
+
key = send(self.class.primary_key)
|
10
|
+
[key] if key
|
10
11
|
end
|
11
12
|
|
12
13
|
module ClassMethods
|
13
14
|
# Defines the primary key field -- can be overridden in subclasses. Overwriting will negate any effect of the
|
14
15
|
# primary_key_prefix_type setting, though.
|
15
16
|
def primary_key
|
16
|
-
reset_primary_key
|
17
|
+
@primary_key ||= reset_primary_key
|
17
18
|
end
|
18
19
|
|
19
20
|
# Returns a quoted version of the primary key name, used to construct SQL statements.
|
@@ -22,20 +23,36 @@ module ActiveRecord
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def reset_primary_key #:nodoc:
|
25
|
-
key = get_primary_key(base_class.name)
|
26
|
+
key = self == base_class ? get_primary_key(base_class.name) :
|
27
|
+
base_class.primary_key
|
28
|
+
|
26
29
|
set_primary_key(key)
|
27
30
|
key
|
28
31
|
end
|
29
32
|
|
30
33
|
def get_primary_key(base_name) #:nodoc:
|
31
|
-
|
34
|
+
return 'id' unless base_name && !base_name.blank?
|
35
|
+
|
32
36
|
case primary_key_prefix_type
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
+
when :table_name
|
38
|
+
base_name.foreign_key(false)
|
39
|
+
when :table_name_with_underscore
|
40
|
+
base_name.foreign_key
|
41
|
+
else
|
42
|
+
if ActiveRecord::Base != self && connection.table_exists?(table_name)
|
43
|
+
connection.primary_key(table_name)
|
44
|
+
else
|
45
|
+
'id'
|
46
|
+
end
|
37
47
|
end
|
38
|
-
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_accessor :original_primary_key
|
51
|
+
|
52
|
+
# Attribute writer for the primary key column
|
53
|
+
def primary_key=(value)
|
54
|
+
@quoted_primary_key = nil
|
55
|
+
@primary_key = value
|
39
56
|
end
|
40
57
|
|
41
58
|
# Sets the name of the primary key column to use to the given value,
|
@@ -47,9 +64,12 @@ module ActiveRecord
|
|
47
64
|
# end
|
48
65
|
def set_primary_key(value = nil, &block)
|
49
66
|
@quoted_primary_key = nil
|
50
|
-
|
67
|
+
@primary_key ||= ''
|
68
|
+
self.original_primary_key = @primary_key
|
69
|
+
value &&= value.to_s
|
70
|
+
connection_pool.primary_keys[table_name] = value
|
71
|
+
self.primary_key = block_given? ? instance_eval(&block) : value
|
51
72
|
end
|
52
|
-
alias :primary_key= :set_primary_key
|
53
73
|
end
|
54
74
|
end
|
55
75
|
end
|