activerecord 1.3.0 → 1.4.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.

Files changed (75) hide show
  1. data/CHANGELOG +77 -2
  2. data/install.rb +5 -0
  3. data/lib/active_record.rb +6 -2
  4. data/lib/active_record/acts/list.rb +56 -45
  5. data/lib/active_record/acts/tree.rb +3 -2
  6. data/lib/active_record/associations.rb +10 -62
  7. data/lib/active_record/associations/association_collection.rb +20 -23
  8. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +36 -10
  9. data/lib/active_record/associations/has_many_association.rb +50 -25
  10. data/lib/active_record/base.rb +118 -80
  11. data/lib/active_record/callbacks.rb +51 -50
  12. data/lib/active_record/connection_adapters/abstract_adapter.rb +33 -12
  13. data/lib/active_record/connection_adapters/db2_adapter.rb +129 -0
  14. data/lib/active_record/connection_adapters/sqlite_adapter.rb +23 -1
  15. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +80 -90
  16. data/lib/active_record/fixtures.rb +1 -1
  17. data/lib/active_record/locking.rb +57 -0
  18. data/lib/active_record/support/class_attribute_accessors.rb +19 -5
  19. data/lib/active_record/support/class_inheritable_attributes.rb +4 -3
  20. data/lib/active_record/support/dependencies.rb +71 -0
  21. data/lib/active_record/support/inflector.rb +1 -0
  22. data/lib/active_record/support/misc.rb +29 -3
  23. data/lib/active_record/support/module_attribute_accessors.rb +57 -0
  24. data/lib/active_record/transactions.rb +18 -11
  25. data/lib/active_record/validations.rb +3 -3
  26. data/lib/active_record/vendor/db2.rb +357 -0
  27. data/lib/active_record/vendor/mysql.rb +1 -1
  28. data/rakefile +17 -5
  29. data/test/associations_test.rb +39 -4
  30. data/test/base_test.rb +13 -4
  31. data/test/binary_test.rb +43 -0
  32. data/test/callbacks_test.rb +230 -0
  33. data/test/connections/native_db2/connection.rb +24 -0
  34. data/test/connections/native_sqlserver/connection.rb +9 -3
  35. data/test/deprecated_associations_test.rb +16 -10
  36. data/test/finder_test.rb +65 -13
  37. data/test/fixtures/associations.png +0 -0
  38. data/test/fixtures/binary.rb +2 -0
  39. data/test/fixtures/companies.yml +21 -0
  40. data/test/fixtures/courses.yml +7 -0
  41. data/test/fixtures/customers.yml +7 -0
  42. data/test/fixtures/db_definitions/db2.sql +124 -0
  43. data/test/fixtures/db_definitions/db22.sql +4 -0
  44. data/test/fixtures/db_definitions/mysql.sql +12 -0
  45. data/test/fixtures/db_definitions/postgresql.sql +13 -0
  46. data/test/fixtures/db_definitions/sqlite.sql +9 -0
  47. data/test/fixtures/db_definitions/sqlserver.sql +13 -0
  48. data/test/fixtures/developers_projects.yml +13 -0
  49. data/test/fixtures/entrants.yml +14 -0
  50. data/test/fixtures/fixture_database.sqlite +0 -0
  51. data/test/fixtures/movies.yml +7 -0
  52. data/test/fixtures/people.yml +3 -0
  53. data/test/fixtures/person.rb +1 -0
  54. data/test/fixtures/projects.yml +7 -0
  55. data/test/fixtures/topics.yml +21 -0
  56. data/test/locking_test.rb +34 -0
  57. data/test/mixin_test.rb +6 -0
  58. data/test/validations_test.rb +1 -1
  59. metadata +33 -29
  60. data/test/fixtures/companies/first_client +0 -6
  61. data/test/fixtures/companies/first_firm +0 -4
  62. data/test/fixtures/companies/second_client +0 -6
  63. data/test/fixtures/courses/java +0 -2
  64. data/test/fixtures/courses/ruby +0 -2
  65. data/test/fixtures/customers/david +0 -6
  66. data/test/fixtures/entrants/first +0 -3
  67. data/test/fixtures/entrants/second +0 -3
  68. data/test/fixtures/entrants/third +0 -3
  69. data/test/fixtures/movies/first +0 -2
  70. data/test/fixtures/movies/second +0 -2
  71. data/test/fixtures/projects/action_controller +0 -2
  72. data/test/fixtures/projects/active_record +0 -2
  73. data/test/fixtures/topics/first +0 -10
  74. data/test/fixtures/topics/second +0 -8
  75. data/test/inflector_test.rb +0 -122
