Skip to content

Commit 23ad9ad

Browse files
authored
Merge pull request #186 from kbrock/early_definition
Early includes and arel definition
2 parents a05204f + 476371d commit 23ad9ad

File tree

5 files changed

+16
-46
lines changed

5 files changed

+16
-46
lines changed

lib/active_record/virtual_attributes.rb

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,15 @@ def virtual_column(name, type:, **options)
5656
virtual_attribute(name, type, **options)
5757
end
5858

59-
def virtual_attribute(name, type, **options)
59+
def virtual_attribute(name, type, uses: nil, arel: nil, **options)
6060
name = name.to_s
6161
reload_schema_from_cache
6262

6363
self.virtual_attributes_to_define =
6464
virtual_attributes_to_define.merge(name => [type, options])
65+
66+
define_virtual_include(name, uses)
67+
define_virtual_arel(name, arel)
6568
end
6669

6770
#
@@ -91,20 +94,14 @@ def load_schema!
9194

9295
virtual_attributes_to_define.each do |name, (type, options)|
9396
type = type.call if type.respond_to?(:call)
94-
type = ActiveRecord::Type.lookup(type, **options.except(:uses, :arel)) if type.kind_of?(Symbol)
95-
96-
define_virtual_attribute(name, type, **options.slice(:uses, :arel))
97-
end
97+
type = ActiveRecord::Type.lookup(type, **options) if type.kind_of?(Symbol)
9898

99-
virtual_delegates_to_define.each do |method_name, (method, options)|
100-
define_virtual_delegate(method_name, method, options)
99+
define_virtual_attribute(name, type)
101100
end
102101
end
103102

104-
def define_virtual_attribute(name, cast_type, uses: nil, arel: nil)
103+
def define_virtual_attribute(name, cast_type)
105104
attribute_types[name.to_s] = cast_type
106-
define_virtual_include(name, uses) if uses
107-
define_virtual_arel(name, arel) if arel
108105
end
109106
end
110107
end

lib/active_record/virtual_attributes/virtual_arel.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def arel_for_virtual_attribute(column_name, table) # :nodoc:
111111
private
112112

113113
def define_virtual_arel(name, arel) # :nodoc:
114-
self._virtual_arel = _virtual_arel.merge(name.to_s => arel)
114+
self._virtual_arel = _virtual_arel.merge(name.to_s => arel) unless arel.nil?
115115
end
116116
end
117117
end

lib/active_record/virtual_attributes/virtual_delegates.rb

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,12 @@ module VirtualAttributes
99
module VirtualDelegates
1010
extend ActiveSupport::Concern
1111

12-
included do
13-
class_attribute :virtual_delegates_to_define, :instance_accessor => false, :default => {}
14-
end
15-
1612
module ClassMethods
1713
#
1814
# Definition
1915
#
2016

21-
def virtual_delegate(*methods, to:, type:, prefix: nil, allow_nil: nil, default: nil, **options) # rubocop:disable Naming/MethodParameterName
17+
def virtual_delegate(*methods, to:, type:, prefix: nil, allow_nil: nil, default: nil, uses: nil, **options) # rubocop:disable Naming/MethodParameterName
2218
to = to.to_s
2319
if to.include?(".") && (methods.size > 1 || prefix)
2420
raise ArgumentError, 'Delegation only supports specifying a target method name when defining a single virtual method with no prefix'
@@ -32,38 +28,17 @@ def virtual_delegate(*methods, to:, type:, prefix: nil, allow_nil: nil, default:
3228
# This better supports reloading of the class and changing the definitions
3329
methods.each do |method|
3430
method_name, to, method = determine_method_names(method, to, prefix)
35-
define_delegate(method_name, method, :to => to, :allow_nil => allow_nil, :default => default)
31+
unless (to_ref = reflection_with_virtual(to))
32+
raise ArgumentError, "Delegation needs an association. Association #{to} does not exist"
33+
end
3634

37-
self.virtual_delegates_to_define =
38-
virtual_delegates_to_define.merge(method_name.to_s => [method, options.merge(:to => to, :type => type)])
35+
define_delegate(method_name, method, :to => to, :allow_nil => allow_nil, :default => default)
36+
virtual_attribute(method_name, type, :uses => (uses || to), :arel => virtual_delegate_arel(method, to_ref), **options)
3937
end
4038
end
4139

4240
private
4341

44-
# define virtual_attribute for delegates
45-
#
46-
# this is called at schema load time (and not at class definition time)
47-
#
48-
# @param method_name [Symbol] name of the attribute on the source class to be defined
49-
# @param col [Symbol] name of the attribute on the associated class to be referenced
50-
# @option options :to [Symbol] name of the association from the source class to be referenced
51-
# @option options :arel [Proc] (optional and not common)
52-
# @option options :uses [Array|Symbol|Hash] sql includes hash. (default: to)
53-
# @option options :type [Symbol|ActiveModel::Type::Value] type for the attribute
54-
def define_virtual_delegate(method_name, col, options)
55-
unless (to = options[:to]) && (to_ref = reflection_with_virtual(to.to_s))
56-
raise ArgumentError, 'Delegation needs an association. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
57-
end
58-
59-
col = col.to_s
60-
type = options[:type]
61-
type = ActiveRecord::Type.lookup(type) if type.kind_of?(Symbol)
62-
63-
arel = virtual_delegate_arel(col, to_ref)
64-
define_virtual_attribute(method_name, type, :uses => (options[:uses] || to), :arel => arel)
65-
end
66-
6742
# see activesupport module/delegation.rb
6843
# rubocop:disable Style/TernaryParentheses
6944
def define_delegate(method_name, method, to: nil, allow_nil: nil, default: nil) # rubocop:disable Naming/MethodParameterName

lib/active_record/virtual_attributes/virtual_includes.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def virtual_includes(name)
2525
private
2626

2727
def define_virtual_include(name, uses)
28-
self._virtual_includes = _virtual_includes.merge(name.to_s => uses)
28+
self._virtual_includes = _virtual_includes.merge(name.to_s => uses) unless uses.nil?
2929
end
3030
end
3131
end

spec/virtual_delegates_spec.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,7 @@ def self.connection
241241
end
242242

243243
it "catches invalid references" do
244-
TestOtherClass.virtual_delegate :col4, :to => :others, :type => :integer
245-
246-
expect { model.new }.to raise_error(NameError)
244+
expect { TestOtherClass.virtual_delegate :col4, :to => :others, :type => :integer }.to raise_error(ArgumentError)
247245
end
248246

249247
it "catches invalid column" do

0 commit comments

Comments
 (0)