activerecord 2.3.8 → 2.3.9.pre

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 (64) hide show
  1. data/CHANGELOG +1 -4
  2. data/Rakefile +1 -1
  3. data/examples/performance.rb +2 -0
  4. data/lib/active_record/association_preload.rb +12 -2
  5. data/lib/active_record/associations.rb +1 -1
  6. data/lib/active_record/associations/association_collection.rb +33 -4
  7. data/lib/active_record/attribute_methods.rb +0 -4
  8. data/lib/active_record/autosave_association.rb +2 -2
  9. data/lib/active_record/base.rb +28 -16
  10. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +1 -1
  11. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1 -0
  12. data/lib/active_record/connection_adapters/abstract_adapter.rb +6 -0
  13. data/lib/active_record/connection_adapters/mysql_adapter.rb +2 -0
  14. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
  15. data/lib/active_record/connection_adapters/sqlite_adapter.rb +2 -1
  16. data/lib/active_record/dirty.rb +1 -1
  17. data/lib/active_record/locale/en.yml +11 -11
  18. data/lib/active_record/locking/optimistic.rb +1 -0
  19. data/lib/active_record/migration.rb +1 -1
  20. data/lib/active_record/named_scope.rb +14 -9
  21. data/lib/active_record/nested_attributes.rb +11 -8
  22. data/lib/active_record/serialization.rb +1 -1
  23. data/lib/active_record/session_store.rb +9 -1
  24. data/lib/active_record/validations.rb +12 -12
  25. data/lib/active_record/version.rb +1 -1
  26. data/test/cases/adapter_test.rb +7 -8
  27. data/test/cases/associations/eager_load_nested_include_test.rb +7 -7
  28. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +19 -0
  29. data/test/cases/associations/eager_test.rb +7 -0
  30. data/test/cases/associations/has_many_associations_test.rb +68 -3
  31. data/test/cases/associations_test.rb +29 -0
  32. data/test/cases/base_test.rb +35 -75
  33. data/test/cases/connection_test_mysql.rb +1 -0
  34. data/test/cases/counter_cache_test.rb +84 -0
  35. data/test/cases/locking_test.rb +2 -1
  36. data/test/cases/migration_test.rb +4 -0
  37. data/test/cases/named_scope_test.rb +6 -1
  38. data/test/cases/nested_attributes_test.rb +49 -14
  39. data/test/cases/reflection_test.rb +5 -5
  40. data/test/cases/sp_test_mysql.rb +16 -0
  41. data/test/cases/transactions_test.rb +22 -1
  42. data/test/cases/validations_i18n_test.rb +12 -12
  43. data/test/cases/validations_test.rb +42 -30
  44. data/test/fixtures/fixture_database.sqlite3 +0 -0
  45. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  46. data/test/fixtures/polymorphic_designs.yml +19 -0
  47. data/test/fixtures/polymorphic_prices.yml +19 -0
  48. data/test/fixtures/tees.yml +4 -0
  49. data/test/fixtures/ties.yml +4 -0
  50. data/test/models/author.rb +2 -0
  51. data/test/models/event_author.rb +3 -0
  52. data/test/models/pirate.rb +2 -2
  53. data/test/models/polymorphic_design.rb +3 -0
  54. data/test/models/polymorphic_price.rb +3 -0
  55. data/test/models/post.rb +2 -0
  56. data/test/models/tee.rb +4 -0
  57. data/test/models/tie.rb +4 -0
  58. data/test/schema/mysql_specific_schema.rb +7 -0
  59. data/test/schema/schema.rb +16 -0
  60. metadata +24 -13
  61. data/examples/performance.sql +0 -85
  62. data/test/cases/encoding_test.rb +0 -6
  63. data/test/fixtures/fixture_database.sqlite +0 -0
  64. data/test/fixtures/fixture_database_2.sqlite +0 -0