data/CHANGELOG CHANGED
@@ -1,4 +1,79 @@
1
- *1.3.0*
1
+ *1.4.0* (January 4th, 2005)
2
+
3
+ * Added automated optimistic locking if the field <tt>lock_version</tt> is present. Each update to the
4
+ record increments the lock_version column and the locking facilities ensure that records instantiated twice
5
+ will let the last one saved raise a StaleObjectError if the first was also updated. Example:
6
+
7
+ p1 = Person.find(1)
8
+ p2 = Person.find(1)
9
+
10
+ p1.first_name = "Michael"
11
+ p1.save
12
+
13
+ p2.first_name = "should fail"
14
+ p2.save # Raises a ActiveRecord::StaleObjectError
15
+
16
+ You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging,
17
+ or otherwise apply the business logic needed to resolve the conflict.
18
+
19
+ #384 [Michael Koziarski]
20
+
21
+ * Added dynamic attribute-based finders as a cleaner way of getting objects by simple queries without turning to SQL.
22
+ They work by appending the name of an attribute to <tt>find_by_</tt>, so you get finders like <tt>Person.find_by_user_name,
23
+ Payment.find_by_transaction_id</tt>. So instead of writing <tt>Person.find_first(["user_name = ?", user_name])</tt>, you just do
24
+ <tt>Person.find_by_user_name(user_name)</tt>.
25
+
26
+ It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like
27
+ <tt>Person.find_by_user_name_and_password</tt> or even <tt>Payment.find_by_purchaser_and_state_and_country</tt>. So instead of writing
28
+ <tt>Person.find_first(["user_name = ? AND password = ?", user_name, password])</tt>, you just do
29
+ <tt>Person.find_by_user_name_and_password(user_name, password)</tt>.
30
+
31
+ While primarily a construct for easier find_firsts, it can also be used as a construct for find_all by using calls like
32
+ <tt>Payment.find_all_by_amount(50)</tt> that is turned into <tt>Payment.find_all(["amount = ?", 50])</tt>. This is something not as equally useful,
33
+ though, as it's not possible to specify the order in which the objects are returned.
34
+
35
+ * Added block-style for callbacks #332 [bitsweat].
36
+
37
+ Before:
38
+ before_destroy(Proc.new{ |record| Person.destroy_all "firm_id = #{record.id}" })
39
+
40
+ After:
41
+ before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
42
+
43
+ * Added :counter_cache option to acts_as_tree that works just like the one you can define on belongs_to #371 [Josh]
44
+
45
+ * Added Base.default_timezone accessor that determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates
46
+ and times from the database. This is set to :local by default.
47
+
48
+ * Added the possibility for adapters to overwrite add_limit! to implement a different limiting scheme than "LIMIT X" used by MySQL, PostgreSQL, and SQLite.
49
+
50
+ * Added the possibility of having objects with acts_as_list created before their scope is available or...
51
+
52
+ * Added a db2 adapter that only depends on the Ruby/DB2 bindings (http://raa.ruby-lang.org/project/ruby-db2/) #386 [Maik Schmidt]
53
+
54
+ * Added the final touches to the Microsoft SQL Server adapter by Joey Gibson that makes it suitable for actual use #394 [DeLynn Barry]
55
+
56
+ * Added that Base#find takes an optional options hash, including :conditions. Base#find_on_conditions deprecated in favor of #find with :conditions #407 [bitsweat]
57
+
58
+ * Added HasManyAssociation#count that works like Base#count #413 [intinig]
59
+
60
+ * Fixed handling of binary content in blobs and similar fields for Ruby/MySQL and SQLite #409 [xal]
61
+
62
+ * Fixed a bug in the Ruby/MySQL that caused binary content to be escaped badly and come back mangled #405 [Tobias Luetke]
63
+
64
+ * Fixed that the const_missing autoload assumes the requested constant is set by require_association and calls const_get to retrieve it.
65
+ If require_association did not set the constant then const_get will call const_missing, resulting in an infinite loop #380 [bitsweat]
66
+
67
+ * Fixed broken transactions that were actually only running object-level and not db level transactions [andreas]
68
+
69
+ * Fixed that validates_uniqueness_of used 'id' instead of defined primary key #406
70
+
71
+ * Fixed that the overwritten respond_to? method didn't take two parameters like the original #391
72
+
73
+ * Fixed quoting in validates_format_of that would allow some rules to pass regardless of input #390 [Dmitry V. Sabanin]
74
+
75
+
76
+ *1.3.0* (December 23, 2004)
2
77
 
3
78
  * Added a require_association hook on const_missing that makes it possible to use any model class without requiring it first. This makes STI look like:
4
79
 
@@ -638,7 +713,7 @@
638
713
  * Fixed PostgreSQL adapter so default values are displayed properly when used in conjunction with
639
714
  Action Pack scaffolding.
640
715
 
641
- * Fixed booleans support for PostgreSQL (use real true/falseon boolean fields instead of 0/1 on tinyints) [radsaq]
716
+ * Fixed booleans support for PostgreSQL (use real true/false on boolean fields instead of 0/1 on tinyints) [radsaq]
642
717
 
643
718
 
644
719
  *0.9.2*
data/install.rb CHANGED
@@ -35,11 +35,14 @@ files = %w-
35
35
  active_record/base.rb
36
36
  active_record/callbacks.rb
37
37
  active_record/connection_adapters/abstract_adapter.rb
38
+ active_record/connection_adapters/db2_adapter.rb
38
39
  active_record/connection_adapters/mysql_adapter.rb
39
40
  active_record/connection_adapters/postgresql_adapter.rb
40
41
  active_record/connection_adapters/sqlite_adapter.rb
42
+ active_record/connection_adapters/sqlserver_adapter.rb
41
43
  active_record/deprecated_associations.rb
42
44
  active_record/fixtures.rb
45
+ active_record/locking.rb
43
46
  active_record/observer.rb
44
47
  active_record/reflection.rb
45
48
  active_record/acts/list.rb
@@ -48,6 +51,8 @@ files = %w-
48
51
  active_record/support/class_inheritable_attributes.rb
49
52
  active_record/support/clean_logger.rb
50
53
  active_record/support/inflector.rb
54
+ active_record/support/misc.rb
55
+ active_record/timestamp.rb
51
56
  active_record/transactions.rb
52
57
  active_record/validations.rb
53
58
  active_record/vendor/mysql.rb
@@ -26,6 +26,7 @@ $:.unshift(File.dirname(__FILE__))
26
26
 
27
27
  require 'active_record/support/clean_logger'
28
28
  require 'active_record/support/misc'
29
+ require 'active_record/support/dependencies'
29
30
 
30
31
  require 'active_record/base'
31
32
  require 'active_record/observer'
@@ -38,11 +39,13 @@ require 'active_record/reflection'
38
39
  require 'active_record/timestamp'
39
40
  require 'active_record/acts/list'
40
41
  require 'active_record/acts/tree'
42
+ require 'active_record/locking'
41
43
 
42
44
  ActiveRecord::Base.class_eval do
43
45
  include ActiveRecord::Validations
44
- include ActiveRecord::Timestamp
45
46
  include ActiveRecord::Callbacks
47
+ include ActiveRecord::Locking
48
+ include ActiveRecord::Timestamp
46
49
  include ActiveRecord::Associations
47
50
  include ActiveRecord::Aggregations
48
51
  include ActiveRecord::Transactions
@@ -54,4 +57,5 @@ end
54
57
  require 'active_record/connection_adapters/mysql_adapter'
55
58
  require 'active_record/connection_adapters/postgresql_adapter'
56
59
  require 'active_record/connection_adapters/sqlite_adapter'
57
- require 'active_record/connection_adapters/sqlserver_adapter'
60
+ require 'active_record/connection_adapters/sqlserver_adapter'
61
+ require 'active_record/connection_adapters/db2_adapter'
@@ -36,19 +36,31 @@ module ActiveRecord
36
36
 
37
37
  configuration[:scope] = "#{configuration[:scope]}_id".intern if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/
38
38
 
39
+ if configuration[:scope].is_a?(Symbol)
40
+ scope_condition_method = %(
41
+ def scope_condition
42
+ if #{configuration[:scope].to_s}.nil?
43
+ "#{configuration[:scope].to_s} IS NULL"
44
+ else
45
+ "#{configuration[:scope].to_s} = \#{#{configuration[:scope].to_s}}"
46
+ end
47
+ end
48
+ )
49
+ else
50
+ scope_condition_method = "def scope_condition() \"#{configuration[:scope]}\" end"
51
+ end
52
+
39
53
  class_eval <<-EOV
40
54
  include ActiveRecord::Acts::List::InstanceMethods
41
55
 
42
56
  def position_column
43
57
  '#{configuration[:column]}'
44
58
  end
45
-
46
- def scope_condition
47
- "#{configuration[:scope].is_a?(Symbol) ? configuration[:scope].to_s + " = \#{" + configuration[:scope].to_s + "}" : configuration[:scope]}"
48
- end
59
+
60
+ #{scope_condition_method}
49
61
 
50
62
  before_destroy :remove_from_list
51
- before_create :add_to_list_bottom
63
+ before_create :add_to_list_bottom
52
64
  EOV
53
65
  end
54
66
  end
@@ -123,55 +135,54 @@ module ActiveRecord
123
135
  end
124
136
 
125
137
  private
126
-
127
- def add_to_list_top
128
- increment_positions_on_all_items
129
- end
138
+ def add_to_list_top
139
+ increment_positions_on_all_items
140
+ end
130
141
 
131
- def add_to_list_bottom
132
- write_attribute(position_column, bottom_position_in_list.to_i + 1)
133
- end
142
+ def add_to_list_bottom
143
+ write_attribute(position_column, bottom_position_in_list.to_i + 1)
144
+ end
134
145
 
135
- # Overwrite this method to define the scope of the list changes
136
- def scope_condition() "1" end
146
+ # Overwrite this method to define the scope of the list changes
147
+ def scope_condition() "1" end
137
148
 
138
- def bottom_position_in_list
139
- item = bottom_item
140
- item ? item.send(position_column) : 0
141
- end
149
+ def bottom_position_in_list
150
+ item = bottom_item
151
+ item ? item.send(position_column) : 0
152
+ end
142
153
 
143
- def bottom_item
144
- self.class.find_first(
145
- "#{scope_condition} ",
146
- "#{position_column} DESC"
147
- )
148
- end
154
+ def bottom_item
155
+ self.class.find_first(
156
+ "#{scope_condition} ",
157
+ "#{position_column} DESC"
158
+ )
159
+ end
149
160
 
150
- def assume_bottom_position
151
- update_attribute position_column, bottom_position_in_list.to_i + 1
152
- end
161
+ def assume_bottom_position
162
+ update_attribute position_column, bottom_position_in_list.to_i + 1
163
+ end
153
164
 
154
- def assume_top_position
155
- update_attribute position_column, 1
156
- end
165
+ def assume_top_position
166
+ update_attribute position_column, 1
167
+ end
157
168
 
158
- def decrement_positions_on_lower_items
159
- self.class.update_all(
160
- "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}"
161
- )
162
- end
169
+ def decrement_positions_on_lower_items
170
+ self.class.update_all(
171
+ "#{position_column} = (#{position_column} - 1)", "#{scope_condition} AND #{position_column} > #{send(position_column).to_i}"
172
+ )
173
+ end
163
174
 
164
- def increment_positions_on_higher_items
165
- self.class.update_all(
166
- "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
167
- )
168
- end
175
+ def increment_positions_on_higher_items
176
+ self.class.update_all(
177
+ "#{position_column} = (#{position_column} + 1)", "#{scope_condition} AND #{position_column} < #{send(position_column).to_i}"
178
+ )
179
+ end
169
180
 
170
- def increment_positions_on_all_items
171
- self.class.update_all(
172
- "#{position_column} = (#{position_column} + 1)", "#{scope_condition}"
173
- )
174
- end
181
+ def increment_positions_on_all_items
182
+ self.class.update_all(
183
+ "#{position_column} = (#{position_column} + 1)", "#{scope_condition}"
184
+ )
185
+ end
175
186
  end
176
187
  end
177
188
  end
@@ -31,11 +31,12 @@ module ActiveRecord
31
31
  #
32
32
  # * <tt>foreign_key</tt> - specifies the column name to use for track of the tree (default: parent_id)
33
33
  # * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
34
+ # * <tt>counter_cache</tt> - keeps a count in a children_count column if set to true (default: false).
34
35
  def acts_as_tree(options = {})
35
- configuration = { :foreign_key => "parent_id", :order => nil }
36
+ configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil }
36
37
  configuration.update(options) if options.is_a?(Hash)
