activerecord 4.0.0.beta1 → 4.0.0.rc1
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 +573 -30
- data/README.rdoc +3 -3
- data/lib/active_record.rb +8 -2
- data/lib/active_record/associations.rb +16 -9
- data/lib/active_record/associations/association.rb +8 -6
- data/lib/active_record/associations/association_scope.rb +2 -1
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/belongs_to.rb +37 -5
- data/lib/active_record/associations/collection_association.rb +38 -14
- data/lib/active_record/associations/collection_proxy.rb +18 -15
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +3 -3
- data/lib/active_record/associations/has_many_association.rb +4 -3
- data/lib/active_record/associations/has_many_through_association.rb +1 -1
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +29 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +26 -6
- data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_part.rb +6 -6
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +5 -5
- data/lib/active_record/attribute_methods.rb +20 -5
- data/lib/active_record/attribute_methods/dirty.rb +5 -1
- data/lib/active_record/attribute_methods/primary_key.rb +1 -1
- data/lib/active_record/attribute_methods/serialization.rb +9 -2
- data/lib/active_record/autosave_association.rb +19 -5
- data/lib/active_record/base.rb +3 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +8 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +3 -9
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +2 -8
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +60 -61
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +291 -153
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +92 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +55 -29
- data/lib/active_record/connection_adapters/column.rb +4 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -3
- data/lib/active_record/connection_adapters/mysql_adapter.rb +5 -5
- data/lib/active_record/connection_adapters/postgresql/cast.rb +22 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -9
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +53 -24
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -5
- data/lib/active_record/connection_handling.rb +7 -7
- data/lib/active_record/core.rb +43 -8
- data/lib/active_record/counter_cache.rb +2 -1
- data/lib/active_record/errors.rb +11 -10
- data/lib/active_record/explain.rb +9 -7
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +3 -2
- data/lib/active_record/fixture_set/file.rb +1 -2
- data/lib/active_record/fixtures.rb +13 -7
- data/lib/active_record/inheritance.rb +12 -4
- data/lib/active_record/integration.rb +3 -3
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/log_subscriber.rb +2 -2
- data/lib/active_record/migration.rb +69 -21
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +98 -46
- data/lib/active_record/persistence.rb +3 -3
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +18 -4
- data/lib/active_record/railties/console_sandbox.rb +3 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -1
- data/lib/active_record/railties/databases.rake +38 -80
- data/lib/active_record/reflection.rb +36 -3
- data/lib/active_record/relation.rb +18 -8
- data/lib/active_record/relation/calculations.rb +10 -5
- data/lib/active_record/relation/delegation.rb +3 -5
- data/lib/active_record/relation/finder_methods.rb +27 -14
- data/lib/active_record/relation/merger.rb +30 -2
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_methods.rb +113 -16
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/schema_dumper.rb +5 -1
- data/lib/active_record/schema_migration.rb +8 -5
- data/lib/active_record/scoping.rb +56 -2
- data/lib/active_record/scoping/default.rb +12 -11
- data/lib/active_record/scoping/named.rb +7 -3
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/tasks/database_tasks.rb +55 -10
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -2
- data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
- data/lib/active_record/timestamp.rb +6 -0
- data/lib/active_record/transactions.rb +7 -3
- data/lib/active_record/validations.rb +1 -2
- data/lib/active_record/validations/uniqueness.rb +7 -3
- data/lib/active_record/version.rb +7 -6
- data/lib/rails/generators/active_record/migration/migration_generator.rb +9 -2
- data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +4 -1
- metadata +17 -12
- data/examples/associations.png +0 -0
@@ -83,16 +83,16 @@ module ActiveRecord
|
|
83
83
|
# # #<Pet id: 3, name: "Choo-Choo">
|
84
84
|
# # ]
|
85
85
|
#
|
86
|
-
# Be careful because this also means you
|
87
|
-
# object with only the fields that you
|
88
|
-
# to access a field that is not in the initialized record you
|
86
|
+
# Be careful because this also means you're initializing a model
|
87
|
+
# object with only the fields that you've selected. If you attempt
|
88
|
+
# to access a field that is not in the initialized record you'll
|
89
89
|
# receive:
|
90
90
|
#
|
91
91
|
# person.pets.select(:name).first.person_id
|
92
92
|
# # => ActiveModel::MissingAttributeError: missing attribute: person_id
|
93
93
|
#
|
94
94
|
# *Second:* You can pass a block so it can be used just like Array#select.
|
95
|
-
# This
|
95
|
+
# This builds an array of objects from the database for the scope,
|
96
96
|
# converting them into an array and iterating through them using
|
97
97
|
# Array#select.
|
98
98
|
#
|
@@ -228,6 +228,7 @@ module ActiveRecord
|
|
228
228
|
def build(attributes = {}, &block)
|
229
229
|
@association.build(attributes, &block)
|
230
230
|
end
|
231
|
+
alias_method :new, :build
|
231
232
|
|
232
233
|
# Returns a new object of the collection type that has been instantiated with
|
233
234
|
# attributes, linked to this object and that has already been saved (if it
|
@@ -303,7 +304,7 @@ module ActiveRecord
|
|
303
304
|
@association.concat(*records)
|
304
305
|
end
|
305
306
|
|
306
|
-
#
|
307
|
+
# Replaces this collection with +other_array+. This will perform a diff
|
307
308
|
# and delete/add only records that have changed.
|
308
309
|
#
|
309
310
|
# class Person < ActiveRecord::Base
|
@@ -649,11 +650,12 @@ module ActiveRecord
|
|
649
650
|
# # #<Pet name: "Fancy-Fancy">
|
650
651
|
# # ]
|
651
652
|
#
|
652
|
-
# person.pets.select(:name).
|
653
|
+
# person.pets.select(:name).distinct
|
653
654
|
# # => [#<Pet name: "Fancy-Fancy">]
|
654
|
-
def
|
655
|
-
@association.
|
655
|
+
def distinct
|
656
|
+
@association.distinct
|
656
657
|
end
|
658
|
+
alias uniq distinct
|
657
659
|
|
658
660
|
# Count all records using SQL.
|
659
661
|
#
|
@@ -831,8 +833,6 @@ module ActiveRecord
|
|
831
833
|
@association.include?(record)
|
832
834
|
end
|
833
835
|
|
834
|
-
alias_method :new, :build
|
835
|
-
|
836
836
|
def proxy_association
|
837
837
|
@association
|
838
838
|
end
|
@@ -847,10 +847,8 @@ module ActiveRecord
|
|
847
847
|
|
848
848
|
# Returns a <tt>Relation</tt> object for the records in this association
|
849
849
|
def scope
|
850
|
-
association
|
851
|
-
|
852
|
-
@association.scope.extending! do
|
853
|
-
define_method(:proxy_association) { association }
|
850
|
+
@association.scope.tap do |scope|
|
851
|
+
scope.proxy_association = @association
|
854
852
|
end
|
855
853
|
end
|
856
854
|
|
@@ -924,7 +922,7 @@ module ActiveRecord
|
|
924
922
|
alias_method :to_a, :to_ary
|
925
923
|
|
926
924
|
# Adds one or more +records+ to the collection by setting their foreign keys
|
927
|
-
# to the association
|
925
|
+
# to the association's primary key. Returns +self+, so several appends may be
|
928
926
|
# chained together.
|
929
927
|
#
|
930
928
|
# class Person < ActiveRecord::Base
|
@@ -947,6 +945,11 @@ module ActiveRecord
|
|
947
945
|
proxy_association.concat(records) && self
|
948
946
|
end
|
949
947
|
alias_method :push, :<<
|
948
|
+
alias_method :append, :<<
|
949
|
+
|
950
|
+
def prepend(*args)
|
951
|
+
raise NoMethodError, "prepend on association is not defined. Please use << or append"
|
952
|
+
end
|
950
953
|
|
951
954
|
# Equivalent to +delete_all+. The difference is that returns +self+, instead
|
952
955
|
# of an array with the deleted objects, so methods can be chained. See
|
@@ -26,7 +26,7 @@ module ActiveRecord
|
|
26
26
|
join_table[reflection.association_foreign_key] => record.id
|
27
27
|
)
|
28
28
|
|
29
|
-
owner.connection.insert stmt
|
29
|
+
owner.class.connection.insert stmt
|
30
30
|
end
|
31
31
|
|
32
32
|
record
|
@@ -41,7 +41,7 @@ module ActiveRecord
|
|
41
41
|
def delete_records(records, method)
|
42
42
|
if sql = options[:delete_sql]
|
43
43
|
records = load_target if records == :all
|
44
|
-
records.each { |record| owner.connection.delete(interpolate(sql, record)) }
|
44
|
+
records.each { |record| owner.class.connection.delete(interpolate(sql, record)) }
|
45
45
|
else
|
46
46
|
relation = join_table
|
47
47
|
condition = relation[reflection.foreign_key].eq(owner.id)
|
@@ -53,7 +53,7 @@ module ActiveRecord
|
|
53
53
|
)
|
54
54
|
end
|
55
55
|
|
56
|
-
owner.connection.delete(relation.where(condition).compile_delete)
|
56
|
+
owner.class.connection.delete(relation.where(condition).compile_delete)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -22,10 +22,11 @@ module ActiveRecord
|
|
22
22
|
else
|
23
23
|
if options[:dependent] == :destroy
|
24
24
|
# No point in executing the counter update since we're going to destroy the parent anyway
|
25
|
-
load_target.each
|
25
|
+
load_target.each { |t| t.destroyed_by_association = reflection }
|
26
|
+
destroy_all
|
27
|
+
else
|
28
|
+
delete_all
|
26
29
|
end
|
27
|
-
|
28
|
-
delete_all
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
@@ -5,10 +5,31 @@ module ActiveRecord
|
|
5
5
|
autoload :JoinBase, 'active_record/associations/join_dependency/join_base'
|
6
6
|
autoload :JoinAssociation, 'active_record/associations/join_dependency/join_association'
|
7
7
|
|
8
|
-
attr_reader :join_parts, :reflections, :alias_tracker, :
|
9
|
-
|
8
|
+
attr_reader :join_parts, :reflections, :alias_tracker, :base_klass
|
9
|
+
|
10
|
+
# base is the base class on which operation is taking place.
|
11
|
+
# associations is the list of associations which are joined using hash, symbol or array.
|
12
|
+
# joins is the list of all string join commnads and arel nodes.
|
13
|
+
#
|
14
|
+
# Example :
|
15
|
+
#
|
16
|
+
# class Physician < ActiveRecord::Base
|
17
|
+
# has_many :appointments
|
18
|
+
# has_many :patients, through: :appointments
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# If I execute `@physician.patients.to_a` then
|
22
|
+
# base #=> Physician
|
23
|
+
# associations #=> []
|
24
|
+
# joins #=> [#<Arel::Nodes::InnerJoin: ...]
|
25
|
+
#
|
26
|
+
# However if I execute `Physician.joins(:appointments).to_a` then
|
27
|
+
# base #=> Physician
|
28
|
+
# associations #=> [:appointments]
|
29
|
+
# joins #=> []
|
30
|
+
#
|
10
31
|
def initialize(base, associations, joins)
|
11
|
-
@
|
32
|
+
@base_klass = base
|
12
33
|
@table_joins = joins
|
13
34
|
@join_parts = [JoinBase.new(base)]
|
14
35
|
@associations = {}
|
@@ -54,10 +75,12 @@ module ActiveRecord
|
|
54
75
|
parent
|
55
76
|
}.uniq
|
56
77
|
|
57
|
-
remove_duplicate_results!(
|
78
|
+
remove_duplicate_results!(base_klass, records, @associations)
|
58
79
|
records
|
59
80
|
end
|
60
81
|
|
82
|
+
protected
|
83
|
+
|
61
84
|
def remove_duplicate_results!(base, records, associations)
|
62
85
|
case associations
|
63
86
|
when Symbol, String
|
@@ -88,8 +111,6 @@ module ActiveRecord
|
|
88
111
|
end
|
89
112
|
end
|
90
113
|
|
91
|
-
protected
|
92
|
-
|
93
114
|
def cache_joined_association(association)
|
94
115
|
associations = []
|
95
116
|
parent = association.parent
|
@@ -108,8 +129,8 @@ module ActiveRecord
|
|
108
129
|
parent ||= join_parts.last
|
109
130
|
case associations
|
110
131
|
when Symbol, String
|
111
|
-
reflection = parent.reflections[associations.
|
112
|
-
raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?"
|
132
|
+
reflection = parent.reflections[associations.intern] or
|
133
|
+
raise ConfigurationError, "Association named '#{ associations }' was not found on #{ parent.base_klass.name }; perhaps you misspelled it?"
|
113
134
|
unless join_association = find_join_association(reflection, parent)
|
114
135
|
@reflections << reflection
|
115
136
|
join_association = build_join_association(reflection, parent)
|
@@ -55,14 +55,19 @@ module ActiveRecord
|
|
55
55
|
|
56
56
|
def find_parent_in(other_join_dependency)
|
57
57
|
other_join_dependency.join_parts.detect do |join_part|
|
58
|
-
parent
|
58
|
+
case parent
|
59
|
+
when JoinBase
|
60
|
+
parent.base_klass == join_part.base_klass
|
61
|
+
else
|
62
|
+
parent == join_part
|
63
|
+
end
|
59
64
|
end
|
60
65
|
end
|
61
66
|
|
62
|
-
def join_to(
|
67
|
+
def join_to(manager)
|
63
68
|
tables = @tables.dup
|
64
69
|
foreign_table = parent_table
|
65
|
-
foreign_klass = parent.
|
70
|
+
foreign_klass = parent.base_klass
|
66
71
|
|
67
72
|
# The chain starts with the target table, but we want to end with it here (makes
|
68
73
|
# more sense in this context), so we reverse
|
@@ -75,7 +80,7 @@ module ActiveRecord
|
|
75
80
|
foreign_key = reflection.foreign_key
|
76
81
|
when :has_and_belongs_to_many
|
77
82
|
# Join the join table first...
|
78
|
-
|
83
|
+
manager.from(join(
|
79
84
|
table,
|
80
85
|
table[reflection.foreign_key].
|
81
86
|
eq(foreign_table[reflection.active_record_primary_key])
|
@@ -109,15 +114,30 @@ module ActiveRecord
|
|
109
114
|
constraint = constraint.and(item.arel.constraints) unless item.arel.constraints.empty?
|
110
115
|
end
|
111
116
|
|
112
|
-
|
117
|
+
manager.from(join(table, constraint))
|
113
118
|
|
114
119
|
# The current table in this iteration becomes the foreign table in the next
|
115
120
|
foreign_table, foreign_klass = table, reflection.klass
|
116
121
|
end
|
117
122
|
|
118
|
-
|
123
|
+
manager
|
119
124
|
end
|
120
125
|
|
126
|
+
# Builds equality condition.
|
127
|
+
#
|
128
|
+
# Example:
|
129
|
+
#
|
130
|
+
# class Physician < ActiveRecord::Base
|
131
|
+
# has_many :appointments
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
# If I execute `Physician.joins(:appointments).to_a` then
|
135
|
+
# reflection #=> #<ActiveRecord::Reflection::AssociationReflection @macro=:has_many ...>
|
136
|
+
# table #=> #<Arel::Table @name="appointments" ...>
|
137
|
+
# key #=> physician_id
|
138
|
+
# foreign_table #=> #<Arel::Table @name="physicians" ...>
|
139
|
+
# foreign_key #=> id
|
140
|
+
#
|
121
141
|
def build_constraint(reflection, table, key, foreign_table, foreign_key)
|
122
142
|
constraint = table[key].eq(foreign_table[foreign_key])
|
123
143
|
|
@@ -4,7 +4,7 @@ module ActiveRecord
|
|
4
4
|
class JoinBase < JoinPart # :nodoc:
|
5
5
|
def ==(other)
|
6
6
|
other.class == self.class &&
|
7
|
-
other.
|
7
|
+
other.base_klass == base_klass
|
8
8
|
end
|
9
9
|
|
10
10
|
def aliased_prefix
|
@@ -16,7 +16,7 @@ module ActiveRecord
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def aliased_table_name
|
19
|
-
|
19
|
+
base_klass.table_name
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Associations
|
3
3
|
class JoinDependency # :nodoc:
|
4
|
-
# A JoinPart represents a part of a JoinDependency. It is
|
4
|
+
# A JoinPart represents a part of a JoinDependency. It is inherited
|
5
5
|
# by JoinBase and JoinAssociation. A JoinBase represents the Active Record which
|
6
6
|
# everything else is being joined onto. A JoinAssociation represents an association which
|
7
7
|
# is joining to the base. A JoinAssociation may result in more than one actual join
|
@@ -11,12 +11,12 @@ module ActiveRecord
|
|
11
11
|
# The Active Record class which this join part is associated 'about'; for a JoinBase
|
12
12
|
# this is the actual base model, for a JoinAssociation this is the target model of the
|
13
13
|
# association.
|
14
|
-
attr_reader :
|
14
|
+
attr_reader :base_klass
|
15
15
|
|
16
|
-
delegate :table_name, :column_names, :primary_key, :reflections, :arel_engine, :to => :
|
16
|
+
delegate :table_name, :column_names, :primary_key, :reflections, :arel_engine, :to => :base_klass
|
17
17
|
|
18
|
-
def initialize(
|
19
|
-
@
|
18
|
+
def initialize(base_klass)
|
19
|
+
@base_klass = base_klass
|
20
20
|
@cached_record = {}
|
21
21
|
@column_names_with_alias = nil
|
22
22
|
end
|
@@ -70,7 +70,7 @@ module ActiveRecord
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def instantiate(row)
|
73
|
-
@cached_record[record_id(row)] ||=
|
73
|
+
@cached_record[record_id(row)] ||= base_klass.instantiate(extract_record(row))
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -5,9 +5,13 @@ module ActiveRecord
|
|
5
5
|
include ThroughAssociation
|
6
6
|
|
7
7
|
def associated_records_by_owner
|
8
|
-
|
9
|
-
|
8
|
+
records_by_owner = super
|
9
|
+
|
10
|
+
if reflection_scope.distinct_value
|
11
|
+
records_by_owner.each_value { |records| records.uniq! }
|
10
12
|
end
|
13
|
+
|
14
|
+
records_by_owner
|
11
15
|
end
|
12
16
|
end
|
13
17
|
end
|
@@ -81,7 +81,7 @@ module ActiveRecord
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def extract_callstack_for_multiparameter_attributes(pairs)
|
84
|
-
attributes = {
|
84
|
+
attributes = {}
|
85
85
|
|
86
86
|
pairs.each do |(multiparameter_name, value)|
|
87
87
|
attribute_name = multiparameter_name.split("(").first
|
@@ -146,7 +146,7 @@ module ActiveRecord
|
|
146
146
|
end
|
147
147
|
else
|
148
148
|
# else column is a timestamp, so if Date bits were not provided, error
|
149
|
-
|
149
|
+
validate_required_parameters!([1,2,3])
|
150
150
|
|
151
151
|
# If Date bits were provided but blank, then return nil
|
152
152
|
return if blank_date_parameter?
|
@@ -172,14 +172,14 @@ module ActiveRecord
|
|
172
172
|
def read_other(klass)
|
173
173
|
max_position = extract_max_param
|
174
174
|
positions = (1..max_position)
|
175
|
-
|
175
|
+
validate_required_parameters!(positions)
|
176
176
|
|
177
177
|
set_values = values.values_at(*positions)
|
178
178
|
klass.new(*set_values)
|
179
179
|
end
|
180
180
|
|
181
181
|
# Checks whether some blank date parameter exists. Note that this is different
|
182
|
-
# than the
|
182
|
+
# than the validate_required_parameters! method, since it just checks for blank
|
183
183
|
# positions instead of missing ones, and does not raise in case one blank position
|
184
184
|
# exists. The caller is responsible to handle the case of this returning true.
|
185
185
|
def blank_date_parameter?
|
@@ -187,7 +187,7 @@ module ActiveRecord
|
|
187
187
|
end
|
188
188
|
|
189
189
|
# If some position is not provided, it errors out a missing parameter exception.
|
190
|
-
def
|
190
|
+
def validate_required_parameters!(positions)
|
191
191
|
if missing_parameter = positions.detect { |position| !values.key?(position) }
|
192
192
|
raise ArgumentError.new("Missing Parameter - #{name}(#{missing_parameter})")
|
193
193
|
end
|
@@ -21,7 +21,7 @@ module ActiveRecord
|
|
21
21
|
# Generates all the attribute related methods for columns in the database
|
22
22
|
# accessors, mutators and query methods.
|
23
23
|
def define_attribute_methods # :nodoc:
|
24
|
-
# Use a mutex; we don't want two thread
|
24
|
+
# Use a mutex; we don't want two thread simultaneously trying to define
|
25
25
|
# attribute methods.
|
26
26
|
@attribute_methods_mutex.synchronize do
|
27
27
|
return if attribute_methods_generated?
|
@@ -56,7 +56,7 @@ module ActiveRecord
|
|
56
56
|
# # => false
|
57
57
|
def instance_method_already_implemented?(method_name)
|
58
58
|
if dangerous_attribute_method?(method_name)
|
59
|
-
raise DangerousAttributeError, "#{method_name} is defined by
|
59
|
+
raise DangerousAttributeError, "#{method_name} is defined by Active Record"
|
60
60
|
end
|
61
61
|
|
62
62
|
if superclass == Base
|
@@ -163,8 +163,22 @@ module ActiveRecord
|
|
163
163
|
# person.respond_to('age?') # => true
|
164
164
|
# person.respond_to(:nothing) # => false
|
165
165
|
def respond_to?(name, include_private = false)
|
166
|
+
name = name.to_s
|
166
167
|
self.class.define_attribute_methods unless self.class.attribute_methods_generated?
|
167
|
-
super
|
168
|
+
result = super
|
169
|
+
|
170
|
+
# If the result is false the answer is false.
|
171
|
+
return false unless result
|
172
|
+
|
173
|
+
# If the result is true then check for the select case.
|
174
|
+
# For queries selecting a subset of columns, return false for unselected columns.
|
175
|
+
# We check defined?(@attributes) not to issue warnings if called on objects that
|
176
|
+
# have been allocated but not yet initialized.
|
177
|
+
if defined?(@attributes) && @attributes.present? && self.class.column_names.include?(name)
|
178
|
+
return has_attribute?(name)
|
179
|
+
end
|
180
|
+
|
181
|
+
return true
|
168
182
|
end
|
169
183
|
|
170
184
|
# Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
|
@@ -328,13 +342,14 @@ module ActiveRecord
|
|
328
342
|
end
|
329
343
|
|
330
344
|
def attribute_method?(attr_name) # :nodoc:
|
345
|
+
# We check defined? because Syck calls respond_to? before actually calling initialize.
|
331
346
|
defined?(@attributes) && @attributes.include?(attr_name)
|
332
347
|
end
|
333
348
|
|
334
349
|
private
|
335
350
|
|
336
351
|
# Returns a Hash of the Arel::Attributes and attribute values that have been
|
337
|
-
#
|
352
|
+
# typecasted for use in an Arel insert/update method.
|
338
353
|
def arel_attributes_with_values(attribute_names)
|
339
354
|
attrs = {}
|
340
355
|
arel_table = self.class.arel_table
|
@@ -348,7 +363,7 @@ module ActiveRecord
|
|
348
363
|
# Filters the primary keys and readonly attributes from the attribute names.
|
349
364
|
def attributes_for_update(attribute_names)
|
350
365
|
attribute_names.select do |name|
|
351
|
-
column_for_attribute(name) && !
|
366
|
+
column_for_attribute(name) && !readonly_attribute?(name)
|
352
367
|
end
|
353
368
|
end
|
354
369
|
|