activerecord 1.11.1 → 1.12.1
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 +198 -0
- data/lib/active_record.rb +19 -14
- data/lib/active_record/acts/list.rb +8 -6
- data/lib/active_record/acts/tree.rb +33 -10
- data/lib/active_record/aggregations.rb +1 -7
- data/lib/active_record/associations.rb +151 -82
- data/lib/active_record/associations/association_collection.rb +25 -0
- data/lib/active_record/associations/association_proxy.rb +9 -8
- data/lib/active_record/associations/belongs_to_association.rb +19 -5
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +44 -69
- data/lib/active_record/associations/has_many_association.rb +6 -14
- data/lib/active_record/associations/has_one_association.rb +5 -3
- data/lib/active_record/base.rb +344 -130
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +128 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +104 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +249 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +245 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +29 -464
- data/lib/active_record/connection_adapters/db2_adapter.rb +40 -10
- data/lib/active_record/connection_adapters/mysql_adapter.rb +131 -60
- data/lib/active_record/connection_adapters/oci_adapter.rb +106 -26
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +211 -62
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +193 -44
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +24 -15
- data/lib/active_record/fixtures.rb +47 -24
- data/lib/active_record/migration.rb +34 -5
- data/lib/active_record/observer.rb +32 -2
- data/lib/active_record/query_cache.rb +12 -11
- data/lib/active_record/schema.rb +58 -0
- data/lib/active_record/schema_dumper.rb +84 -0
- data/lib/active_record/transactions.rb +1 -3
- data/lib/active_record/validations.rb +40 -26
- data/lib/active_record/vendor/mysql.rb +6 -0
- data/lib/active_record/version.rb +9 -0
- data/rakefile +5 -16
- data/test/abstract_unit.rb +6 -11
- data/test/adapter_test.rb +58 -0
- data/test/ar_schema_test.rb +33 -0
- data/test/association_callbacks_test.rb +14 -0
- data/test/associations_go_eager_test.rb +56 -14
- data/test/associations_test.rb +245 -25
- data/test/base_test.rb +205 -34
- data/test/binary_test.rb +25 -42
- data/test/callbacks_test.rb +75 -0
- data/test/conditions_scoping_test.rb +136 -0
- data/test/connections/native_mysql/connection.rb +0 -4
- data/test/connections/native_sqlite3/in_memory_connection.rb +17 -0
- data/test/copy_table_sqlite.rb +64 -0
- data/test/deprecated_associations_test.rb +7 -6
- data/test/deprecated_finder_test.rb +3 -3
- data/test/finder_test.rb +33 -3
- data/test/fixtures/accounts.yml +5 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/category.rb +11 -1
- data/test/fixtures/comment.rb +22 -2
- data/test/fixtures/comments.yml +6 -0
- data/test/fixtures/companies.yml +15 -0
- data/test/fixtures/company.rb +24 -1
- data/test/fixtures/db_definitions/db2.drop.sql +5 -1
- data/test/fixtures/db_definitions/db2.sql +15 -1
- data/test/fixtures/db_definitions/mysql.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql.sql +17 -2
- data/test/fixtures/db_definitions/oci.drop.sql +37 -5
- data/test/fixtures/db_definitions/oci.sql +47 -4
- data/test/fixtures/db_definitions/oci2.drop.sql +1 -1
- data/test/fixtures/db_definitions/oci2.sql +2 -2
- data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +33 -4
- data/test/fixtures/db_definitions/sqlite.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite.sql +16 -2
- data/test/fixtures/db_definitions/sqlserver.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver.sql +16 -2
- data/test/fixtures/developer.rb +1 -1
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/keyboard.rb +3 -0
- data/test/fixtures/mixins.yml +11 -1
- data/test/fixtures/order.rb +4 -0
- data/test/fixtures/post.rb +4 -0
- data/test/fixtures/posts.yml +7 -0
- data/test/fixtures/project.rb +1 -0
- data/test/fixtures/subject.rb +4 -0
- data/test/fixtures/subscriber.rb +2 -4
- data/test/fixtures/topics.yml +2 -2
- data/test/fixtures_test.rb +79 -7
- data/test/inheritance_test.rb +2 -2
- data/test/lifecycle_test.rb +14 -6
- data/test/migration_test.rb +164 -6
- data/test/mixin_test.rb +78 -2
- data/test/pk_test.rb +25 -1
- data/test/readonly_test.rb +31 -0
- data/test/reflection_test.rb +4 -1
- data/test/schema_dumper_test.rb +19 -0
- data/test/schema_test_postgresql.rb +3 -2
- data/test/synonym_test_oci.rb +17 -0
- data/test/threaded_connections_test.rb +2 -1
- data/test/transactions_test.rb +109 -10
- data/test/validations_test.rb +70 -42
- metadata +25 -5
- data/test/fixtures/associations.png +0 -0
- data/test/thread_safety_test.rb +0 -36
data/CHANGELOG
CHANGED
@@ -1,3 +1,201 @@
|
|
1
|
+
*1.12.1* (October 19th, 2005)
|
2
|
+
|
3
|
+
* Always parenthesize :conditions options so they may be safely combined with STI and constraints.
|
4
|
+
|
5
|
+
* Correct PostgreSQL primary key sequence detection. #2507 [tmornini@infomania.com]
|
6
|
+
|
7
|
+
* Added support for using limits in eager loads that involve has_many and has_and_belongs_to_many associations
|
8
|
+
|
9
|
+
|
10
|
+
*1.12.0* (October 16th, 2005)
|
11
|
+
|
12
|
+
* Update/clean up documentation (rdoc)
|
13
|
+
|
14
|
+
* PostgreSQL sequence support. Use set_sequence_name in your model class to specify its primary key sequence. #2292 [Rick Olson <technoweenie@gmail.com>, Robby Russell <robby@planetargon.com>]
|
15
|
+
|
16
|
+
* Change default logging colors to work on both white and black backgrounds. [Sam Stephenson]
|
17
|
+
|
18
|
+
* YAML fixtures support ordered hashes for fixtures with foreign key dependencies in the same table. #1896 [purestorm@ggnore.net]
|
19
|
+
|
20
|
+
* :dependent now accepts :nullify option. Sets the foreign key of the related objects to NULL instead of deleting them. #2015 [Robby Russell <robby@planetargon.com>]
|
21
|
+
|
22
|
+
* Introduce read-only records. If you call object.readonly! then it will mark the object as read-only and raise ReadOnlyRecord if you call object.save. object.readonly? reports whether the object is read-only. Passing :readonly => true to any finder method will mark returned records as read-only. The :joins option now implies :readonly, so if you use this option, saving the same record will now fail. Use find_by_sql to work around.
|
23
|
+
|
24
|
+
* Avoid memleak in dev mode when using fcgi
|
25
|
+
|
26
|
+
* Simplified .clear on active record associations by using the existing delete_records method. #1906 [Caleb <me@cpb.ca>]
|
27
|
+
|
28
|
+
* Delegate access to a customized primary key to the conventional id method. #2444. [Blair Zajac <blair@orcaware.com>]
|
29
|
+
|
30
|
+
* Fix errors caused by assigning a has-one or belongs-to property to itself
|
31
|
+
|
32
|
+
* Add ActiveRecord::Base.schema_format setting which specifies how databases should be dumped [Sam Stephenson]
|
33
|
+
|
34
|
+
* Update DB2 adapter. #2206. [contact@maik-schmidt.de]
|
35
|
+
|
36
|
+
* Corrections to SQLServer native data types. #2267. [rails.20.clarry@spamgourmet.com]
|
37
|
+
|
38
|
+
* Deprecated ActiveRecord::Base.threaded_connection in favor of ActiveRecord::Base.allow_concurrency.
|
39
|
+
|
40
|
+
* Protect id attribute from mass assigment even when the primary key is set to something else. #2438. [Blair Zajac <blair@orcaware.com>]
|
41
|
+
|
42
|
+
* Misc doc fixes (typos/grammar/etc.). #2430. [coffee2code]
|
43
|
+
|
44
|
+
* Add test coverage for content_columns. #2432. [coffee2code]
|
45
|
+
|
46
|
+
* Speed up for unthreaded environments. #2431. [skaes@web.de]
|
47
|
+
|
48
|
+
* Optimization for Mysql selects using mysql-ruby extension greater than 2.6.3. #2426. [skaes@web.de]
|
49
|
+
|
50
|
+
* Speed up the setting of table_name. #2428. [skaes@web.de]
|
51
|
+
|
52
|
+
* Optimize instantiation of STI subclass records. In partial fullfilment of #1236. [skaes@web.de]
|
53
|
+
|
54
|
+
* Fix typo of 'constrains' to 'contraints'. #2069. [Michael Schuerig <michael@schuerig.de>]
|
55
|
+
|
56
|
+
* Optimization refactoring for add_limit_offset!. In partial fullfilment of #1236. [skaes@web.de]
|
57
|
+
|
58
|
+
* Add ability to get all siblings, including the current child, with acts_as_tree. Recloses #2140. [Michael Schuerig <michael@schuerig.de>]
|
59
|
+
|
60
|
+
* Add geometric type for postgresql adapter. #2233 [akaspick@gmail.com]
|
61
|
+
|
62
|
+
* Add option (true by default) to generate reader methods for each attribute of a record to avoid the overhead of calling method missing. In partial fullfilment of #1236. [skaes@web.de]
|
63
|
+
|
64
|
+
* Add convenience predicate methods on Column class. In partial fullfilment of #1236. [skaes@web.de]
|
65
|
+
|
66
|
+
* Raise errors when invalid hash keys are passed to ActiveRecord::Base.find. #2363 [Chad Fowler <chad@chadfowler.com>, Nicholas Seckar]
|
67
|
+
|
68
|
+
* Added :force option to create_table that'll try to drop the table if it already exists before creating
|
69
|
+
|
70
|
+
* Fix transactions so that calling return while inside a transaction will not leave an open transaction on the connection. [Nicholas Seckar]
|
71
|
+
|
72
|
+
* Use foreign_key inflection uniformly. #2156 [Blair Zajac <blair@orcaware.com>]
|
73
|
+
|
74
|
+
* model.association.clear should destroy associated objects if :dependent => true instead of nullifying their foreign keys. #2221 [joergd@pobox.com, ObieFernandez <obiefernandez@gmail.com>]
|
75
|
+
|
76
|
+
* Returning false from before_destroy should cancel the action. #1829 [Jeremy Huffman]
|
77
|
+
|
78
|
+
* Recognize PostgreSQL NOW() default as equivalent to CURRENT_TIMESTAMP or CURRENT_DATE, depending on the column's type. #2256 [mat <mat@absolight.fr>]
|
79
|
+
|
80
|
+
* Extensive documentation for the abstract database adapter. #2250 [François Beausoleil <fbeausoleil@ftml.net>]
|
81
|
+
|
82
|
+
* Clean up Fixtures.reset_sequences for PostgreSQL. Handle tables with no rows and models with custom primary keys. #2174, #2183 [jay@jay.fm, Blair Zajac <blair@orcaware.com>]
|
83
|
+
|
84
|
+
* Improve error message when nil is assigned to an attr which validates_size_of within a range. #2022 [Manuel Holtgrewe <purestorm@ggnore.net>]
|
85
|
+
|
86
|
+
* Make update_attribute use the same writer method that update_attributes uses.
|
87
|
+
#2237 [trevor@protocool.com]
|
88
|
+
|
89
|
+
* Make migrations honor table name prefixes and suffixes. #2298 [Jakob S, Marcel Molina]
|
90
|
+
|
91
|
+
* Correct and optimize PostgreSQL bytea escaping. #1745, #1837 [dave@cherryville.org, ken@miriamtech.com, bellis@deepthought.org]
|
92
|
+
|
93
|
+
* Fixtures should only reset a PostgreSQL sequence if it corresponds to an integer primary key named id. #1749 [chris@chrisbrinker.com]
|
94
|
+
|
95
|
+
* Standardize the interpretation of boolean columns in the Mysql and Sqlite adapters. (Use MysqlAdapter.emulate_booleans = false to disable this behavior)
|
96
|
+
|
97
|
+
* Added new symbol-driven approach to activating observers with Base#observers= [DHH]. Example:
|
98
|
+
|
99
|
+
ActiveRecord::Base.observers = :cacher, :garbage_collector
|
100
|
+
|
101
|
+
* Added AbstractAdapter#select_value and AbstractAdapter#select_values as convenience methods for selecting single values, instead of hashes, of the first column in a SELECT #2283 [solo@gatelys.com]
|
102
|
+
|
103
|
+
* Wrap :conditions in parentheses to prevent problems with OR's #1871 [Jamis Buck]
|
104
|
+
|
105
|
+
* Allow the postgresql adapter to work with the SchemaDumper. [Jamis Buck]
|
106
|
+
|
107
|
+
* Add ActiveRecord::SchemaDumper for dumping a DB schema to a pure-ruby file, making it easier to consolidate large migration lists and port database schemas between databases. [Jamis Buck]
|
108
|
+
|
109
|
+
* Fixed migrations for Windows when using more than 10 [David Naseby]
|
110
|
+
|
111
|
+
* Fixed that the create_x method from belongs_to wouldn't save the association properly #2042 [Florian Weber]
|
112
|
+
|
113
|
+
* Fixed saving a record with two unsaved belongs_to associations pointing to the same object #2023 [Tobias Luetke]
|
114
|
+
|
115
|
+
* Improved migrations' behavior when the schema_info table is empty. [Nicholas Seckar]
|
116
|
+
|
117
|
+
* Fixed that Observers didn't observe sub-classes #627 [Florian Weber]
|
118
|
+
|
119
|
+
* Fix eager loading error messages, allow :include to specify tables using strings or symbols. Closes #2222 [Marcel Molina]
|
120
|
+
|
121
|
+
* Added check for RAILS_CONNECTION_ADAPTERS on startup and only load the connection adapters specified within if its present (available in Rails through config.connection_adapters using the new config) #1958 [skae]
|
122
|
+
|
123
|
+
* Fixed various problems with has_and_belongs_to_many when using customer finder_sql #2094 [Florian Weber]
|
124
|
+
|
125
|
+
* Added better exception error when unknown column types are used with migrations #1814 [fbeausoleil@ftml.net]
|
126
|
+
|
127
|
+
* Fixed "connection lost" issue with the bundled Ruby/MySQL driver (would kill the app after 8 hours of inactivity) #2163, #428 [kajism@yahoo.com]
|
128
|
+
|
129
|
+
* Fixed comparison of Active Record objects so two new objects are not equal #2099 [deberg]
|
130
|
+
|
131
|
+
* Fixed that the SQL Server adapter would sometimes return DBI::Timestamp objects instead of Time #2127 [Tom Ward]
|
132
|
+
|
133
|
+
* Added the instance methods #root and #ancestors on acts_as_tree and fixed siblings to not include the current node #2142, #2140 [coffee2code]
|
134
|
+
|
135
|
+
* Fixed that Active Record would call SHOW FIELDS twice (or more) for the same model when the cached results were available #1947 [sd@notso.net]
|
136
|
+
|
137
|
+
* Added log_level and use_silence parameter to ActiveRecord::Base.benchmark. The first controls at what level the benchmark statement will be logged (now as debug, instead of info) and the second that can be passed false to include all logging statements during the benchmark block/
|
138
|
+
|
139
|
+
* Make sure the schema_info table is created before querying the current version #1903
|
140
|
+
|
141
|
+
* Fixtures ignore table name prefix and suffix #1987 [Jakob S]
|
142
|
+
|
143
|
+
* Add documentation for index_type argument to add_index method for migrations #2005 [blaine@odeo.com]
|
144
|
+
|
145
|
+
* Modify read_attribute to allow a symbol argument #2024 [Ken Kunz]
|
146
|
+
|
147
|
+
* Make destroy return self #1913 [sebastian.kanthak@muehlheim.de]
|
148
|
+
|
149
|
+
* Fix typo in validations documentation #1938 [court3nay]
|
150
|
+
|
151
|
+
* Make acts_as_list work for insert_at(1) #1966 [hensleyl@papermountain.org]
|
152
|
+
|
153
|
+
* Fix typo in count_by_sql documentation #1969 [Alexey Verkhovsky]
|
154
|
+
|
155
|
+
* Allow add_column and create_table to specify NOT NULL #1712 [emptysands@gmail.com]
|
156
|
+
|
157
|
+
* Fix create_table so that id column is implicitly added [Rick Olson]
|
158
|
+
|
159
|
+
* Default sequence names for Oracle changed to #{table_name}_seq, which is the most commonly used standard. In addition, a new method ActiveRecord::Base#set_sequence_name allows the developer to set the sequence name per model. This is a non-backwards-compatible change -- anyone using the old-style "rails_sequence" will need to either create new sequences, or set: ActiveRecord::Base.set_sequence_name = "rails_sequence" #1798
|
160
|
+
|
161
|
+
* OCIAdapter now properly handles synonyms, which are commonly used to separate out the schema owner from the application user #1798
|
162
|
+
|
163
|
+
* Fixed the handling of camelCase columns names in Oracle #1798
|
164
|
+
|
165
|
+
* Implemented for OCI the Rakefile tasks of :clone_structure_to_test, :db_structure_dump, and :purge_test_database, which enable Oracle folks to enjoy all the agile goodness of Rails for testing. Note that the current implementation is fairly limited -- only tables and sequences are cloned, not constraints or indexes. A full clone in Oracle generally requires some manual effort, and is version-specific. Post 9i, Oracle recommends the use of the DBMS_METADATA package, though that approach requires editing of the physical characteristics generated #1798
|
166
|
+
|
167
|
+
* Fixed the handling of multiple blob columns in Oracle if one or more of them are null #1798
|
168
|
+
|
169
|
+
* Added support for calling constrained class methods on has_many and has_and_belongs_to_many collections #1764 [Tobias Luetke]
|
170
|
+
|
171
|
+
class Comment < AR:B
|
172
|
+
def self.search(q)
|
173
|
+
find(:all, :conditions => ["body = ?", q])
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class Post < AR:B
|
178
|
+
has_many :comments
|
179
|
+
end
|
180
|
+
|
181
|
+
Post.find(1).comments.search('hi') # => SELECT * from comments WHERE post_id = 1 AND body = 'hi'
|
182
|
+
|
183
|
+
NOTICE: This patch changes the underlying SQL generated by has_and_belongs_to_many queries. If your relying on that, such as
|
184
|
+
by explicitly referencing the old t and j aliases, you'll need to update your code. Of course, you _shouldn't_ be relying on
|
185
|
+
details like that no less than you should be diving in to touch private variables. But just in case you do, consider yourself
|
186
|
+
noticed :)
|
187
|
+
|
188
|
+
* Added migration support for SQLite (using temporary tables to simulate ALTER TABLE) #1771 [Sam Stephenson]
|
189
|
+
|
190
|
+
* Remove extra definition of supports_migrations? from abstract_adaptor.rb [Nicholas Seckar]
|
191
|
+
|
192
|
+
* Fix acts_as_list so that moving next-to-last item to the bottom does not result in duplicate item positions
|
193
|
+
|
194
|
+
* Fixed incompatibility in DB2 adapter with the new limit/offset approach #1718 [Maik Schmidt]
|
195
|
+
|
196
|
+
* Added :select option to find which can specify a different value than the default *, like find(:all, :select => "first_name, last_name"), if you either only want to select part of the columns or exclude columns otherwise included from a join #1338 [Stefan Kaes]
|
197
|
+
|
198
|
+
|
1
199
|
*1.11.1* (11 July, 2005)
|
2
200
|
|
3
201
|
* Added support for limit and offset with eager loading of has_one and belongs_to associations. Using the options with has_many and has_and_belongs_to_many associations will now raise an ActiveRecord::ConfigurationError #1692 [Rick Olsen]
|
data/lib/active_record.rb
CHANGED
@@ -21,15 +21,17 @@
|
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
#++
|
23
23
|
|
24
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
25
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
unless defined?(ActiveSupport)
|
28
|
+
begin
|
29
|
+
$:.unshift(File.dirname(__FILE__) + "/../../activesupport/lib")
|
30
|
+
require 'active_support'
|
31
|
+
rescue LoadError
|
32
|
+
require 'rubygems'
|
33
|
+
require_gem 'activesupport'
|
34
|
+
end
|
33
35
|
end
|
34
36
|
|
35
37
|
require 'active_record/base'
|
@@ -46,11 +48,13 @@ require 'active_record/acts/tree'
|
|
46
48
|
require 'active_record/acts/nested_set'
|
47
49
|
require 'active_record/locking'
|
48
50
|
require 'active_record/migration'
|
51
|
+
require 'active_record/schema'
|
49
52
|
|
50
53
|
ActiveRecord::Base.class_eval do
|
51
54
|
include ActiveRecord::Validations
|
52
55
|
include ActiveRecord::Locking
|
53
56
|
include ActiveRecord::Callbacks
|
57
|
+
include ActiveRecord::Observing
|
54
58
|
include ActiveRecord::Timestamp
|
55
59
|
include ActiveRecord::Associations
|
56
60
|
include ActiveRecord::Aggregations
|
@@ -61,11 +65,12 @@ ActiveRecord::Base.class_eval do
|
|
61
65
|
include ActiveRecord::Acts::NestedSet
|
62
66
|
end
|
63
67
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
require
|
68
|
+
unless defined?(RAILS_CONNECTION_ADAPTERS)
|
69
|
+
RAILS_CONNECTION_ADAPTERS = %w(mysql postgresql sqlite sqlserver db2 oci)
|
70
|
+
end
|
71
|
+
|
72
|
+
RAILS_CONNECTION_ADAPTERS.each do |adapter|
|
73
|
+
require "active_record/connection_adapters/#{adapter}_adapter"
|
74
|
+
end
|
70
75
|
|
71
76
|
require 'active_record/query_cache'
|
@@ -72,7 +72,7 @@ module ActiveRecord
|
|
72
72
|
# the first in the list of all chapters.
|
73
73
|
module InstanceMethods
|
74
74
|
def insert_at(position = 1)
|
75
|
-
|
75
|
+
insert_at_position(position)
|
76
76
|
end
|
77
77
|
|
78
78
|
def move_lower
|
@@ -163,17 +163,19 @@ module ActiveRecord
|
|
163
163
|
# Overwrite this method to define the scope of the list changes
|
164
164
|
def scope_condition() "1" end
|
165
165
|
|
166
|
-
def bottom_position_in_list
|
167
|
-
item = bottom_item
|
166
|
+
def bottom_position_in_list(except = nil)
|
167
|
+
item = bottom_item(except)
|
168
168
|
item ? item.send(position_column) : 0
|
169
169
|
end
|
170
170
|
|
171
|
-
def bottom_item
|
172
|
-
|
171
|
+
def bottom_item(except = nil)
|
172
|
+
conditions = scope_condition
|
173
|
+
conditions = "#{conditions} AND id != #{except.id}" if except
|
174
|
+
self.class.find(:first, :conditions => conditions, :order => "#{position_column} DESC")
|
173
175
|
end
|
174
176
|
|
175
177
|
def assume_bottom_position
|
176
|
-
update_attribute(position_column, bottom_position_in_list.to_i + 1)
|
178
|
+
update_attribute(position_column, bottom_position_in_list(self).to_i + 1)
|
177
179
|
end
|
178
180
|
|
179
181
|
def assume_top_position
|
@@ -16,16 +16,23 @@ module ActiveRecord
|
|
16
16
|
# Example :
|
17
17
|
# root
|
18
18
|
# \_ child1
|
19
|
-
# \_
|
19
|
+
# \_ subchild1
|
20
|
+
# \_ subchild2
|
20
21
|
#
|
21
22
|
# root = Category.create("name" => "root")
|
22
|
-
# child1
|
23
|
-
# subchild1
|
23
|
+
# child1 = root.children.create("name" => "child1")
|
24
|
+
# subchild1 = child1.children.create("name" => "subchild1")
|
24
25
|
#
|
25
|
-
# root.parent
|
26
|
+
# root.parent # => nil
|
26
27
|
# child1.parent # => root
|
27
28
|
# root.children # => [child1]
|
28
29
|
# root.children.first.children.first # => subchild1
|
30
|
+
#
|
31
|
+
# In addition to the parent and children associations, the following instance methods are added to the class
|
32
|
+
# after specifying the act:
|
33
|
+
# * siblings: Return all the children of the parent excluding the current node ([ subchild2 ] when called from subchild1)
|
34
|
+
# * ancestors: Returns all the ancestors of the current node ([child1, root] when called from subchild2)
|
35
|
+
# * root: Returns the root of the current node (root when called from subchild2)
|
29
36
|
module ClassMethods
|
30
37
|
# Configuration options are:
|
31
38
|
#
|
@@ -48,15 +55,31 @@ module ActiveRecord
|
|
48
55
|
end
|
49
56
|
END
|
50
57
|
|
58
|
+
# Returns list of ancestors, starting from parent until root.
|
59
|
+
#
|
60
|
+
# subchild1.ancestors # => [child1, root]
|
61
|
+
define_method(:ancestors) do
|
62
|
+
node, nodes = self, []
|
63
|
+
nodes << node = node.parent until not node.has_parent?
|
64
|
+
nodes
|
65
|
+
end
|
66
|
+
|
67
|
+
define_method(:root) do
|
68
|
+
node = self
|
69
|
+
node = node.parent until not node.has_parent?
|
70
|
+
node
|
71
|
+
end
|
72
|
+
|
51
73
|
define_method(:siblings) do
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
74
|
+
self_and_siblings - [self]
|
75
|
+
end
|
76
|
+
|
77
|
+
define_method(:self_and_siblings) do
|
78
|
+
has_parent? ? parent.children : self.class.roots
|
57
79
|
end
|
80
|
+
|
58
81
|
end
|
59
82
|
end
|
60
83
|
end
|
61
84
|
end
|
62
|
-
end
|
85
|
+
end
|
@@ -120,7 +120,7 @@ module ActiveRecord
|
|
120
120
|
# composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ]
|
121
121
|
# composed_of :gps_location
|
122
122
|
def composed_of(part_id, options = {})
|
123
|
-
|
123
|
+
options.assert_valid_keys(:class_name, :mapping)
|
124
124
|
|
125
125
|
name = part_id.id2name
|
126
126
|
class_name = options[:class_name] || name_to_class_name(name)
|
@@ -131,12 +131,6 @@ module ActiveRecord
|
|
131
131
|
end
|
132
132
|
|
133
133
|
private
|
134
|
-
# Raises an exception if an invalid option has been specified to prevent misspellings from slipping through
|
135
|
-
def validate_options(valid_option_keys, supplied_option_keys)
|
136
|
-
unknown_option_keys = supplied_option_keys - valid_option_keys
|
137
|
-
raise(ActiveRecordError, "Unknown options: #{unknown_option_keys}") unless unknown_option_keys.empty?
|
138
|
-
end
|
139
|
-
|
140
134
|
def name_to_class_name(name)
|
141
135
|
name.capitalize.gsub(/_(.)/) { |s| $1.capitalize }
|
142
136
|
end
|
@@ -167,9 +167,14 @@ module ActiveRecord
|
|
167
167
|
# the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So its no
|
168
168
|
# catch-all for performance problems, but its a great way to cut down on the number of queries in a situation as the one described above.
|
169
169
|
#
|
170
|
-
# Please note that
|
171
|
-
#
|
172
|
-
#
|
170
|
+
# Please note that limited eager loading with has_many and has_and_belongs_to_many associations is not compatible with describing conditions
|
171
|
+
# on these eager tables. This will work:
|
172
|
+
#
|
173
|
+
# Post.find(:all, :include => :comments, :conditions => "posts.title = 'magic forest'", :limit => 2)
|
174
|
+
#
|
175
|
+
# ...but this will not (and an ArgumentError will be raised):
|
176
|
+
#
|
177
|
+
# Post.find(:all, :include => :comments, :conditions => "comments.body like 'Normal%'", :limit => 2)
|
173
178
|
#
|
174
179
|
# Also have in mind that since the eager loading is pulling from multiple tables, you'll have to disambiguate any column references
|
175
180
|
# in both conditions and orders. So :order => "posts.id DESC" will work while :order => "id DESC" will not. This may require that
|
@@ -227,7 +232,9 @@ module ActiveRecord
|
|
227
232
|
# This will also destroy the objects if they're declared as belongs_to and dependent on this model.
|
228
233
|
# * <tt>collection=objects</tt> - replaces the collections content by deleting and adding objects as appropriate.
|
229
234
|
# * <tt>collection_singular_ids=ids</tt> - replace the collection by the objects identified by the primary keys in +ids+
|
230
|
-
# * <tt>collection.clear</tt> - removes every object from the collection. This
|
235
|
+
# * <tt>collection.clear</tt> - removes every object from the collection. This destroys the associated objects if they
|
236
|
+
# are <tt>:dependent</tt>, deletes them directly from the database if they are <tt>:exclusively_dependent</tt>,
|
237
|
+
# and sets their foreign keys to NULL otherwise.
|
231
238
|
# * <tt>collection.empty?</tt> - returns true if there are no associated objects.
|
232
239
|
# * <tt>collection.size</tt> - returns the number of associated objects.
|
233
240
|
# * <tt>collection.find</tt> - finds an associated object according to the same rules as Base.find.
|
@@ -263,7 +270,9 @@ module ActiveRecord
|
|
263
270
|
# * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
|
264
271
|
# of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_many association will use "person_id"
|
265
272
|
# as the default foreign_key.
|
266
|
-
# * <tt>:dependent</tt> - if set to true all the associated
|
273
|
+
# * <tt>:dependent</tt> - if set to :destroy (or true) all the associated objects are destroyed
|
274
|
+
# alongside this object. Also accepts :nullify which will set the associated objects foriegn key
|
275
|
+
# field to NULL.
|
267
276
|
# May not be set if :exclusively_dependent is also set.
|
268
277
|
# * <tt>:exclusively_dependent</tt> - if set to true all the associated object are deleted in one SQL statement without having their
|
269
278
|
# before_destroy callback run. This should only be used on associations that depend solely on this class and don't need to do any
|
@@ -284,26 +293,39 @@ module ActiveRecord
|
|
284
293
|
# 'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
|
285
294
|
# 'ORDER BY p.first_name'
|
286
295
|
def has_many(association_id, options = {})
|
287
|
-
|
288
|
-
|
296
|
+
options.assert_valid_keys(
|
297
|
+
:foreign_key, :class_name, :exclusively_dependent, :dependent,
|
298
|
+
:conditions, :order, :finder_sql, :counter_sql,
|
299
|
+
:before_add, :after_add, :before_remove, :after_remove
|
300
|
+
)
|
301
|
+
|
289
302
|
association_name, association_class_name, association_class_primary_key_name =
|
290
303
|
associate_identification(association_id, options[:class_name], options[:foreign_key])
|
291
304
|
|
292
305
|
require_association_class(association_class_name)
|
293
306
|
|
294
|
-
if options[:dependent] and options[:exclusively_dependent]
|
295
|
-
|
307
|
+
raise ArgumentError, ':dependent and :exclusively_dependent are mutually exclusive options. You may specify one or the other.' if options[:dependent] and options[:exclusively_dependent]
|
308
|
+
|
296
309
|
# See HasManyAssociation#delete_records. Dependent associations
|
297
310
|
# delete children, otherwise foreign key is set to NULL.
|
298
|
-
|
299
|
-
|
300
|
-
|
311
|
+
case options[:dependent]
|
312
|
+
when :destroy, true
|
313
|
+
module_eval "before_destroy '#{association_name}.each { |o| o.destroy }'"
|
314
|
+
when :nullify
|
315
|
+
module_eval "before_destroy { |record| #{association_class_name}.update_all(%(#{association_class_primary_key_name} = NULL), %(#{association_class_primary_key_name} = \#{record.quoted_id})) }"
|
316
|
+
when nil, false
|
317
|
+
# pass
|
318
|
+
else
|
319
|
+
raise ArgumentError, 'The :dependent option expects either true, :destroy or :nullify'
|
320
|
+
end
|
321
|
+
|
322
|
+
if options[:exclusively_dependent]
|
301
323
|
module_eval "before_destroy { |record| #{association_class_name}.delete_all(%(#{association_class_primary_key_name} = \#{record.quoted_id})) }"
|
302
324
|
end
|
303
325
|
|
304
326
|
add_multiple_associated_save_callbacks(association_name)
|
305
|
-
|
306
|
-
|
327
|
+
add_association_callbacks(association_name, options)
|
328
|
+
|
307
329
|
collection_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, HasManyAssociation)
|
308
330
|
|
309
331
|
# deprecated api
|
@@ -347,7 +369,7 @@ module ActiveRecord
|
|
347
369
|
# sql fragment, such as "rank = 5".
|
348
370
|
# * <tt>:order</tt> - specify the order from which the associated object will be picked at the top. Specified as
|
349
371
|
# an "ORDER BY" sql fragment, such as "last_name, first_name DESC"
|
350
|
-
# * <tt>:dependent</tt> - if set to true
|
372
|
+
# * <tt>:dependent</tt> - if set to :destroy (or true) all the associated object is destroyed when this object is. Also
|
351
373
|
# association is assigned.
|
352
374
|
# * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
|
353
375
|
# of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_one association will use "person_id"
|
@@ -358,7 +380,7 @@ module ActiveRecord
|
|
358
380
|
# has_one :last_comment, :class_name => "Comment", :order => "posted_on"
|
359
381
|
# has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'"
|
360
382
|
def has_one(association_id, options = {})
|
361
|
-
|
383
|
+
options.assert_valid_keys(:class_name, :foreign_key, :remote, :conditions, :order, :dependent, :counter_cache)
|
362
384
|
|
363
385
|
association_name, association_class_name, association_class_primary_key_name =
|
364
386
|
associate_identification(association_id, options[:class_name], options[:foreign_key], false)
|
@@ -380,7 +402,16 @@ module ActiveRecord
|
|
380
402
|
association_constructor_method(:build, association_name, association_class_name, association_class_primary_key_name, options, HasOneAssociation)
|
381
403
|
association_constructor_method(:create, association_name, association_class_name, association_class_primary_key_name, options, HasOneAssociation)
|
382
404
|
|
383
|
-
|
405
|
+
case options[:dependent]
|
406
|
+
when :destroy, true
|
407
|
+
module_eval "before_destroy '#{association_name}.destroy unless #{association_name}.nil?'"
|
408
|
+
when :nullify
|
409
|
+
module_eval "before_destroy '#{association_name}.update_attribute(\"#{association_class_primary_key_name}\", nil)'"
|
410
|
+
when nil, false
|
411
|
+
# pass
|
412
|
+
else
|
413
|
+
raise ArgumentError, "The :dependent option expects either :destroy or :nullify."
|
414
|
+
end
|
384
415
|
|
385
416
|
# deprecated api
|
386
417
|
deprecated_has_association_method(association_name)
|
@@ -429,14 +460,14 @@ module ActiveRecord
|
|
429
460
|
# belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id",
|
430
461
|
# :conditions => 'discounts > #{payments_count}'
|
431
462
|
def belongs_to(association_id, options = {})
|
432
|
-
|
463
|
+
options.assert_valid_keys(:class_name, :foreign_key, :remote, :conditions, :order, :dependent, :counter_cache)
|
433
464
|
|
434
465
|
association_name, association_class_name, class_primary_key_name =
|
435
466
|
associate_identification(association_id, options[:class_name], options[:foreign_key], false)
|
436
467
|
|
437
468
|
require_association_class(association_class_name)
|
438
469
|
|
439
|
-
association_class_primary_key_name = options[:foreign_key] ||
|
470
|
+
association_class_primary_key_name = options[:foreign_key] || association_class_name.foreign_key
|
440
471
|
|
441
472
|
association_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, BelongsToAssociation)
|
442
473
|
association_constructor_method(:build, association_name, association_class_name, association_class_primary_key_name, options, BelongsToAssociation)
|
@@ -445,11 +476,13 @@ module ActiveRecord
|
|
445
476
|
module_eval do
|
446
477
|
before_save <<-EOF
|
447
478
|
association = instance_variable_get("@#{association_name}")
|
448
|
-
if not association.nil?
|
449
|
-
association.
|
450
|
-
|
451
|
-
|
452
|
-
|
479
|
+
if not association.nil?
|
480
|
+
if association.new_record?
|
481
|
+
association.save(true)
|
482
|
+
association.send(:construct_sql)
|
483
|
+
end
|
484
|
+
self["#{association_class_primary_key_name}"] = association.id if association.updated?
|
485
|
+
end
|
453
486
|
EOF
|
454
487
|
end
|
455
488
|
|
@@ -544,9 +577,12 @@ module ActiveRecord
|
|
544
577
|
# has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
|
545
578
|
# 'DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}'
|
546
579
|
def has_and_belongs_to_many(association_id, options = {})
|
547
|
-
|
548
|
-
|
549
|
-
|
580
|
+
options.assert_valid_keys(
|
581
|
+
:class_name, :table_name, :foreign_key, :association_foreign_key, :conditions,
|
582
|
+
:join_table, :finder_sql, :delete_sql, :insert_sql, :order, :uniq, :before_add, :after_add,
|
583
|
+
:before_remove, :after_remove
|
584
|
+
)
|
585
|
+
|
550
586
|
association_name, association_class_name, association_class_primary_key_name =
|
551
587
|
associate_identification(association_id, options[:class_name], options[:foreign_key])
|
552
588
|
|
@@ -570,12 +606,6 @@ module ActiveRecord
|
|
570
606
|
end
|
571
607
|
|
572
608
|
private
|
573
|
-
# Raises an exception if an invalid option has been specified to prevent misspellings from slipping through
|
574
|
-
def validate_options(valid_option_keys, supplied_option_keys)
|
575
|
-
unknown_option_keys = supplied_option_keys - valid_option_keys
|
576
|
-
raise(ActiveRecord::ActiveRecordError, "Unknown options: #{unknown_option_keys}") unless unknown_option_keys.empty?
|
577
|
-
end
|
578
|
-
|
579
609
|
def join_table_name(first_table_name, second_table_name)
|
580
610
|
if first_table_name < second_table_name
|
581
611
|
join_table = "#{first_table_name}_#{second_table_name}"
|
@@ -594,7 +624,7 @@ module ActiveRecord
|
|
594
624
|
)
|
595
625
|
end
|
596
626
|
|
597
|
-
primary_key_name = foreign_key ||
|
627
|
+
primary_key_name = foreign_key || name.foreign_key
|
598
628
|
|
599
629
|
return association_id.id2name, association_class_name, primary_key_name
|
600
630
|
end
|
@@ -681,41 +711,39 @@ module ActiveRecord
|
|
681
711
|
end
|
682
712
|
|
683
713
|
def add_multiple_associated_save_callbacks(association_name)
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
result &&= record.valid?
|
696
|
-
end
|
714
|
+
method_name = "validate_associated_records_for_#{association_name}".to_sym
|
715
|
+
define_method(method_name) do
|
716
|
+
@new_record_before_save = new_record?
|
717
|
+
association = instance_variable_get("@#{association_name}")
|
718
|
+
if association.respond_to?(:loaded?)
|
719
|
+
if new_record?
|
720
|
+
association
|
721
|
+
else
|
722
|
+
association.select { |record| record.new_record? }
|
723
|
+
end.each do |record|
|
724
|
+
errors.add "#{association_name}" unless record.valid?
|
697
725
|
end
|
698
|
-
|
726
|
+
end
|
699
727
|
end
|
700
728
|
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
records_to_save.each{ |record| association.send(:insert_record, record) }
|
711
|
-
association.send(:construct_sql) # reconstruct the SQL queries now that we know the owner's id
|
729
|
+
validate method_name
|
730
|
+
|
731
|
+
after_callback = <<-end_eval
|
732
|
+
association = instance_variable_get("@#{association_name}")
|
733
|
+
if association.respond_to?(:loaded?)
|
734
|
+
if @new_record_before_save
|
735
|
+
records_to_save = association
|
736
|
+
else
|
737
|
+
records_to_save = association.select { |record| record.new_record? }
|
712
738
|
end
|
713
|
-
|
739
|
+
records_to_save.each { |record| association.send(:insert_record, record) }
|
740
|
+
association.send(:construct_sql) # reconstruct the SQL queries now that we know the owner's id
|
741
|
+
end
|
742
|
+
end_eval
|
714
743
|
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
end
|
744
|
+
# Doesn't use after_save as that would save associations added in after_create/after_update twice
|
745
|
+
after_create(after_callback)
|
746
|
+
after_update(after_callback)
|
719
747
|
end
|
720
748
|
|
721
749
|
def association_constructor_method(constructor, association_name, association_class_name, association_class_primary_key_name, options, association_proxy_class)
|
@@ -743,7 +771,6 @@ module ActiveRecord
|
|
743
771
|
reflections = reflect_on_included_associations(options[:include])
|
744
772
|
|
745
773
|
guard_against_missing_reflections(reflections, options)
|
746
|
-
guard_against_unlimitable_reflections(reflections, options)
|
747
774
|
|
748
775
|
schema_abbreviations = generate_schema_abbreviations(reflections)
|
749
776
|
primary_key_table = generate_primary_key_table(reflections, schema_abbreviations)
|
@@ -783,14 +810,15 @@ module ActiveRecord
|
|
783
810
|
|
784
811
|
|
785
812
|
def reflect_on_included_associations(associations)
|
786
|
-
[ associations ].flatten.collect { |association| reflect_on_association(association) }
|
813
|
+
[ associations ].flatten.collect { |association| reflect_on_association(association.to_s.intern) }
|
787
814
|
end
|
788
815
|
|
789
816
|
def guard_against_missing_reflections(reflections, options)
|
790
817
|
reflections.each do |r|
|
791
818
|
raise(
|
792
819
|
ConfigurationError,
|
793
|
-
"Association was not found; perhaps you misspelled it?
|
820
|
+
"Association was not found; perhaps you misspelled it? " +
|
821
|
+
"You specified :include => :#{[options[:include]].flatten.join(', :')}"
|
794
822
|
) if r.nil?
|
795
823
|
end
|
796
824
|
end
|
@@ -843,24 +871,61 @@ module ActiveRecord
|
|
843
871
|
sql = "SELECT #{column_aliases(schema_abbreviations)} FROM #{table_name} "
|
844
872
|
sql << reflections.collect { |reflection| association_join(reflection) }.to_s
|
845
873
|
sql << "#{options[:joins]} " if options[:joins]
|
874
|
+
|
846
875
|
add_conditions!(sql, options[:conditions])
|
847
876
|
add_sti_conditions!(sql, reflections)
|
877
|
+
add_limited_ids_condition!(sql, options) if !using_limitable_reflections?(reflections) && options[:limit]
|
878
|
+
|
848
879
|
sql << "ORDER BY #{options[:order]} " if options[:order]
|
880
|
+
|
849
881
|
add_limit!(sql, options) if using_limitable_reflections?(reflections)
|
882
|
+
|
883
|
+
return sanitize_sql(sql)
|
884
|
+
end
|
885
|
+
|
886
|
+
def add_limited_ids_condition!(sql, options)
|
887
|
+
unless (id_list = select_limited_ids_list(options)).empty?
|
888
|
+
sql << "#{condition_word(sql)} #{table_name}.#{primary_key} IN (#{id_list}) "
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
def select_limited_ids_list(options)
|
893
|
+
connection.select_values(
|
894
|
+
construct_finder_sql_for_association_limiting(options),
|
895
|
+
"#{name} Load IDs For Limited Eager Loading"
|
896
|
+
).collect { |id| "'#{id}'" }.join(", ")
|
897
|
+
end
|
898
|
+
|
899
|
+
def construct_finder_sql_for_association_limiting(options)
|
900
|
+
raise(ArgumentError, "Limited eager loads and conditions on the eager tables is incompatible") if include_eager_conditions?(options)
|
901
|
+
|
902
|
+
sql = "SELECT #{primary_key} FROM #{table_name} "
|
903
|
+
add_conditions!(sql, options[:conditions])
|
904
|
+
sql << "ORDER BY #{options[:order]} " if options[:order]
|
905
|
+
add_limit!(sql, options)
|
850
906
|
return sanitize_sql(sql)
|
851
907
|
end
|
852
908
|
|
909
|
+
def include_eager_conditions?(options)
|
910
|
+
return false unless options[:conditions]
|
911
|
+
|
912
|
+
options[:conditions].scan(/ ([^.]+)\.[^.]+ /).flatten.any? do |condition_table_name|
|
913
|
+
condition_table_name != table_name
|
914
|
+
end
|
915
|
+
end
|
916
|
+
|
853
917
|
def using_limitable_reflections?(reflections)
|
854
918
|
reflections.reject { |r| [ :belongs_to, :has_one ].include?(r.macro) }.length.zero?
|
855
919
|
end
|
856
920
|
|
857
921
|
def add_sti_conditions!(sql, reflections)
|
858
|
-
|
859
|
-
|
860
|
-
|
922
|
+
sti_conditions = reflections.collect do |reflection|
|
923
|
+
reflection.klass.send(:type_condition) unless reflection.klass.descends_from_active_record?
|
924
|
+
end.compact
|
925
|
+
|
926
|
+
unless sti_conditions.empty?
|
927
|
+
sql << condition_word(sql) + sti_conditions.join(" AND ")
|
861
928
|
end
|
862
|
-
sti_sql.sub!(/AND/, "WHERE") unless sql =~ /where/i
|
863
|
-
sql << sti_sql
|
864
929
|
end
|
865
930
|
|
866
931
|
def column_aliases(schema_abbreviations)
|
@@ -890,16 +955,15 @@ module ActiveRecord
|
|
890
955
|
end
|
891
956
|
|
892
957
|
def add_association_callbacks(association_name, options)
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
end
|
958
|
+
callbacks = %w(before_add after_add before_remove after_remove)
|
959
|
+
callbacks.each do |callback_name|
|
960
|
+
full_callback_name = "#{callback_name.to_s}_for_#{association_name.to_s}"
|
961
|
+
defined_callbacks = options[callback_name.to_sym]
|
962
|
+
if options.has_key?(callback_name.to_sym)
|
963
|
+
class_inheritable_reader full_callback_name.to_sym
|
964
|
+
write_inheritable_array(full_callback_name.to_sym, [defined_callbacks].flatten)
|
965
|
+
end
|
966
|
+
end
|
903
967
|
end
|
904
968
|
|
905
969
|
def extract_record(schema_abbreviations, table_name, row)
|
@@ -910,6 +974,11 @@ module ActiveRecord
|
|
910
974
|
end
|
911
975
|
return record
|
912
976
|
end
|
977
|
+
|
978
|
+
def condition_word(sql)
|
979
|
+
sql =~ /where/i ? " AND " : "WHERE "
|
980
|
+
end
|
913
981
|
end
|
982
|
+
|
914
983
|
end
|
915
984
|
end
|