37
38
 
38
- belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key]
39
+ belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
39
40
  has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => true
40
41
  end
41
42
  end
@@ -3,30 +3,6 @@ require 'active_record/associations/has_many_association'
3
3
  require 'active_record/associations/has_and_belongs_to_many_association'
4
4
  require 'active_record/deprecated_associations'
5
5
 
6
-
7
- unless Object.respond_to?(:require_association)
8
- Object.send(:define_method, :require_association) { |file_name| ActiveRecord::Base.require_association(file_name) }
9
- end
10
-
11
- class Object
12
- class << self
13
- # Use const_missing to autoload associations so we don't have to
14
- # require_association when using single-table inheritance.
15
- unless respond_to?(:pre_association_const_missing)
16
- alias_method :pre_association_const_missing, :const_missing
17
-
18
- def const_missing(class_id)
19
- begin
20
- require_association(Inflector.underscore(Inflector.demodulize(class_id.to_s)))
21
- return Object.const_get(class_id) if Object.const_get(class_id).ancestors.include?(ActiveRecord::Base)
22
- rescue LoadError
23
- pre_association_const_missing(class_id)
24
- end
25
- end
26
- end
27
- end
28
- end
29
-
30
6
  module ActiveRecord
31
7
  module Associations # :nodoc:
32
8
  def self.append_features(base)
@@ -146,7 +122,7 @@ module ActiveRecord
146
122
  # All of the association macros can be specialized through options which makes more complex cases than the simple and guessable ones
147
123
  # possible.
148
124
  module ClassMethods
149
- # Adds the following methods for retrival and query of collections of associated objects.
125
+ # Adds the following methods for retrieval and query of collections of associated objects.
150
126
  # +collection+ is replaced with the symbol passed as the first argument, so
151
127
  # <tt>has_many :clients</tt> would add among others <tt>has_clients?</tt>.
152
128
  # * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
@@ -248,7 +224,7 @@ module ActiveRecord
248
224
  deprecated_build_method(association_name)
249
225
  end
250
226
 
251
- # Adds the following methods for retrival and query of a single associated object.
227
+ # Adds the following methods for retrieval and query of a single associated object.
252
228
  # +association+ is replaced with the symbol passed as the first argument, so
253
229
  # <tt>has_one :manager</tt> would add among others <tt>has_manager?</tt>.
254
230
  # * <tt>association(force_reload = false)</tt> - returns the associated object. Nil is returned if none is found.
@@ -304,7 +280,7 @@ module ActiveRecord
304
280
  module_eval "before_destroy '#{association_name}.destroy if has_#{association_name}?'" if options[:dependent]