data/CHANGELOG CHANGED
@@ -1,8 +1,5 @@
1
+ *2.3.9 (August 29, 2010)*
1
2
  *2.3.8 (May 24, 2010)*
2
-
3
- * Version bump.
4
-
5
-
6
3
  *2.3.7 (May 24, 2010)*
7
4
 
8
5
  * Version bump.
data/Rakefile CHANGED
@@ -192,7 +192,7 @@ spec = Gem::Specification.new do |s|
192
192
  s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
193
193
  end
194
194
 
195
- s.add_dependency('activesupport', '= 2.3.8' + PKG_BUILD)
195
+ s.add_dependency('activesupport', '= 2.3.9' + PKG_BUILD)
196
196
 
197
197
  s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
198
198
  s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"
@@ -12,6 +12,8 @@ require 'rbench'
12
12
 
13
13
  __DIR__ = File.dirname(__FILE__)
14
14
  $:.unshift "#{__DIR__}/../lib"
15
+ $:.unshift "#{__DIR__}/../../activesupport/lib"
16
+
15
17
  require 'active_record'
16
18
 
17
19
  conn = { :adapter => 'mysql',
@@ -282,7 +282,11 @@ module ActiveRecord
282
282
  end
283
283
  through_records.flatten!
284
284
  else
285
- records.first.class.preload_associations(records, through_association)
285
+ options = {}
286
+ options[:include] = reflection.options[:include] || reflection.options[:source] if reflection.options[:conditions]
287
+ options[:order] = reflection.options[:order]
288
+ options[:conditions] = reflection.options[:conditions]
289
+ records.first.class.preload_associations(records, through_association, options)
286
290
  through_records = records.map {|record| record.send(through_association)}.flatten
287
291
  end
288
292
  through_records.compact!
@@ -357,7 +361,13 @@ module ActiveRecord
357
361
  table_name = reflection.klass.quoted_table_name
358
362
 
359
363
  if interface = reflection.options[:as]
360
- conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'"
364
+ parent_type = if reflection.active_record.abstract_class?
365
+ self.base_class.sti_name
366
+ else
367
+ reflection.active_record.sti_name
368
+ end
369
+
370
+ conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{parent_type}'"
361
371
  else
362
372
  foreign_key = reflection.primary_key_name
363
373
  conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} #{in_or_equals_for_ids(ids)}"
@@ -1782,7 +1782,7 @@ module ActiveRecord
1782
1782
  end
1783
1783
 
1784
1784
  def using_limitable_reflections?(reflections)
1785
- reflections.collect(&:collection?).length.zero?
1785
+ reflections.none?(&:collection?)
1786
1786
  end
1787
1787
 
1788
1788
  def column_aliases(join_dependency)
@@ -234,8 +234,9 @@ module ActiveRecord
234
234
  # See destroy for more info.
235
235
  def destroy_all
236
236
  load_target
237
- destroy(@target)
238
- reset_target!
237
+ destroy(@target).tap do
238
+ reset_target!
239
+ end
239
240
  end
240
241
 
241
242
  def create(attrs = {})
@@ -349,7 +350,17 @@ module ActiveRecord
349
350
  begin
350
351
  if !loaded?
351
352
  if @target.is_a?(Array) && @target.any?
352
- @target = find_target + @target.find_all {|t| t.new_record? }
353
+ @target = find_target.map do |f|
354
+ i = @target.index(f)
355
+ if i
356
+ @target.delete_at(i).tap do |t|
357
+ keys = ["id"] + t.changes.keys + (f.attribute_names - t.attribute_names)
358
+ t.attributes = f.attributes.except(*keys)
359
+ end
360
+ else
361
+ f
362
+ end
363
+ end + @target
353
364
  else
354
365
  @target = find_target
355
366
  end
@@ -364,6 +375,17 @@ module ActiveRecord
364
375
  end
365
376
 
366
377
  def method_missing(method, *args)
