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.
- data/CHANGELOG +1 -4
- data/Rakefile +1 -1
- data/examples/performance.rb +2 -0
- data/lib/active_record/association_preload.rb +12 -2
- data/lib/active_record/associations.rb +1 -1
- data/lib/active_record/associations/association_collection.rb +33 -4
- data/lib/active_record/attribute_methods.rb +0 -4
- data/lib/active_record/autosave_association.rb +2 -2
- data/lib/active_record/base.rb +28 -16
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +6 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +2 -1
- data/lib/active_record/dirty.rb +1 -1
- data/lib/active_record/locale/en.yml +11 -11
- data/lib/active_record/locking/optimistic.rb +1 -0
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/named_scope.rb +14 -9
- data/lib/active_record/nested_attributes.rb +11 -8
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/session_store.rb +9 -1
- data/lib/active_record/validations.rb +12 -12
- data/lib/active_record/version.rb +1 -1
- data/test/cases/adapter_test.rb +7 -8
- data/test/cases/associations/eager_load_nested_include_test.rb +7 -7
- data/test/cases/associations/eager_load_nested_polymorphic_include.rb +19 -0
- data/test/cases/associations/eager_test.rb +7 -0
- data/test/cases/associations/has_many_associations_test.rb +68 -3
- data/test/cases/associations_test.rb +29 -0
- data/test/cases/base_test.rb +35 -75
- data/test/cases/connection_test_mysql.rb +1 -0
- data/test/cases/counter_cache_test.rb +84 -0
- data/test/cases/locking_test.rb +2 -1
- data/test/cases/migration_test.rb +4 -0
- data/test/cases/named_scope_test.rb +6 -1
- data/test/cases/nested_attributes_test.rb +49 -14
- data/test/cases/reflection_test.rb +5 -5
- data/test/cases/sp_test_mysql.rb +16 -0
- data/test/cases/transactions_test.rb +22 -1
- data/test/cases/validations_i18n_test.rb +12 -12
- data/test/cases/validations_test.rb +42 -30
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/fixtures/polymorphic_designs.yml +19 -0
- data/test/fixtures/polymorphic_prices.yml +19 -0
- data/test/fixtures/tees.yml +4 -0
- data/test/fixtures/ties.yml +4 -0
- data/test/models/author.rb +2 -0
- data/test/models/event_author.rb +3 -0
- data/test/models/pirate.rb +2 -2
- data/test/models/polymorphic_design.rb +3 -0
- data/test/models/polymorphic_price.rb +3 -0
- data/test/models/post.rb +2 -0
- data/test/models/tee.rb +4 -0
- data/test/models/tie.rb +4 -0
- data/test/schema/mysql_specific_schema.rb +7 -0
- data/test/schema/schema.rb +16 -0
- metadata +24 -13
- data/examples/performance.sql +0 -85
- data/test/cases/encoding_test.rb +0 -6
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
data/CHANGELOG
CHANGED
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.
|
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"
|
data/examples/performance.rb
CHANGED
@@ -282,7 +282,11 @@ module ActiveRecord
|
|
282
282
|
end
|
283
283
|
through_records.flatten!
|
284
284
|
else
|
285
|
-
|
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
|
-
|
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)}"
|
@@ -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
|
-
|
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
|
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
|
-
|
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
|
data/lib/active_record/base.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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(
|
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.
|
976
|
-
|
977
|
-
|
978
|
-
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/active_record/dirty.rb
CHANGED
@@ -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.
|
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 {
|
15
|
-
too_short: "is too short (minimum is {
|
16
|
-
wrong_length: "is the wrong length (should be {
|
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 {
|
20
|
-
greater_than_or_equal_to: "must be greater than or equal to {
|
21
|
-
equal_to: "must be equal to {
|
22
|
-
less_than: "must be less than {
|
23
|
-
less_than_or_equal_to: "must be less than or equal to {
|
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: {
|
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: "{
|
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 {
|
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"
|
@@ -516,7 +516,7 @@ module ActiveRecord
|
|
516
516
|
raise DuplicateMigrationNameError.new(name.camelize)
|
517
517
|
end
|
518
518
|
|
519
|
-
klasses <<
|
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.
|
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
|
-
|
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
|
-
|
96
|
-
|
97
|
-
|
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
|