305
281
  end
306
282
 
307
- # Adds the following methods for retrival and query for a single associated object that this object holds an id to.
283
+ # Adds the following methods for retrieval and query for a single associated object that this object holds an id to.
308
284
  # +association+ is replaced with the symbol passed as the first argument, so
309
285
  # <tt>belongs_to :author</tt> would add among others <tt>has_author?</tt>.
310
286
  # * <tt>association(force_reload = false)</tt> - returns the associated object. Nil is returned if none is found.
@@ -313,7 +289,7 @@ module ActiveRecord
313
289
  # same id as the associated object.
314
290
  # * <tt>association.nil?</tt> - returns true if there is no associated object.
315
291
  #
316
- # Example: An Post class declares <tt>has_one :author</tt>, which will add:
292
+ # Example: A Post class declares <tt>has_one :author</tt>, which will add:
317
293
  # * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
318
294
  # * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>)
319
295
  # * <tt>Post#author?</tt> (similar to <tt>post.author == some_author</tt>)
@@ -388,9 +364,12 @@ module ActiveRecord
388
364
  #
389
365
  # Any additional fields added to the join table will be placed as attributes when pulling records out through
390
366
  # has_and_belongs_to_many associations. This is helpful when have information about the association itself
391
- # that you want available on retrival.
367
+ # that you want available on retrieval. Note that any fields in the join table will override matching field names
368
+ # in the two joined tables. As a consequence, having an "id" field in the join table usually has the undesirable
369
+ # result of clobbering the "id" fields in either of the other two tables.
370
+ #
392
371
  #
393
- # Adds the following methods for retrival and query.
372
+ # Adds the following methods for retrieval and query.
394
373
  # +collection+ is replaced with the symbol passed as the first argument, so