378
+ case method.to_s
379
+ when 'find_or_create'
380
+ return find(:first, :conditions => args.first) || create(args.first)
381
+ when /^find_or_create_by_(.*)$/
382
+ rest = $1
383
+ return send("find_by_#{rest}", *args) ||
384
+ method_missing("create_by_#{rest}", *args)
385
+ when /^create_by_(.*)$/
386
+ return create Hash[$1.split('_and_').zip(args)]
387
+ end
388
+
367
389
  if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
368
390
  if block_given?
369
391
  super { |*block_args| yield(*block_args) }
@@ -411,7 +433,14 @@ module ActiveRecord
411
433
  callback(:before_add, record)
412
434
  yield(record) if block_given?
413
435
  @target ||= [] unless loaded?
414
- @target << record unless @reflection.options[:uniq] && @target.include?(record)
436
+ index = @target.index(record)
437
+ unless @reflection.options[:uniq] && index
438
+ if index
439
+ @target[index] = record
440
+ else
441
+ @target << record
442
+ end
443
+ end
415
444
  callback(:after_add, record)
416
445
  set_inverse_instance(record, @owner)
417
446
  record
@@ -230,10 +230,6 @@ module ActiveRecord
230
230
  # It's also possible to instantiate related objects, so a Client class belonging to the clients
231
231
  # table with a +master_id+ foreign key can instantiate master through Client#master.
232
232
  def method_missing(method_id, *args, &block)
233
- if method_id == :to_ary || method_id == :to_str
234
- raise NoMethodError, "undefined method `#{method_id}' for #{inspect}:#{self.class}"
235
- end
236
-
237
233
  method_name = method_id.to_s
238
234
 
239
235
  if self.class.private_method_defined?(method_name)
@@ -146,12 +146,12 @@ module ActiveRecord
146
146
  # add_autosave_association_callbacks(reflect_on_association(name))
147
147
  # end
148
148
  ASSOCIATION_TYPES.each do |type|
149
- module_eval %{
149
+ module_eval <<-CODE, __FILE__, __LINE__ + 1
150
150
  def #{type}(name, options = {})
151
151
  super
152
152
  add_autosave_association_callbacks(reflect_on_association(name))
153
153
  end
154
- }
154
+ CODE
155
155
  end
156
156
 
157
157
  # Adds a validate and save callback for the association as specified by
@@ -1,5 +1,6 @@
1
1
  require 'yaml'
2
2
  require 'set'
3
+ require 'active_support/core_ext/class/attribute'
3
4
 
4
5
  module ActiveRecord #:nodoc:
5
6
  # Generic Active Record exception class.
@@ -515,7 +516,7 @@ module ActiveRecord #:nodoc:
515
516
  @@timestamped_migrations = true
516
517
 
517
518
  # Determine whether to store the full constant name including namespace when using STI
518
- superclass_delegating_accessor :store_full_sti_class
519
+ class_attribute :store_full_sti_class
519
520
  self.store_full_sti_class = false
520
521
 
521
522
  # Stores the default scope for the class
@@ -935,11 +936,18 @@ module ActiveRecord #:nodoc:
935
936
  def reset_counters(id, *counters)
936
937
  object = find(id)
937
938
  counters.each do |association|
938
- child_class = reflect_on_association(association).klass
939
- counter_name = child_class.reflect_on_association(self.name.downcase.to_sym).counter_cache_column
939
+ child_class = reflect_on_association(association.to_sym).klass
940
+ belongs_name = self.name.demodulize.underscore.to_sym
941
+ counter_name = child_class.reflect_on_association(belongs_name).counter_cache_column
942
+ value = object.send(association).count
940
943
 
941
- connection.update("UPDATE #{quoted_table_name} SET #{connection.quote_column_name(counter_name)} = #{object.send(association).count} WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}", "#{name} UPDATE")
944
+ connection.update(<<-CMD, "#{name} UPDATE")
945
+ UPDATE #{quoted_table_name}
946
+ SET #{connection.quote_column_name(counter_name)} = #{value}
947
+ WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}
948
+ CMD
942
949
  end
