activerecord 1.13.2 → 1.14.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 +452 -10
- data/RUNNING_UNIT_TESTS +1 -1
- data/lib/active_record.rb +5 -2
- data/lib/active_record/acts/list.rb +1 -1
- data/lib/active_record/acts/tree.rb +29 -25
- data/lib/active_record/aggregations.rb +3 -2
- data/lib/active_record/associations.rb +783 -337
- data/lib/active_record/associations/association_collection.rb +7 -12
- data/lib/active_record/associations/association_proxy.rb +62 -24
- data/lib/active_record/associations/belongs_to_association.rb +27 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +38 -38
- data/lib/active_record/associations/has_many_association.rb +61 -56
- data/lib/active_record/associations/has_many_through_association.rb +144 -0
- data/lib/active_record/associations/has_one_association.rb +22 -16
- data/lib/active_record/base.rb +482 -182
- data/lib/active_record/calculations.rb +225 -0
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +162 -47
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +21 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +34 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +107 -61
- data/lib/active_record/connection_adapters/mysql_adapter.rb +29 -6
- data/lib/active_record/connection_adapters/openbase_adapter.rb +349 -0
- data/lib/active_record/connection_adapters/{oci_adapter.rb → oracle_adapter.rb} +125 -59
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +24 -21
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +47 -8
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +36 -16
- data/lib/active_record/connection_adapters/sybase_adapter.rb +684 -0
- data/lib/active_record/fixtures.rb +42 -17
- data/lib/active_record/locking.rb +36 -15
- data/lib/active_record/migration.rb +111 -8
- data/lib/active_record/observer.rb +25 -1
- data/lib/active_record/reflection.rb +103 -41
- data/lib/active_record/schema.rb +2 -2
- data/lib/active_record/schema_dumper.rb +55 -18
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/validations.rb +65 -40
- data/lib/active_record/vendor/db2.rb +10 -5
- data/lib/active_record/vendor/simple.rb +693 -702
- data/lib/active_record/version.rb +2 -2
- data/rakefile +4 -4
- data/test/aaa_create_tables_test.rb +25 -6
- data/test/abstract_unit.rb +39 -1
- data/test/adapter_test.rb +31 -4
- data/test/associations_cascaded_eager_loading_test.rb +106 -0
- data/test/associations_go_eager_test.rb +85 -16
- data/test/associations_join_model_test.rb +338 -0
- data/test/associations_test.rb +129 -50
- data/test/base_test.rb +204 -49
- data/test/binary_test.rb +1 -1
- data/test/calculations_test.rb +169 -0
- data/test/callbacks_test.rb +5 -23
- data/test/class_inheritable_attributes_test.rb +1 -1
- data/test/column_alias_test.rb +1 -1
- data/test/connections/native_mysql/connection.rb +1 -0
- data/test/connections/native_openbase/connection.rb +22 -0
- data/test/connections/{native_oci → native_oracle}/connection.rb +7 -9
- data/test/connections/native_sqlite/connection.rb +1 -1
- data/test/connections/native_sqlite3/connection.rb +1 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -0
- data/test/connections/native_sybase/connection.rb +24 -0
- data/test/defaults_test.rb +18 -0
- data/test/deprecated_associations_test.rb +2 -2
- data/test/deprecated_finder_test.rb +0 -6
- data/test/finder_test.rb +26 -23
- data/test/fixtures/accounts.yml +10 -0
- data/test/fixtures/author.rb +31 -6
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_posts.yml +4 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +11 -0
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +17 -5
- data/test/fixtures/company_in_module.rb +19 -5
- data/test/fixtures/db_definitions/db2.drop.sql +3 -0
- data/test/fixtures/db_definitions/db2.sql +121 -100
- data/test/fixtures/db_definitions/db22.sql +2 -2
- data/test/fixtures/db_definitions/firebird.drop.sql +4 -0
- data/test/fixtures/db_definitions/firebird.sql +26 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +3 -0
- data/test/fixtures/db_definitions/mysql.sql +21 -1
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +282 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/{oci.drop.sql → oracle.drop.sql} +6 -0
- data/test/fixtures/db_definitions/{oci.sql → oracle.sql} +25 -4
- data/test/fixtures/db_definitions/{oci2.drop.sql → oracle2.drop.sql} +0 -0
- data/test/fixtures/db_definitions/{oci2.sql → oracle2.sql} +0 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +22 -1
- data/test/fixtures/db_definitions/schema.rb +32 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlite.sql +18 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlserver.sql +23 -3
- data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
- data/test/fixtures/db_definitions/sybase.sql +204 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developers.yml +6 -1
- data/test/fixtures/developers_projects.yml +4 -0
- data/test/fixtures/funny_jokes.yml +14 -0
- data/test/fixtures/joke.rb +6 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/mixin.rb +1 -1
- data/test/fixtures/person.rb +4 -1
- data/test/fixtures/post.rb +26 -1
- data/test/fixtures/project.rb +1 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +2 -1
- data/test/fixtures/tag.rb +5 -0
- data/test/fixtures/tagging.rb +6 -0
- data/test/fixtures/taggings.yml +18 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/tasks.yml +2 -2
- data/test/fixtures/topic.rb +2 -2
- data/test/fixtures/topics.yml +1 -0
- data/test/fixtures_test.rb +47 -13
- data/test/inheritance_test.rb +2 -2
- data/test/locking_test.rb +15 -1
- data/test/method_scoping_test.rb +248 -13
- data/test/migration_test.rb +68 -11
- data/test/mixin_nested_set_test.rb +1 -1
- data/test/modules_test.rb +6 -1
- data/test/readonly_test.rb +1 -1
- data/test/reflection_test.rb +63 -9
- data/test/schema_dumper_test.rb +41 -0
- data/test/{synonym_test_oci.rb → synonym_test_oracle.rb} +1 -1
- data/test/threaded_connections_test.rb +10 -0
- data/test/unconnected_test.rb +12 -5
- data/test/validations_test.rb +197 -10
- metadata +295 -260
- data/test/fixtures/db_definitions/create_oracle_db.bat +0 -0
- data/test/fixtures/db_definitions/create_oracle_db.sh +0 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
@@ -18,6 +18,7 @@ module ActiveRecord
|
|
18
18
|
def <<(*records)
|
19
19
|
result = true
|
20
20
|
load_target
|
21
|
+
|
21
22
|
@owner.transaction do
|
22
23
|
flatten_deeper(records).each do |record|
|
23
24
|
raise_on_type_mismatch(record)
|
@@ -28,7 +29,7 @@ module ActiveRecord
|
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
|
-
result
|
32
|
+
result && self
|
32
33
|
end
|
33
34
|
|
34
35
|
alias_method :push, :<<
|
@@ -60,11 +61,13 @@ module ActiveRecord
|
|
60
61
|
# Removes all records from this association. Returns +self+ so method calls may be chained.
|
61
62
|
def clear
|
62
63
|
return self if length.zero? # forces load_target if hasn't happened already
|
63
|
-
|
64
|
+
|
65
|
+
if @reflection.options[:dependent] && @reflection.options[:dependent] == :delete_all
|
64
66
|
destroy_all
|
65
67
|
else
|
66
68
|
delete_all
|
67
69
|
end
|
70
|
+
|
68
71
|
self
|
69
72
|
end
|
70
73
|
|
@@ -124,14 +127,6 @@ module ActiveRecord
|
|
124
127
|
end
|
125
128
|
|
126
129
|
private
|
127
|
-
def raise_on_type_mismatch(record)
|
128
|
-
raise ActiveRecord::AssociationTypeMismatch, "#{@association_class} expected, got #{record.class}" unless record.is_a?(@association_class)
|
129
|
-
end
|
130
|
-
|
131
|
-
def target_obsolete?
|
132
|
-
false
|
133
|
-
end
|
134
|
-
|
135
130
|
# Array#flatten has problems with recursive arrays. Going one level deeper solves the majority of the problems.
|
136
131
|
def flatten_deeper(array)
|
137
132
|
array.collect { |element| element.respond_to?(:flatten) ? element.flatten : element }.flatten
|
@@ -155,8 +150,8 @@ module ActiveRecord
|
|
155
150
|
end
|
156
151
|
|
157
152
|
def callbacks_for(callback_name)
|
158
|
-
full_callback_name = "#{callback_name
|
159
|
-
@owner.class.read_inheritable_attribute(full_callback_name.to_sym)
|
153
|
+
full_callback_name = "#{callback_name}_for_#{@reflection.name}"
|
154
|
+
@owner.class.read_inheritable_attribute(full_callback_name.to_sym) || []
|
160
155
|
end
|
161
156
|
|
162
157
|
end
|
@@ -1,29 +1,45 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Associations
|
3
3
|
class AssociationProxy #:nodoc:
|
4
|
+
attr_reader :reflection
|
4
5
|
alias_method :proxy_respond_to?, :respond_to?
|
5
6
|
alias_method :proxy_extend, :extend
|
6
7
|
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?|^proxy_respond_to\?|^proxy_extend|^send)/ }
|
7
8
|
|
8
|
-
def initialize(owner,
|
9
|
-
@owner = owner
|
10
|
-
|
11
|
-
@association_name = association_name
|
12
|
-
@association_class = eval(association_class_name, nil, __FILE__, __LINE__)
|
13
|
-
@association_class_primary_key_name = association_class_primary_key_name
|
14
|
-
|
15
|
-
proxy_extend(options[:extend]) if options[:extend]
|
16
|
-
|
9
|
+
def initialize(owner, reflection)
|
10
|
+
@owner, @reflection = owner, reflection
|
11
|
+
proxy_extend(reflection.options[:extend]) if reflection.options[:extend]
|
17
12
|
reset
|
18
13
|
end
|
19
14
|
|
20
|
-
def
|
21
|
-
|
15
|
+
def respond_to?(symbol, include_priv = false)
|
16
|
+
proxy_respond_to?(symbol, include_priv) || (load_target && @target.respond_to?(symbol, include_priv))
|
17
|
+
end
|
18
|
+
|
19
|
+
# Explicitly proxy === because the instance method removal above
|
20
|
+
# doesn't catch it.
|
21
|
+
def ===(other)
|
22
22
|
load_target
|
23
|
+
other === @target
|
24
|
+
end
|
25
|
+
|
26
|
+
def aliased_table_name
|
27
|
+
@reflection.klass.table_name
|
28
|
+
end
|
29
|
+
|
30
|
+
def conditions
|
31
|
+
@conditions ||= eval("%(#{@reflection.active_record.send :sanitize_sql, @reflection.options[:conditions]})") if @reflection.options[:conditions]
|
32
|
+
end
|
33
|
+
alias :sql_conditions :conditions
|
34
|
+
|
35
|
+
def reset
|
36
|
+
@target = nil
|
37
|
+
@loaded = false
|
23
38
|
end
|
24
39
|
|
25
|
-
def
|
26
|
-
|
40
|
+
def reload
|
41
|
+
reset
|
42
|
+
load_target
|
27
43
|
end
|
28
44
|
|
29
45
|
def loaded?
|
@@ -38,14 +54,14 @@ module ActiveRecord
|
|
38
54
|
@target
|
39
55
|
end
|
40
56
|
|
41
|
-
def target=(
|
42
|
-
@target =
|
43
|
-
|
57
|
+
def target=(target)
|
58
|
+
@target = target
|
59
|
+
loaded
|
44
60
|
end
|
45
61
|
|
46
62
|
protected
|
47
63
|
def dependent?
|
48
|
-
@options[:dependent] || false
|
64
|
+
@reflection.options[:dependent] || false
|
49
65
|
end
|
50
66
|
|
51
67
|
def quoted_record_ids(records)
|
@@ -61,15 +77,34 @@ module ActiveRecord
|
|
61
77
|
end
|
62
78
|
|
63
79
|
def sanitize_sql(sql)
|
64
|
-
@
|
80
|
+
@reflection.klass.send(:sanitize_sql, sql)
|
65
81
|
end
|
66
82
|
|
67
83
|
def extract_options_from_args!(args)
|
68
84
|
@owner.send(:extract_options_from_args!, args)
|
69
85
|
end
|
86
|
+
|
87
|
+
def set_belongs_to_association_for(record)
|
88
|
+
if @reflection.options[:as]
|
89
|
+
record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
|
90
|
+
record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
|
91
|
+
else
|
92
|
+
record[@reflection.primary_key_name] = @owner.id unless @owner.new_record?
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def merge_options_from_reflection!(options)
|
97
|
+
options.reverse_merge!(
|
98
|
+
:group => @reflection.options[:group],
|
99
|
+
:limit => @reflection.options[:limit],
|
100
|
+
:offset => @reflection.options[:offset],
|
101
|
+
:joins => @reflection.options[:joins],
|
102
|
+
:include => @reflection.options[:include],
|
103
|
+
:select => @reflection.options[:select]
|
104
|
+
)
|
105
|
+
end
|
70
106
|
|
71
107
|
private
|
72
|
-
|
73
108
|
def method_missing(method, *args, &block)
|
74
109
|
load_target
|
75
110
|
@target.send(method, *args, &block)
|
@@ -78,13 +113,14 @@ module ActiveRecord
|
|
78
113
|
def load_target
|
79
114
|
if !@owner.new_record? || foreign_key_present
|
80
115
|
begin
|
81
|
-
@target = find_target if
|
116
|
+
@target = find_target if !loaded?
|
82
117
|
rescue ActiveRecord::RecordNotFound
|
83
118
|
reset
|
84
119
|
end
|
85
120
|
end
|
86
|
-
|
87
|
-
|
121
|
+
|
122
|
+
loaded if target
|
123
|
+
target
|
88
124
|
end
|
89
125
|
|
90
126
|
# Can be overwritten by associations that might have the foreign key available for an association without
|
@@ -94,8 +130,10 @@ module ActiveRecord
|
|
94
130
|
end
|
95
131
|
|
96
132
|
def raise_on_type_mismatch(record)
|
97
|
-
|
133
|
+
unless record.is_a?(@reflection.klass)
|
134
|
+
raise ActiveRecord::AssociationTypeMismatch, "#{@reflection.class_name} expected, got #{record.class}"
|
135
|
+
end
|
98
136
|
end
|
99
137
|
end
|
100
138
|
end
|
101
|
-
end
|
139
|
+
end
|
@@ -1,74 +1,55 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Associations
|
3
3
|
class BelongsToAssociation < AssociationProxy #:nodoc:
|
4
|
-
|
5
|
-
def initialize(owner, association_name, association_class_name, association_class_primary_key_name, options)
|
6
|
-
super
|
7
|
-
construct_sql
|
8
|
-
end
|
9
|
-
|
10
|
-
def reset
|
11
|
-
@target = nil
|
12
|
-
@loaded = false
|
13
|
-
end
|
14
|
-
|
15
4
|
def create(attributes = {})
|
16
|
-
|
17
|
-
replace(record, true)
|
18
|
-
record
|
5
|
+
replace(@reflection.klass.create(attributes))
|
19
6
|
end
|
20
7
|
|
21
8
|
def build(attributes = {})
|
22
|
-
|
23
|
-
replace(record, true)
|
24
|
-
record
|
9
|
+
replace(@reflection.klass.new(attributes))
|
25
10
|
end
|
26
11
|
|
27
|
-
def replace(
|
28
|
-
|
29
|
-
|
12
|
+
def replace(record)
|
13
|
+
counter_cache_name = @reflection.counter_cache_column
|
14
|
+
|
15
|
+
if record.nil?
|
16
|
+
if counter_cache_name && @owner[counter_cache_name] && !@owner.new_record?
|
17
|
+
@reflection.klass.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name]
|
18
|
+
end
|
19
|
+
|
20
|
+
@target = @owner[@reflection.primary_key_name] = nil
|
30
21
|
else
|
31
|
-
raise_on_type_mismatch(
|
22
|
+
raise_on_type_mismatch(record)
|
32
23
|
|
33
|
-
|
34
|
-
|
24
|
+
if counter_cache_name && !@owner.new_record?
|
25
|
+
@reflection.klass.increment_counter(counter_cache_name, record.id)
|
26
|
+
@reflection.klass.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name]
|
27
|
+
end
|
28
|
+
|
29
|
+
@target = (AssociationProxy === record ? record.target : record)
|
30
|
+
@owner[@reflection.primary_key_name] = record.id unless record.new_record?
|
35
31
|
@updated = true
|
36
32
|
end
|
37
|
-
@loaded = true
|
38
33
|
|
39
|
-
|
34
|
+
loaded
|
35
|
+
record
|
40
36
|
end
|
41
37
|
|
42
38
|
def updated?
|
43
39
|
@updated
|
44
40
|
end
|
45
41
|
|
46
|
-
protected
|
47
|
-
|
48
|
-
|
49
42
|
private
|
50
43
|
def find_target
|
51
|
-
|
52
|
-
@
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
)
|
57
|
-
else
|
58
|
-
@association_class.find(@owner[@association_class_primary_key_name], :include => @options[:include])
|
59
|
-
end
|
44
|
+
@reflection.klass.find(
|
45
|
+
@owner[@reflection.primary_key_name],
|
46
|
+
:conditions => conditions,
|
47
|
+
:include => @reflection.options[:include]
|
48
|
+
)
|
60
49
|
end
|
61
50
|
|
62
51
|
def foreign_key_present
|
63
|
-
!@owner[@
|
64
|
-
end
|
65
|
-
|
66
|
-
def target_obsolete?
|
67
|
-
@owner[@association_class_primary_key_name] != @target.id
|
68
|
-
end
|
69
|
-
|
70
|
-
def construct_sql
|
71
|
-
@finder_sql = "#{@association_class.table_name}.#{@association_class.primary_key} = #{@owner.id}"
|
52
|
+
!@owner[@reflection.primary_key_name].nil?
|
72
53
|
end
|
73
54
|
end
|
74
55
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
class BelongsToPolymorphicAssociation < AssociationProxy #:nodoc:
|
4
|
+
def replace(record)
|
5
|
+
if record.nil?
|
6
|
+
@target = @owner[@reflection.primary_key_name] = @owner[@reflection.options[:foreign_type]] = nil
|
7
|
+
else
|
8
|
+
@target = (AssociationProxy === record ? record.target : record)
|
9
|
+
|
10
|
+
unless record.new_record?
|
11
|
+
@owner[@reflection.primary_key_name] = record.id
|
12
|
+
@owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
@updated = true
|
16
|
+
end
|
17
|
+
|
18
|
+
loaded
|
19
|
+
record
|
20
|
+
end
|
21
|
+
|
22
|
+
def updated?
|
23
|
+
@updated
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def find_target
|
28
|
+
return nil if association_class.nil?
|
29
|
+
|
30
|
+
if @reflection.options[:conditions]
|
31
|
+
association_class.find(
|
32
|
+
@owner[@reflection.primary_key_name],
|
33
|
+
:conditions => conditions,
|
34
|
+
:include => @reflection.options[:include]
|
35
|
+
)
|
36
|
+
else
|
37
|
+
association_class.find(@owner[@reflection.primary_key_name], :include => @reflection.options[:include])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def foreign_key_present
|
42
|
+
!@owner[@reflection.primary_key_name].nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
def association_class
|
46
|
+
@owner[@reflection.options[:foreign_type]] ? @owner[@reflection.options[:foreign_type]].constantize : nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,20 +1,14 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Associations
|
3
3
|
class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
|
4
|
-
def initialize(owner,
|
4
|
+
def initialize(owner, reflection)
|
5
5
|
super
|
6
|
-
|
7
|
-
@association_foreign_key = options[:association_foreign_key] || association_class_name.foreign_key
|
8
|
-
@association_table_name = options[:table_name] || @association_class.table_name
|
9
|
-
@join_table = options[:join_table]
|
10
|
-
@order = options[:order]
|
11
|
-
|
12
6
|
construct_sql
|
13
7
|
end
|
14
8
|
|
15
9
|
def build(attributes = {})
|
16
10
|
load_target
|
17
|
-
record = @
|
11
|
+
record = @reflection.klass.new(attributes)
|
18
12
|
@target << record
|
19
13
|
record
|
20
14
|
end
|
@@ -27,7 +21,7 @@ module ActiveRecord
|
|
27
21
|
options = Base.send(:extract_options_from_args!, args)
|
28
22
|
|
29
23
|
# If using a custom finder_sql, scan the entire collection.
|
30
|
-
if @options[:finder_sql]
|
24
|
+
if @reflection.options[:finder_sql]
|
31
25
|
expects_array = args.first.kind_of?(Array)
|
32
26
|
ids = args.flatten.compact.uniq
|
33
27
|
|
@@ -40,60 +34,66 @@ module ActiveRecord
|
|
40
34
|
end
|
41
35
|
else
|
42
36
|
conditions = "#{@finder_sql}"
|
37
|
+
|
43
38
|
if sanitized_conditions = sanitize_sql(options[:conditions])
|
44
39
|
conditions << " AND (#{sanitized_conditions})"
|
45
40
|
end
|
41
|
+
|
46
42
|
options[:conditions] = conditions
|
47
43
|
options[:joins] = @join_sql
|
48
44
|
options[:readonly] ||= false
|
49
45
|
|
50
|
-
if options[:order] && @options[:order]
|
51
|
-
options[:order] = "#{options[:order]}, #{@options[:order]}"
|
52
|
-
elsif @options[:order]
|
53
|
-
options[:order] = @options[:order]
|
46
|
+
if options[:order] && @reflection.options[:order]
|
47
|
+
options[:order] = "#{options[:order]}, #{@reflection.options[:order]}"
|
48
|
+
elsif @reflection.options[:order]
|
49
|
+
options[:order] = @reflection.options[:order]
|
54
50
|
end
|
55
51
|
|
52
|
+
merge_options_from_reflection!(options)
|
53
|
+
|
56
54
|
# Pass through args exactly as we received them.
|
57
55
|
args << options
|
58
|
-
@
|
56
|
+
@reflection.klass.find(*args)
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
62
60
|
def push_with_attributes(record, join_attributes = {})
|
63
61
|
raise_on_type_mismatch(record)
|
64
62
|
join_attributes.each { |key, value| record[key.to_s] = value }
|
63
|
+
|
65
64
|
callback(:before_add, record)
|
66
65
|
insert_record(record) unless @owner.new_record?
|
67
66
|
@target << record
|
68
67
|
callback(:after_add, record)
|
68
|
+
|
69
69
|
self
|
70
70
|
end
|
71
71
|
|
72
72
|
alias :concat_with_attributes :push_with_attributes
|
73
73
|
|
74
74
|
def size
|
75
|
-
@options[:uniq] ? count_records : super
|
75
|
+
@reflection.options[:uniq] ? count_records : super
|
76
76
|
end
|
77
77
|
|
78
78
|
protected
|
79
79
|
def method_missing(method, *args, &block)
|
80
|
-
if @target.respond_to?(method) || (!@
|
80
|
+
if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
|
81
81
|
super
|
82
82
|
else
|
83
|
-
@
|
84
|
-
@
|
83
|
+
@reflection.klass.with_scope(:find => { :conditions => @finder_sql, :joins => @join_sql, :readonly => false }) do
|
84
|
+
@reflection.klass.send(method, *args, &block)
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
89
|
def find_target
|
90
|
-
if @options[:finder_sql]
|
91
|
-
records = @
|
90
|
+
if @reflection.options[:finder_sql]
|
91
|
+
records = @reflection.klass.find_by_sql(@finder_sql)
|
92
92
|
else
|
93
|
-
records = find(:all
|
93
|
+
records = find(:all)
|
94
94
|
end
|
95
95
|
|
96
|
-
@options[:uniq] ? uniq(records) : records
|
96
|
+
@reflection.options[:uniq] ? uniq(records) : records
|
97
97
|
end
|
98
98
|
|
99
99
|
def count_records
|
@@ -105,16 +105,16 @@ module ActiveRecord
|
|
105
105
|
return false unless record.save
|
106
106
|
end
|
107
107
|
|
108
|
-
if @options[:insert_sql]
|
109
|
-
@owner.connection.execute(interpolate_sql(@options[:insert_sql], record))
|
108
|
+
if @reflection.options[:insert_sql]
|
109
|
+
@owner.connection.execute(interpolate_sql(@reflection.options[:insert_sql], record))
|
110
110
|
else
|
111
|
-
columns = @owner.connection.columns(@join_table, "#{@join_table} Columns")
|
111
|
+
columns = @owner.connection.columns(@reflection.options[:join_table], "#{@reflection.options[:join_table]} Columns")
|
112
112
|
|
113
113
|
attributes = columns.inject({}) do |attributes, column|
|
114
114
|
case column.name
|
115
|
-
when @
|
115
|
+
when @reflection.primary_key_name
|
116
116
|
attributes[column.name] = @owner.quoted_id
|
117
|
-
when @association_foreign_key
|
117
|
+
when @reflection.association_foreign_key
|
118
118
|
attributes[column.name] = record.quoted_id
|
119
119
|
else
|
120
120
|
if record.attributes.has_key?(column.name)
|
@@ -126,7 +126,7 @@ module ActiveRecord
|
|
126
126
|
end
|
127
127
|
|
128
128
|
sql =
|
129
|
-
"INSERT INTO #{@join_table} (#{@owner.send(:quoted_column_names, attributes).join(', ')}) " +
|
129
|
+
"INSERT INTO #{@reflection.options[:join_table]} (#{@owner.send(:quoted_column_names, attributes).join(', ')}) " +
|
130
130
|
"VALUES (#{attributes.values.join(', ')})"
|
131
131
|
|
132
132
|
@owner.connection.execute(sql)
|
@@ -136,26 +136,26 @@ module ActiveRecord
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def delete_records(records)
|
139
|
-
if sql = @options[:delete_sql]
|
139
|
+
if sql = @reflection.options[:delete_sql]
|
140
140
|
records.each { |record| @owner.connection.execute(interpolate_sql(sql, record)) }
|
141
141
|
else
|
142
142
|
ids = quoted_record_ids(records)
|
143
|
-
sql = "DELETE FROM #{@join_table} WHERE #{@
|
143
|
+
sql = "DELETE FROM #{@reflection.options[:join_table]} WHERE #{@reflection.primary_key_name} = #{@owner.quoted_id} AND #{@reflection.association_foreign_key} IN (#{ids})"
|
144
144
|
@owner.connection.execute(sql)
|
145
145
|
end
|
146
146
|
end
|
147
|
-
|
147
|
+
|
148
148
|
def construct_sql
|
149
|
-
interpolate_sql_options!(@options, :finder_sql)
|
149
|
+
interpolate_sql_options!(@reflection.options, :finder_sql)
|
150
150
|
|
151
|
-
if @options[:finder_sql]
|
152
|
-
@finder_sql = @options[:finder_sql]
|
151
|
+
if @reflection.options[:finder_sql]
|
152
|
+
@finder_sql = @reflection.options[:finder_sql]
|
153
153
|
else
|
154
|
-
@finder_sql = "#{@join_table}.#{@
|
155
|
-
@finder_sql << " AND (#{
|
154
|
+
@finder_sql = "#{@reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{@owner.quoted_id} "
|
155
|
+
@finder_sql << " AND (#{conditions})" if conditions
|
156
156
|
end
|
157
|
-
|
158
|
-
@join_sql = "
|
157
|
+
|
158
|
+
@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
159
|
end
|
160
160
|
|
161
161
|
end
|