395
374
  # <tt>has_and_belongs_to_many :categories</tt> would add among others +add_categories+.
396
375
  # * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
@@ -478,31 +457,6 @@ module ActiveRecord
478
457
  deprecated_has_collection_method(association_name)
479
458
  end
480
459
 
481
- # Loads the <tt>file_name</tt> if reload_associations is true or requires if it's false.
482
- def require_association(file_name)
483
- if !associations_loaded.include?(file_name)
484
- associations_loaded << file_name
485
- reload_associations ? silence_warnings { load("#{file_name}.rb") } : require(file_name)
486
- end
487
- end
488
-
489
- # Resets the list of dependencies loaded (typically to be called by the end of a request), so when require_association is
490
- # called for that dependency it'll be loaded anew.
491
- def reset_associations_loaded
492
- self.associations_loaded = []
493
- end
494
-
495
- # Reload all the associations that have already been loaded once.
496
- def reload_associations_loaded
497
- associations_loaded.each do |file_name|
498
- begin
499
- silence_warnings { load("#{file_name}.rb") }
500
- rescue LoadError
501
- # The association didn't reside in its own file, so we assume it was required by other means
502
- end
503
- end
504
- end
505
-
506
460
  private
507
461
  # Raises an exception if an invalid option has been specified to prevent misspellings from slipping through
508
462
  def validate_options(valid_option_keys, supplied_option_keys)
@@ -619,13 +573,7 @@ module ActiveRecord
619
573
  end
620
574
 
621
575
  def require_association_class(class_name)
622
- return unless class_name
623
-
624
- begin
625
- require_association(Inflector.underscore(class_name))
626
- rescue LoadError
627
- # Failed to load the associated class -- let's hope the developer is doing the requiring himself.
628
- end
576
+ require_association(Inflector.underscore(class_name)) if class_name
629
577
  end
630
578
  end
631
579
  end
@@ -22,8 +22,8 @@ module ActiveRecord
22
22
  @collection.to_ary
23
23
  end
24
24
 
25
- def respond_to?(symbol)
26
- proxy_respond_to?(symbol) || [].respond_to?(symbol)
25
+ def respond_to?(symbol, include_priv = false)
26
+ proxy_respond_to?(symbol, include_priv) || [].respond_to?(symbol, include_priv)
27
27
  end
28
28
 
29
29
  def loaded?
@@ -100,13 +100,25 @@ module ActiveRecord
100
100
  def interpolate_sql(sql, record = nil)
101
101
  @owner.send(:interpolate_sql, sql, record)
102
102
  end
103
-
103
+
104
+ def sanitize_sql(sql)
105
+ @association_class.send(:sanitize_sql, sql)
106
+ end
107
+
108
+ def extract_options_from_args!(args)
109
+ @owner.send(:extract_options_from_args!, args)
110
+ end
111
+
104
112
  private
105
113
  def load_collection
106
- begin
107
- @collection = find_all_records unless loaded?
108
- rescue ActiveRecord::RecordNotFound
109
- @collection = []
114
+ if loaded?
115
+ @collection
116
+ else
117
+ begin
118
+ @collection = find_all_records
119
+ rescue ActiveRecord::RecordNotFound
120
+ @collection = []
121
+ end
110
122
  end
111
123
  end
112
124
 
@@ -114,25 +126,10 @@ module ActiveRecord
114
126
  raise ActiveRecord::AssociationTypeMismatch, "#{@association_class} expected, got #{record.class}" unless record.is_a?(@association_class)
115
127
  end
116
128
 
117
-
118
- def load_collection_to_array
119
- return unless @collection_array.nil?
120
- begin
121
- @collection_array = find_all_records
122
- rescue ActiveRecord::StatementInvalid, ActiveRecord::RecordNotFound
123
- @collection_array = []
124
- end
125
- end
126
-
127
- def duplicated_records_array(records)
128
- records = [records] unless records.is_a?(Array) || records.is_a?(ActiveRecord::Associations::AssociationCollection)
129
- records.dup
130
- end
131
-
132
129
  # Array#flatten has problems with rescursive arrays. Going one level deeper solves the majority of the problems.
133
130
  def flatten_deeper(array)
134
131
  array.collect { |element| element.respond_to?(:flatten) ? element.flatten : element }.flatten
135
132
  end
136
133
  end
137
134
  end
138
- end
135
+ end