950
+ return true
943
951
  end
944
952
 
945
953
  # A generic "counter updater" implementation, intended primarily to be
@@ -972,19 +980,13 @@ module ActiveRecord #:nodoc:
972
980
  # # SET comment_count = comment_count + 1,
973
981
  # # WHERE id IN (10, 15)
974
982
  def update_counters(id, counters)
975
- updates = counters.inject([]) { |list, (counter_name, increment)|
976
- sign = increment < 0 ? "-" : "+"
977
- list << "#{connection.quote_column_name(counter_name)} = COALESCE(#{connection.quote_column_name(counter_name)}, 0) #{sign} #{increment.abs}"
978
- }.join(", ")
979
-
980
- if id.is_a?(Array)
981
- ids_list = id.map {|i| quote_value(i)}.join(', ')
982
- condition = "IN (#{ids_list})"
983
- else
984
- condition = "= #{quote_value(id)}"
983
+ updates = counters.map do |counter_name, value|
984
+ operator = value < 0 ? '-' : '+'
985
+ quoted_column = connection.quote_column_name(counter_name)
986
+ "#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
985
987
  end
986
988
 
987
- update_all(updates, "#{connection.quote_column_name(primary_key)} #{condition}")
989
+ update_all(updates.join(', '), primary_key => id )
988
990
  end
989
991
 
990
992
  # Increment a number field by one, usually representing a count.
@@ -1284,6 +1286,8 @@ module ActiveRecord #:nodoc:
1284
1286
 
1285
1287
  # Turns the +table_name+ back into a class name following the reverse rules of +table_name+.
1286
1288
  def class_name(table_name = table_name) # :nodoc:
1289
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base#class_name is deprecated and will be removed in Rails 2.3.9.", caller)
1290
+
1287
1291
  # remove any prefix and/or suffix from the table name
1288
1292
  class_name = table_name[table_name_prefix.length..-(table_name_suffix.length + 1)].camelize
1289
1293
  class_name = class_name.singularize if pluralize_table_names
@@ -2642,7 +2646,7 @@ module ActiveRecord #:nodoc:
2642
2646
  # Note: The new instance will share a link to the same attributes as the original class. So any change to the attributes in either
2643
2647
  # instance will affect the other.
2644
2648
  def becomes(klass)
2645
- returning klass.new do |became|
2649
+ klass.new.tap do |became|
2646
2650
  became.instance_variable_set("@attributes", @attributes)
2647
2651
  became.instance_variable_set("@attributes_cache", @attributes_cache)
2648
2652
  became.instance_variable_set("@new_record", new_record?)
@@ -2660,12 +2664,20 @@ module ActiveRecord #:nodoc:
2660
2664
  # Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will
2661
2665
  # fail and false will be returned.
2662
2666
  def update_attributes(attributes)
2667
+ with_transaction_returning_status(:update_attributes_inside_transaction, attributes)
2668
+ end
2669
+
2670
+ def update_attributes_inside_transaction(attributes) #:nodoc:
2663
2671
  self.attributes = attributes
2664
2672
  save
2665
2673
  end
2666
2674
 
2667
2675
  # Updates an object just like Base.update_attributes but calls save! instead of save so an exception is raised if the record is invalid.
2668
2676
  def update_attributes!(attributes)
2677
+ with_transaction_returning_status(:update_attributes_inside_transaction!, attributes)
2678
+ end
2679
+
2680
+ def update_attributes_inside_transaction!(attributes) #:nodoc:
2669
2681
  self.attributes = attributes
2670
2682
  save!
2671
2683
  end
@@ -10,7 +10,7 @@ module ActiveRecord
10
10
  ##
11
11
  # :singleton-method:
12
12
  # The connection handler
