activerecord 1.15.6 → 2.0.0
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 +2454 -34
- data/README +1 -1
- data/RUNNING_UNIT_TESTS +3 -34
- data/Rakefile +98 -77
- data/install.rb +1 -1
- data/lib/active_record.rb +13 -22
- data/lib/active_record/aggregations.rb +38 -49
- data/lib/active_record/associations.rb +452 -333
- data/lib/active_record/associations/association_collection.rb +66 -20
- data/lib/active_record/associations/association_proxy.rb +9 -8
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +46 -51
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +38 -18
- data/lib/active_record/associations/has_one_association.rb +30 -14
- data/lib/active_record/attribute_methods.rb +253 -0
- data/lib/active_record/base.rb +719 -494
- data/lib/active_record/calculations.rb +62 -63
- data/lib/active_record/callbacks.rb +57 -83
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +38 -9
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +56 -15
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +191 -62
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -17
- data/lib/active_record/connection_adapters/mysql_adapter.rb +119 -37
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +473 -210
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +91 -107
- data/lib/active_record/fixtures.rb +503 -113
- data/lib/active_record/locking/optimistic.rb +72 -34
- data/lib/active_record/migration.rb +80 -57
- data/lib/active_record/observer.rb +13 -10
- data/lib/active_record/query_cache.rb +16 -57
- data/lib/active_record/reflection.rb +35 -38
- data/lib/active_record/schema.rb +5 -5
- data/lib/active_record/schema_dumper.rb +35 -13
- data/lib/active_record/serialization.rb +98 -0
- data/lib/active_record/serializers/json_serializer.rb +71 -0
- data/lib/active_record/{xml_serialization.rb → serializers/xml_serializer.rb} +90 -83
- data/lib/active_record/timestamp.rb +20 -21
- data/lib/active_record/transactions.rb +39 -43
- data/lib/active_record/validations.rb +256 -107
- data/lib/active_record/version.rb +3 -3
- data/lib/activerecord.rb +1 -0
- data/test/aaa_create_tables_test.rb +15 -2
- data/test/abstract_unit.rb +24 -17
- data/test/active_schema_test_mysql.rb +20 -8
- data/test/adapter_test.rb +23 -5
- data/test/adapter_test_sqlserver.rb +15 -1
- data/test/aggregations_test.rb +16 -1
- data/test/all.sh +2 -2
- data/test/associations/ar_joins_test.rb +0 -0
- data/test/associations/callbacks_test.rb +51 -30
- data/test/associations/cascaded_eager_loading_test.rb +1 -29
- data/test/associations/eager_singularization_test.rb +145 -0
- data/test/associations/eager_test.rb +42 -6
- data/test/associations/extension_test.rb +6 -1
- data/test/associations/inner_join_association_test.rb +88 -0
- data/test/associations/join_model_test.rb +47 -16
- data/test/associations_test.rb +449 -226
- data/test/attribute_methods_test.rb +97 -0
- data/test/base_test.rb +251 -105
- data/test/binary_test.rb +22 -27
- data/test/calculations_test.rb +37 -5
- data/test/callbacks_test.rb +23 -0
- data/test/connection_test_firebird.rb +2 -2
- data/test/connection_test_mysql.rb +30 -0
- data/test/connections/native_mysql/connection.rb +3 -0
- data/test/connections/native_sqlite/connection.rb +5 -14
- data/test/connections/native_sqlite3/connection.rb +5 -14
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -1
- data/test/{copy_table_sqlite.rb → copy_table_test_sqlite.rb} +8 -3
- data/test/datatype_test_postgresql.rb +178 -27
- data/test/{empty_date_time_test.rb → date_time_test.rb} +13 -1
- data/test/defaults_test.rb +8 -1
- data/test/deprecated_finder_test.rb +7 -128
- data/test/finder_test.rb +192 -54
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author.rb +12 -5
- data/test/fixtures/binaries.yml +130 -435
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +8 -1
- data/test/fixtures/computer.rb +1 -0
- data/test/fixtures/contact.rb +16 -0
- data/test/fixtures/customer.rb +2 -2
- data/test/fixtures/db_definitions/db2.drop.sql +1 -0
- data/test/fixtures/db_definitions/db2.sql +4 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +3 -1
- data/test/fixtures/db_definitions/firebird.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase.sql +5 -0
- data/test/fixtures/db_definitions/openbase.sql +41 -25
- data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle.sql +5 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +7 -0
- data/test/fixtures/db_definitions/postgresql.sql +87 -58
- data/test/fixtures/db_definitions/postgresql2.sql +1 -2
- data/test/fixtures/db_definitions/schema.rb +280 -0
- data/test/fixtures/db_definitions/schema2.rb +11 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +4 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +1 -0
- data/test/fixtures/db_definitions/sybase.sql +4 -0
- data/test/fixtures/developer.rb +10 -0
- data/test/fixtures/example.log +1 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/item.rb +7 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/joke.rb +0 -3
- data/test/fixtures/matey.rb +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/minimalistic.rb +2 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixins.yml +2 -100
- data/test/fixtures/parrot.rb +13 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/pirate.rb +5 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/post.rb +1 -0
- data/test/fixtures/project.rb +3 -2
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ship.rb +3 -0
- data/test/fixtures/ships.yml +5 -0
- data/test/fixtures/tagging.rb +4 -0
- data/test/fixtures/taggings.yml +8 -1
- data/test/fixtures/topic.rb +13 -1
- data/test/fixtures/treasure.rb +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures_test.rb +205 -24
- data/test/inheritance_test.rb +7 -1
- data/test/json_serialization_test.rb +180 -0
- data/test/lifecycle_test.rb +1 -1
- data/test/locking_test.rb +85 -2
- data/test/migration_test.rb +206 -40
- data/test/mixin_test.rb +13 -515
- data/test/pk_test.rb +3 -6
- data/test/query_cache_test.rb +104 -0
- data/test/reflection_test.rb +16 -0
- data/test/reserved_word_test_mysql.rb +177 -0
- data/test/schema_dumper_test.rb +38 -3
- data/test/serialization_test.rb +47 -0
- data/test/transactions_test.rb +74 -23
- data/test/unconnected_test.rb +1 -1
- data/test/validations_test.rb +322 -32
- data/test/xml_serialization_test.rb +121 -44
- metadata +48 -41
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -85
- data/lib/active_record/acts/list.rb +0 -256
- data/lib/active_record/acts/nested_set.rb +0 -211
- data/lib/active_record/acts/tree.rb +0 -96
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -228
- data/lib/active_record/connection_adapters/firebird_adapter.rb +0 -728
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +0 -861
- data/lib/active_record/connection_adapters/openbase_adapter.rb +0 -350
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -690
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +0 -591
- data/lib/active_record/connection_adapters/sybase_adapter.rb +0 -662
- data/lib/active_record/deprecated_associations.rb +0 -104
- data/lib/active_record/deprecated_finders.rb +0 -44
- data/lib/active_record/vendor/simple.rb +0 -693
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -58
- data/test/connections/native_sqlserver/connection.rb +0 -23
- data/test/connections/native_sqlserver_odbc/connection.rb +0 -25
- data/test/deprecated_associations_test.rb +0 -396
- data/test/fixtures/db_definitions/mysql.drop.sql +0 -32
- data/test/fixtures/db_definitions/mysql.sql +0 -234
- data/test/fixtures/db_definitions/mysql2.drop.sql +0 -2
- data/test/fixtures/db_definitions/mysql2.sql +0 -5
- data/test/fixtures/db_definitions/sqlserver.drop.sql +0 -34
- data/test/fixtures/db_definitions/sqlserver.sql +0 -243
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +0 -2
- data/test/fixtures/db_definitions/sqlserver2.sql +0 -5
- data/test/fixtures/mixin.rb +0 -63
- data/test/mixin_nested_set_test.rb +0 -196
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
load_target
|
8
8
|
@target.to_ary
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def reset
|
12
12
|
reset_target!
|
13
13
|
@loaded = false
|
@@ -17,7 +17,7 @@ module ActiveRecord
|
|
17
17
|
# Since << flattens its argument list and inserts each record, +push+ and +concat+ behave identically.
|
18
18
|
def <<(*records)
|
19
19
|
result = true
|
20
|
-
load_target
|
20
|
+
load_target if @owner.new_record?
|
21
21
|
|
22
22
|
@owner.transaction do
|
23
23
|
flatten_deeper(records).each do |record|
|
@@ -34,7 +34,7 @@ module ActiveRecord
|
|
34
34
|
|
35
35
|
alias_method :push, :<<
|
36
36
|
alias_method :concat, :<<
|
37
|
-
|
37
|
+
|
38
38
|
# Remove all records from this association
|
39
39
|
def delete_all
|
40
40
|
load_target
|
@@ -66,9 +66,9 @@ module ActiveRecord
|
|
66
66
|
|
67
67
|
# Removes all records from this association. Returns +self+ so method calls may be chained.
|
68
68
|
def clear
|
69
|
-
return self if length.zero? # forces load_target if hasn't happened already
|
69
|
+
return self if length.zero? # forces load_target if it hasn't happened already
|
70
70
|
|
71
|
-
if @reflection.options[:dependent] && @reflection.options[:dependent] == :
|
71
|
+
if @reflection.options[:dependent] && @reflection.options[:dependent] == :destroy
|
72
72
|
destroy_all
|
73
73
|
else
|
74
74
|
delete_all
|
@@ -84,27 +84,24 @@ module ActiveRecord
|
|
84
84
|
|
85
85
|
reset_target!
|
86
86
|
end
|
87
|
-
|
88
|
-
def create(
|
89
|
-
|
90
|
-
|
91
|
-
attributes.collect { |attr| create(attr) }
|
87
|
+
|
88
|
+
def create(attrs = {})
|
89
|
+
if attrs.is_a?(Array)
|
90
|
+
attrs.collect { |attr| create(attr) }
|
92
91
|
else
|
93
|
-
record
|
94
|
-
if @owner.new_record?
|
95
|
-
ActiveSupport::Deprecation.warn("Calling .create on a has_many association without saving its owner will not work in rails 2.0, you probably want .build instead")
|
96
|
-
else
|
97
|
-
record.save
|
98
|
-
end
|
99
|
-
record
|
92
|
+
create_record(attrs) { |record| record.save }
|
100
93
|
end
|
101
94
|
end
|
102
95
|
|
96
|
+
def create!(attrs = {})
|
97
|
+
create_record(attrs) { |record| record.save! }
|
98
|
+
end
|
99
|
+
|
103
100
|
# Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and
|
104
101
|
# calling collection.size if it has. If it's more likely than not that the collection does have a size larger than zero
|
105
102
|
# and you need to fetch that collection afterwards, it'll take one less SELECT query if you use length.
|
106
103
|
def size
|
107
|
-
if loaded? && !@reflection.options[:uniq]
|
104
|
+
if @owner.new_record? || (loaded? && !@reflection.options[:uniq])
|
108
105
|
@target.size
|
109
106
|
elsif !loaded? && !@reflection.options[:uniq] && @target.is_a?(Array)
|
110
107
|
unsaved_records = Array(@target.detect { |r| r.new_record? })
|
@@ -124,6 +121,14 @@ module ActiveRecord
|
|
124
121
|
size.zero?
|
125
122
|
end
|
126
123
|
|
124
|
+
def any?(&block)
|
125
|
+
if block_given?
|
126
|
+
method_missing(:any?, &block)
|
127
|
+
else
|
128
|
+
!empty?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
127
132
|
def uniq(collection = self)
|
128
133
|
seen = Set.new
|
129
134
|
collection.inject([]) do |kept, record|
|
@@ -150,7 +155,21 @@ module ActiveRecord
|
|
150
155
|
end
|
151
156
|
end
|
152
157
|
|
158
|
+
|
153
159
|
protected
|
160
|
+
def method_missing(method, *args, &block)
|
161
|
+
if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
|
162
|
+
super
|
163
|
+
else
|
164
|
+
@reflection.klass.send(:with_scope, construct_scope) { @reflection.klass.send(method, *args, &block) }
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# overloaded in derived Association classes to provide useful scoping depending on association type.
|
169
|
+
def construct_scope
|
170
|
+
{}
|
171
|
+
end
|
172
|
+
|
154
173
|
def reset_target!
|
155
174
|
@target = Array.new
|
156
175
|
end
|
@@ -167,6 +186,27 @@ module ActiveRecord
|
|
167
186
|
end
|
168
187
|
|
169
188
|
private
|
189
|
+
|
190
|
+
def create_record(attrs, &block)
|
191
|
+
ensure_owner_is_not_new
|
192
|
+
record = @reflection.klass.send(:with_scope, :create => construct_scope[:create]) { @reflection.klass.new(attrs) }
|
193
|
+
add_record_to_target_with_callbacks(record, &block)
|
194
|
+
end
|
195
|
+
|
196
|
+
def build_record(attrs, &block)
|
197
|
+
record = @reflection.klass.new(attrs)
|
198
|
+
add_record_to_target_with_callbacks(record, &block)
|
199
|
+
end
|
200
|
+
|
201
|
+
def add_record_to_target_with_callbacks(record)
|
202
|
+
callback(:before_add, record)
|
203
|
+
yield(record) if block_given?
|
204
|
+
@target ||= [] unless loaded?
|
205
|
+
@target << record
|
206
|
+
callback(:after_add, record)
|
207
|
+
record
|
208
|
+
end
|
209
|
+
|
170
210
|
def callback(method, record)
|
171
211
|
callbacks_for(method).each do |callback|
|
172
212
|
case callback
|
@@ -187,8 +227,14 @@ module ActiveRecord
|
|
187
227
|
def callbacks_for(callback_name)
|
188
228
|
full_callback_name = "#{callback_name}_for_#{@reflection.name}"
|
189
229
|
@owner.class.read_inheritable_attribute(full_callback_name.to_sym) || []
|
190
|
-
end
|
230
|
+
end
|
191
231
|
|
232
|
+
def ensure_owner_is_not_new
|
233
|
+
if @owner.new_record?
|
234
|
+
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
192
238
|
end
|
193
239
|
end
|
194
|
-
end
|
240
|
+
end
|
@@ -46,8 +46,8 @@ module ActiveRecord
|
|
46
46
|
alias :sql_conditions :conditions
|
47
47
|
|
48
48
|
def reset
|
49
|
-
@target = nil
|
50
49
|
@loaded = false
|
50
|
+
@target = nil
|
51
51
|
end
|
52
52
|
|
53
53
|
def reload
|
@@ -72,9 +72,14 @@ module ActiveRecord
|
|
72
72
|
loaded
|
73
73
|
end
|
74
74
|
|
75
|
+
def inspect
|
76
|
+
reload unless loaded?
|
77
|
+
@target.inspect
|
78
|
+
end
|
79
|
+
|
75
80
|
protected
|
76
81
|
def dependent?
|
77
|
-
@reflection.options[:dependent]
|
82
|
+
@reflection.options[:dependent]
|
78
83
|
end
|
79
84
|
|
80
85
|
def quoted_record_ids(records)
|
@@ -93,10 +98,6 @@ module ActiveRecord
|
|
93
98
|
@reflection.klass.send(:sanitize_sql, sql)
|
94
99
|
end
|
95
100
|
|
96
|
-
def extract_options_from_args!(args)
|
97
|
-
@owner.send(:extract_options_from_args!, args)
|
98
|
-
end
|
99
|
-
|
100
101
|
def set_belongs_to_association_for(record)
|
101
102
|
if @reflection.options[:as]
|
102
103
|
record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
|
@@ -138,14 +139,14 @@ module ActiveRecord
|
|
138
139
|
end
|
139
140
|
|
140
141
|
# Can be overwritten by associations that might have the foreign key available for an association without
|
141
|
-
# having the object itself (and still being a new record). Currently, only belongs_to
|
142
|
+
# having the object itself (and still being a new record). Currently, only belongs_to presents this scenario.
|
142
143
|
def foreign_key_present
|
143
144
|
false
|
144
145
|
end
|
145
146
|
|
146
147
|
def raise_on_type_mismatch(record)
|
147
148
|
unless record.is_a?(@reflection.klass)
|
148
|
-
raise ActiveRecord::AssociationTypeMismatch, "#{@reflection.
|
149
|
+
raise ActiveRecord::AssociationTypeMismatch, "#{@reflection.klass} expected, got #{record.class}"
|
149
150
|
end
|
150
151
|
end
|
151
152
|
|
@@ -5,31 +5,26 @@ module ActiveRecord
|
|
5
5
|
super
|
6
6
|
construct_sql
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def build(attributes = {})
|
10
10
|
load_target
|
11
|
-
|
12
|
-
@target << record
|
13
|
-
record
|
11
|
+
build_record(attributes)
|
14
12
|
end
|
15
13
|
|
16
14
|
def create(attributes = {})
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
insert_record(record) unless @owner.new_record?
|
23
|
-
record
|
24
|
-
end
|
15
|
+
create_record(attributes) { |record| insert_record(record) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def create!(attributes = {})
|
19
|
+
create_record(attributes) { |record| insert_record(record, true) }
|
25
20
|
end
|
26
21
|
|
27
22
|
def find_first
|
28
23
|
load_target.first
|
29
24
|
end
|
30
|
-
|
25
|
+
|
31
26
|
def find(*args)
|
32
|
-
options =
|
27
|
+
options = args.extract_options!
|
33
28
|
|
34
29
|
# If using a custom finder_sql, scan the entire collection.
|
35
30
|
if @reflection.options[:finder_sql]
|
@@ -52,7 +47,7 @@ module ActiveRecord
|
|
52
47
|
|
53
48
|
options[:conditions] = conditions
|
54
49
|
options[:joins] = @join_sql
|
55
|
-
options[:readonly] =
|
50
|
+
options[:readonly] = finding_with_ambiguous_select?(options[:select] || @reflection.options[:select])
|
56
51
|
|
57
52
|
if options[:order] && @reflection.options[:order]
|
58
53
|
options[:order] = "#{options[:order]}, #{@reflection.options[:order]}"
|
@@ -62,47 +57,26 @@ module ActiveRecord
|
|
62
57
|
|
63
58
|
merge_options_from_reflection!(options)
|
64
59
|
|
60
|
+
options[:select] ||= (@reflection.options[:select] || '*')
|
61
|
+
|
65
62
|
# Pass through args exactly as we received them.
|
66
63
|
args << options
|
67
64
|
@reflection.klass.find(*args)
|
68
65
|
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Deprecated as of Rails 1.2. If your associations require attributes
|
72
|
-
# you should be using has_many :through
|
73
|
-
def push_with_attributes(record, join_attributes = {})
|
74
|
-
raise_on_type_mismatch(record)
|
75
|
-
join_attributes.each { |key, value| record[key.to_s] = value }
|
76
|
-
|
77
|
-
callback(:before_add, record)
|
78
|
-
insert_record(record) unless @owner.new_record?
|
79
|
-
@target << record
|
80
|
-
callback(:after_add, record)
|
81
|
-
|
82
|
-
self
|
83
66
|
end
|
84
|
-
deprecate :push_with_attributes => "consider using has_many :through instead"
|
85
|
-
|
86
|
-
alias :concat_with_attributes :push_with_attributes
|
87
67
|
|
88
68
|
protected
|
89
|
-
def method_missing(method, *args, &block)
|
90
|
-
if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
|
91
|
-
super
|
92
|
-
else
|
93
|
-
@reflection.klass.with_scope(:find => { :conditions => @finder_sql, :joins => @join_sql, :readonly => false }) do
|
94
|
-
@reflection.klass.send(method, *args, &block)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
69
|
def count_records
|
100
70
|
load_target.size
|
101
71
|
end
|
102
72
|
|
103
|
-
def insert_record(record)
|
73
|
+
def insert_record(record, force=true)
|
104
74
|
if record.new_record?
|
105
|
-
|
75
|
+
if force
|
76
|
+
record.save!
|
77
|
+
else
|
78
|
+
return false unless record.save
|
79
|
+
end
|
106
80
|
end
|
107
81
|
|
108
82
|
if @reflection.options[:insert_sql]
|
@@ -131,10 +105,10 @@ module ActiveRecord
|
|
131
105
|
|
132
106
|
@owner.connection.execute(sql)
|
133
107
|
end
|
134
|
-
|
108
|
+
|
135
109
|
return true
|
136
110
|
end
|
137
|
-
|
111
|
+
|
138
112
|
def delete_records(records)
|
139
113
|
if sql = @reflection.options[:delete_sql]
|
140
114
|
records.each { |record| @owner.connection.execute(interpolate_sql(sql, record)) }
|
@@ -144,7 +118,7 @@ module ActiveRecord
|
|
144
118
|
@owner.connection.execute(sql)
|
145
119
|
end
|
146
120
|
end
|
147
|
-
|
121
|
+
|
148
122
|
def construct_sql
|
149
123
|
interpolate_sql_options!(@reflection.options, :finder_sql)
|
150
124
|
|
@@ -158,12 +132,33 @@ module ActiveRecord
|
|
158
132
|
@join_sql = "INNER JOIN #{@reflection.options[:join_table]} ON #{@reflection.klass.table_name}.#{@reflection.klass.primary_key} = #{@reflection.options[:join_table]}.#{@reflection.association_foreign_key}"
|
159
133
|
end
|
160
134
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
135
|
+
def construct_scope
|
136
|
+
{ :find => { :conditions => @finder_sql,
|
137
|
+
:joins => @join_sql,
|
138
|
+
:readonly => false,
|
139
|
+
:order => @reflection.options[:order],
|
140
|
+
:limit => @reflection.options[:limit] } }
|
141
|
+
end
|
142
|
+
|
143
|
+
# Join tables with additional columns on top of the two foreign keys must be considered ambiguous unless a select
|
144
|
+
# clause has been explicitly defined. Otherwise you can get broken records back, if, for example, the join column also has
|
145
|
+
# an id column. This will then overwrite the id column of the records coming back.
|
146
|
+
def finding_with_ambiguous_select?(select_clause)
|
165
147
|
!select_clause && @owner.connection.columns(@reflection.options[:join_table], "Join Table Columns").size != 2
|
166
148
|
end
|
149
|
+
|
150
|
+
private
|
151
|
+
def create_record(attributes)
|
152
|
+
# Can't use Base.create because the foreign key may be a protected attribute.
|
153
|
+
ensure_owner_is_not_new
|
154
|
+
if attributes.is_a?(Array)
|
155
|
+
attributes.collect { |attr| create(attr) }
|
156
|
+
else
|
157
|
+
record = build(attributes)
|
158
|
+
yield(record)
|
159
|
+
record
|
160
|
+
end
|
161
|
+
end
|
167
162
|
end
|
168
163
|
end
|
169
164
|
end
|
@@ -10,34 +10,9 @@ module ActiveRecord
|
|
10
10
|
if attributes.is_a?(Array)
|
11
11
|
attributes.collect { |attr| build(attr) }
|
12
12
|
else
|
13
|
-
record
|
14
|
-
set_belongs_to_association_for(record)
|
15
|
-
|
16
|
-
@target ||= [] unless loaded?
|
17
|
-
@target << record
|
18
|
-
|
19
|
-
record
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# DEPRECATED.
|
24
|
-
def find_all(runtime_conditions = nil, orderings = nil, limit = nil, joins = nil)
|
25
|
-
if @reflection.options[:finder_sql]
|
26
|
-
@reflection.klass.find_by_sql(@finder_sql)
|
27
|
-
else
|
28
|
-
conditions = @finder_sql
|
29
|
-
conditions += " AND (#{sanitize_sql(runtime_conditions)})" if runtime_conditions
|
30
|
-
orderings ||= @reflection.options[:order]
|
31
|
-
@reflection.klass.find_all(conditions, orderings, limit, joins)
|
13
|
+
build_record(attributes) { |record| set_belongs_to_association_for(record) }
|
32
14
|
end
|
33
15
|
end
|
34
|
-
deprecate :find_all => "use find(:all, ...) instead"
|
35
|
-
|
36
|
-
# DEPRECATED. Find the first associated record. All arguments are optional.
|
37
|
-
def find_first(conditions = nil, orderings = nil)
|
38
|
-
find_all(conditions, orderings, 1).first
|
39
|
-
end
|
40
|
-
deprecate :find_first => "use find(:first, ...) instead"
|
41
16
|
|
42
17
|
# Count the number of associated records. All arguments are optional.
|
43
18
|
def count(*args)
|
@@ -46,7 +21,7 @@ module ActiveRecord
|
|
46
21
|
elsif @reflection.options[:finder_sql]
|
47
22
|
@reflection.klass.count_by_sql(@finder_sql)
|
48
23
|
else
|
49
|
-
column_name, options = @reflection.klass.send(:
|
24
|
+
column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args)
|
50
25
|
options[:conditions] = options[:conditions].nil? ?
|
51
26
|
@finder_sql :
|
52
27
|
@finder_sql + " AND (#{sanitize_sql(options[:conditions])})"
|
@@ -57,12 +32,12 @@ module ActiveRecord
|
|
57
32
|
end
|
58
33
|
|
59
34
|
def find(*args)
|
60
|
-
options =
|
35
|
+
options = args.extract_options!
|
61
36
|
|
62
37
|
# If using a custom finder_sql, scan the entire collection.
|
63
38
|
if @reflection.options[:finder_sql]
|
64
39
|
expects_array = args.first.kind_of?(Array)
|
65
|
-
ids
|
40
|
+
ids = args.flatten.compact.uniq.map(&:to_i)
|
66
41
|
|
67
42
|
if ids.size == 1
|
68
43
|
id = ids.first
|
@@ -93,26 +68,6 @@ module ActiveRecord
|
|
93
68
|
end
|
94
69
|
|
95
70
|
protected
|
96
|
-
def method_missing(method, *args, &block)
|
97
|
-
if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
|
98
|
-
super
|
99
|
-
else
|
100
|
-
create_scoping = {}
|
101
|
-
set_belongs_to_association_for(create_scoping)
|
102
|
-
|
103
|
-
@reflection.klass.with_scope(
|
104
|
-
:create => create_scoping,
|
105
|
-
:find => {
|
106
|
-
:conditions => @finder_sql,
|
107
|
-
:joins => @join_sql,
|
108
|
-
:readonly => false
|
109
|
-
}
|
110
|
-
) do
|
111
|
-
@reflection.klass.send(method, *args, &block)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
71
|
def load_target
|
117
72
|
if !@owner.new_record? || foreign_key_present
|
118
73
|
begin
|
@@ -164,14 +119,17 @@ module ActiveRecord
|
|
164
119
|
end
|
165
120
|
|
166
121
|
def delete_records(records)
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
122
|
+
case @reflection.options[:dependent]
|
123
|
+
when :destroy
|
124
|
+
records.each(&:destroy)
|
125
|
+
when :delete_all
|
126
|
+
@reflection.klass.delete(records.map(&:id))
|
127
|
+
else
|
128
|
+
ids = quoted_record_ids(records)
|
129
|
+
@reflection.klass.update_all(
|
130
|
+
"#{@reflection.primary_key_name} = NULL",
|
131
|
+
"#{@reflection.primary_key_name} = #{@owner.quoted_id} AND #{@reflection.klass.primary_key} IN (#{ids})"
|
132
|
+
)
|
175
133
|
end
|
176
134
|
end
|
177
135
|
|
@@ -205,6 +163,12 @@ module ActiveRecord
|
|
205
163
|
@counter_sql = @finder_sql
|
206
164
|
end
|
207
165
|
end
|
166
|
+
|
167
|
+
def construct_scope
|
168
|
+
create_scoping = {}
|
169
|
+
set_belongs_to_association_for(create_scoping)
|
170
|
+
{ :find => { :conditions => @finder_sql, :readonly => false, :order => @reflection.options[:order], :limit => @reflection.options[:limit] }, :create => create_scoping }
|
171
|
+
end
|
208
172
|
end
|
209
173
|
end
|
210
174
|
end
|