13
- superclass_delegating_accessor :connection_handler
13
+ class_attribute :connection_handler
14
14
  self.connection_handler = ConnectionAdapters::ConnectionHandler.new
15
15
 
16
16
  # Returns the connection currently associated with the class. This can
@@ -195,6 +195,7 @@ module ActiveRecord
195
195
  # remove_column(:suppliers, :qualification)
196
196
  # remove_columns(:suppliers, :qualification, :experience)
197
197
  def remove_column(table_name, *column_names)
198
+ raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
198
199
  column_names.flatten.each do |column_name|
199
200
  execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
200
201
  end
@@ -211,6 +211,12 @@ module ActiveRecord
211
211
  log_info(sql, name, 0)
212
212
  nil
213
213
  end
214
+ rescue SystemExit, SignalException, NoMemoryError => e
215
+ # Don't re-wrap these exceptions. They are probably not being caused by invalid
216
+ # sql, but rather some external stimulus beyond the responsibilty of this code.
217
+ # Additionaly, wrapping these exceptions with StatementInvalid would lead to
218
+ # meaningful loss of data, such as losing SystemExit#status.
219
+ raise e
214
220
  rescue Exception => e
215
221
  # Log message and raise exception.
216
222
  # Set last_verification to 0, so that connection gets verified
@@ -315,6 +315,7 @@ module ActiveRecord
315
315
  rows = []
316
316
  result.each { |row| rows << row }
317
317
  result.free
318
+ @connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
318
319
  rows
319
320
  end
320
321
 
@@ -638,6 +639,7 @@ module ActiveRecord
638
639
  result = execute(sql, name)
639
640
  rows = result.all_hashes
640
641
  result.free
642
+ @connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
641
643
  rows
642
644
  end
643
645
 
@@ -25,7 +25,7 @@ module ActiveRecord
25
25
  module ConnectionAdapters #:nodoc:
26
26
  class SQLite3Adapter < SQLiteAdapter # :nodoc:
27
27
  def table_structure(table_name)
28
- returning structure = @connection.table_info(quote_table_name(table_name)) do
28
+ @connection.table_info(quote_table_name(table_name)).tap do |structure|
29
29
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
30
30
  end
31
31
  end
@@ -269,6 +269,7 @@ module ActiveRecord
269
269
  end
270
270
 
271
271
  def remove_column(table_name, *column_names) #:nodoc:
272
+ raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
272
273
  column_names.flatten.each do |column_name|
273
274
  alter_table(table_name) do |definition|
274
275
  definition.columns.delete(definition[column_name])
@@ -329,7 +330,7 @@ module ActiveRecord
329
330
  end
330
331
 
331
332
  def table_structure(table_name)
332
- returning structure = execute("PRAGMA table_info(#{quote_table_name(table_name)})") do
333
+ execute("PRAGMA table_info(#{quote_table_name(table_name)})").tap do |structure|
333
334
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
334
335
  end
335
336
  end
@@ -44,7 +44,7 @@ module ActiveRecord
44
44
  base.alias_method_chain :update, :dirty
45
45
  base.alias_method_chain :reload, :dirty
46
46
 
47
- base.superclass_delegating_accessor :partial_updates
47
+ base.class_attribute :partial_updates
48
48
  base.partial_updates = true
49
49
 
50
50
  base.send(:extend, ClassMethods)
@@ -11,23 +11,23 @@ en:
11
11
  accepted: "must be accepted"
12
12
  empty: "can't be empty"
13
13
  blank: "can't be blank"
14
- too_long: "is too long (maximum is {{count}} characters)"
15
- too_short: "is too short (minimum is {{count}} characters)"
16
- wrong_length: "is the wrong length (should be {{count}} characters)"
14
+ too_long: "is too long (maximum is %{count} characters)"
15
+ too_short: "is too short (minimum is %{count} characters)"
16
+ wrong_length: "is the wrong length (should be %{count} characters)"
17
17
  taken: "has already been taken"
18
18
  not_a_number: "is not a number"
19
- greater_than: "must be greater than {{count}}"
20
- greater_than_or_equal_to: "must be greater than or equal to {{count}}"
21
- equal_to: "must be equal to {{count}}"
22
- less_than: "must be less than {{count}}"
23
- less_than_or_equal_to: "must be less than or equal to {{count}}"
19
+ greater_than: "must be greater than %{count}"
20
+ greater_than_or_equal_to: "must be greater than or equal to %{count}"
21
+ equal_to: "must be equal to %{count}"
22
+ less_than: "must be less than %{count}"
23
+ less_than_or_equal_to: "must be less than or equal to %{count}"
24
24
  odd: "must be odd"
25
25
  even: "must be even"
26
- record_invalid: "Validation failed: {{errors}}"
26
+ record_invalid: "Validation failed: %{errors}"
27
27
  # Append your own errors here or at the model/attributes scope.
28
28
 
29
29
  full_messages:
30
- format: "{{attribute}} {{message}}"
30
+ format: "%{attribute} %{message}"
31
31
 
32
32
  # You can define own errors for models or model attributes.
33
33
  # The values :model, :attribute and :value are always available for interpolation.
@@ -35,7 +35,7 @@ en:
35
35
  # For example,
36
36
  # models:
37
37
  # user:
38
- # blank: "This is a custom blank message for {{model}}: {{attribute}}"
38
+ # blank: "This is a custom blank message for %{model}: %{attribute}"
39
39
  # attributes:
40
40
  # login:
41
41
  # blank: "This is a custom blank message for User login"
@@ -128,6 +128,7 @@ module ActiveRecord
128
128
  end
129
129
  end
130
130
 
131
+ @destroyed = true
131
132
  freeze
132
133
  end
133
134
 
@@ -516,7 +516,7 @@ module ActiveRecord
516
516
  raise DuplicateMigrationNameError.new(name.camelize)
517
517
  end
518
518
 
519
- klasses << returning(MigrationProxy.new) do |migration|
519
+ klasses << (MigrationProxy.new).tap do |migration|
520
520
  migration.name = name.camelize
521
521
  migration.version = version
522
522
  migration.filename = file
@@ -8,10 +8,7 @@ module ActiveRecord
8
8
  #
9
9
  # You can define a scope that applies to all finders using ActiveRecord::Base.default_scope.
10
10
  def self.included(base)
11
- base.class_eval do
12
- extend ClassMethods
13
- named_scope :scoped, lambda { |scope| scope }
14
- end
11
+ base.extend ClassMethods
15
12
  end
16
13
 
17
14
  module ClassMethods
@@ -19,6 +16,10 @@ module ActiveRecord
19
16
  read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
20
17
  end
21
18
 
19
+ def scoped(scope, &block)
20
+ Scope.new(self, scope, &block)
21
+ end
22
+
22
23
  # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,
23
24
  # such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>.
24
25
  #
@@ -84,18 +85,22 @@ module ActiveRecord
84
85
  # assert_equal expected_options, Shirt.colored('red').proxy_options
85
86
  def named_scope(name, options = {}, &block)
86
87
  name = name.to_sym
88
+
87
89
  scopes[name] = lambda do |parent_scope, *args|
88
90
  Scope.new(parent_scope, case options
89
91
  when Hash
90
92
  options
91
93
  when Proc
92
- options.call(*args)
94
+ if self.model_name != parent_scope.model_name
95
+ options.bind(parent_scope).call(*args)
96
+ else
97
+ options.call(*args)
98
+ end
93
99
  end, &block)
94
100
  end
95
- (class << self; self end).instance_eval do
96
- define_method name do |*args|
97
- scopes[name].call(self, *args)
98
- end
101
+
102
+ singleton_class.send :define_method, name do |*args|
103
+ scopes[name].call(self, *args)
99
104
  end
100
105
  end
101
106
  end