Skip to content

Commit ea2d98d

Browse files
committed
Deprecate message when virtual_delegate is not passed type
1 parent e620c9e commit ea2d98d

File tree

6 files changed

+48
-28
lines changed

6 files changed

+48
-28
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ The versioning of this gem follows ActiveRecord versioning, and does not follow
44

55
## [Unreleased]
66

7+
## [7.1.1] - 2025-06-18
8+
9+
* Deprecate virtual_delegate without a type [#188](https://github.com/ManageIQ/activerecord-virtual_attributes/pull/188)
10+
711
## [7.1.0] - 2025-02-19
812

913
* Use TableAlias for table aliasing [#168](https://github.com/ManageIQ/activerecord-virtual_attributes/pull/168)
@@ -111,7 +115,8 @@ The versioning of this gem follows ActiveRecord versioning, and does not follow
111115
* Initial Release
112116
* Extracted from ManageIQ/manageiq
113117

114-
[Unreleased]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v7.1.0...HEAD
118+
[Unreleased]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v7.1.1...HEAD
119+
[7.1.1]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v7.1.0...v7.1.1
115120
[7.1.0]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v7.0.0...v7.1.0
116121
[7.0.0]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v6.1.2...v7.0.0
117122
[6.1.2]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v6.1.1...v6.1.2

lib/active_record/virtual_attributes.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require "active_support/concern"
22
require "active_record"
33

4+
require "active_record/virtual_attributes/version"
45
require "active_record/virtual_attributes/virtual_includes"
56
require "active_record/virtual_attributes/virtual_arel"
67
require "active_record/virtual_attributes/virtual_delegates"
@@ -37,6 +38,10 @@ def type
3738
ActiveRecord::Type.register(:string_set, Type::StringSet)
3839
ActiveRecord::Type.register(:symbol, Type::Symbol)
3940

41+
def self.deprecator
42+
@deprecator ||= ActiveSupport::Deprecation.new(ActiveRecord::VirtualAttributes::VERSION, "virtual_attributes")
43+
end
44+
4045
included do
4146
class_attribute :virtual_attributes_to_define, :instance_accessor => false, :default => {}
4247
end
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module ActiveRecord
22
module VirtualAttributes
3-
VERSION = "7.1.0".freeze
3+
VERSION = "7.1.1".freeze
44
end
55
end

lib/active_record/virtual_attributes/virtual_delegates.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ def virtual_delegate(*methods)
2424
raise ArgumentError, 'Delegation needs an association. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
2525
end
2626

27+
unless options[:type]
28+
ActiveRecord::VirtualAttributes.deprecator.warn("Calling virtual_delegate without :type is now deprecated", caller)
29+
end
30+
2731
to = to.to_s
2832
if to.include?(".") && methods.size > 1
2933
raise ArgumentError, 'Delegation only supports specifying a method name when defining a single virtual method'

spec/virtual_attributes_spec.rb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ def col2
482482
end
483483

484484
it "supports delegates" do
485-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1
485+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :type => :integer
486486

487487
expect(TestClass.attribute_supported_by_sql?(:parent_col1)).to be_truthy
488488
end
@@ -530,7 +530,7 @@ def col2
530530
end
531531

532532
it "supports delegates" do
533-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1
533+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :type => :integer
534534

535535
expect(TestClass.attribute_supported_by_sql?(:parent_col1)).to be_truthy
536536
end
@@ -598,42 +598,42 @@ def self.connection
598598
let(:parent) { TestClass.create(:col1 => 4) }
599599

600600
it "delegates to child" do
601-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1
601+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :type => :integer
602602
tc = TestClass.new(:ref1 => parent)
603603
expect(tc.parent_col1).to eq(4)
604604
end
605605

606606
it "delegates to nil child" do
607-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true
607+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true, :type => :integer
608608
tc = TestClass.new
609609
expect(tc.parent_col1).to be_nil
610610
end
611611

612612
it "defines virtual attribute" do
613-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1
613+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :type => :integer
614614
expect(TestClass.virtual_attribute_names).to include("parent_col1")
615615
end
616616

617617
it "defines with a new name" do
618-
TestClass.virtual_delegate 'funky_name', :to => "ref1.col1"
618+
TestClass.virtual_delegate 'funky_name', :to => "ref1.col1", :type => :integer
619619
tc = TestClass.new(:ref1 => parent)
620620
expect(tc.funky_name).to eq(4)
621621
end
622622

623623
it "defaults for to nil child (array)" do
624-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true, :default => []
624+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true, :default => [], :type => :integer
625625
tc = TestClass.new
626626
expect(tc.parent_col1).to eq([])
627627
end
628628

629629
it "defaults for to nil child (integer)" do
630-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true, :default => 0
630+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true, :default => 0, :type => :integer
631631
tc = TestClass.new
632632
expect(tc.parent_col1).to eq(0)
633633
end
634634

635635
it "defaults for to nil child (string)" do
636-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true, :default => "def"
636+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true, :default => "def", :type => :integer
637637
tc = TestClass.new
638638
expect(tc.parent_col1).to eq("def")
639639
end

spec/virtual_delegates_spec.rb

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,24 @@
33
let(:parent) { TestClass.create(:col1 => 4) }
44

55
it "delegates to parent" do
6-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1
6+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :type => :integer
77
tc = TestClass.new(:ref1 => parent)
88
expect(tc.parent_col1).to eq(4)
99
end
1010

1111
it "delegates to nil parent" do
12-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true
12+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :allow_nil => true, :type => :integer
1313
tc = TestClass.new
1414
expect(tc.parent_col1).to be_nil
1515
end
1616

1717
it "defines parent virtual attribute" do
18-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1
18+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :type => :integer
1919
expect(TestClass.virtual_attribute_names).to include("parent_col1")
2020
end
2121

2222
it "delegates to parent (sql)" do
23-
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1
23+
TestClass.virtual_delegate :col1, :prefix => 'parent', :to => :ref1, :type => :integer
2424
TestClass.create(:ref1 => parent)
2525
tcs = TestClass.select(:id, :col1, TestClass.arel_table[:parent_col1].as("x"))
2626
expect(tcs.map(&:x)).to match_array([nil, 4])
@@ -44,21 +44,27 @@
4444
end.to raise_error(ArgumentError, /needs an association/)
4545
end
4646

47+
it "expects a ':type' for delegation" do
48+
expect(ActiveRecord::VirtualAttributes.deprecator).to receive(:warn).with(/type/, anything())
49+
TestClass.virtual_delegate :col1, :to => :ref1
50+
TestClass.new
51+
end
52+
4753
it "only allows 1 method when delegating to a specific method" do
4854
expect do
49-
TestClass.virtual_delegate :col1, :col2, :to => "ref1.method"
55+
TestClass.virtual_delegate :col1, :col2, :to => "ref1.method", :type => :string
5056
end.to raise_error(ArgumentError, /single virtual method/)
5157
end
5258

5359
it "only allows 1 level deep delegation" do
5460
expect do
55-
TestClass.virtual_delegate :col1, :to => "ref1.method.method2"
61+
TestClass.virtual_delegate :col1, :to => "ref1.method.method2", :type => :string
5662
end.to raise_error(ArgumentError, /single association/)
5763
end
5864

5965
it "detects invalid destination" do
6066
expect do
61-
TestClass.virtual_delegate :col1, :to => "bogus_ref.method"
67+
TestClass.virtual_delegate :col1, :to => "bogus_ref.method", :type => :string
6268
TestClass.new
6369
end.to raise_error(ArgumentError, /needs an association/)
6470
end
@@ -72,24 +78,24 @@
7278
let(:child) { TestClass.create }
7379

7480
it "delegates to child" do
75-
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2
81+
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2, :type => :integer
7682
tc = TestClass.create(:ref2 => child)
7783
expect(tc.child_col1).to eq(tc.id)
7884
end
7985

8086
it "delegates to nil child" do
81-
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2, :allow_nil => true
87+
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2, :allow_nil => true, :type => :integer
8288
tc = TestClass.new
8389
expect(tc.child_col1).to be_nil
8490
end
8591

8692
it "defines child virtual attribute" do
87-
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2
93+
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2, :type => :integer
8894
expect(TestClass.virtual_attribute_names).to include("child_col1")
8995
end
9096

9197
it "delegates to child (sql)" do
92-
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2
98+
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2, :type => :integer
9399
tc = TestClass.create(:ref2 => child)
94100
tcs = TestClass.select(:id, :col1, :child_col1).to_a
95101
expect { expect(tcs.map(&:child_col1)).to match_array([nil, tc.id]) }.to_not make_database_queries
@@ -98,7 +104,7 @@
98104
# this may fail in the future as our way of building queries may change
99105
# just want to make sure it changed due to intentional changes
100106
it "uses table alias for subquery" do
101-
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2
107+
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2, :type => :integer
102108
sql = TestClass.select(:id, :col1, :child_col1).to_sql
103109
expect(sql).to match(/["`]test_classes_[^"`]*["`][.]["`]col1["`]/i)
104110
end
@@ -114,7 +120,7 @@
114120
# ensure virtual attribute referencing a relation with a select()
115121
# does not throw an exception due to multi-column select
116122
it "properly generates sub select" do
117-
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2
123+
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2, :type => :integer
118124
TestClass.create(:ref2 => child)
119125
expect { TestClass.select(:id, :child_col1).to_a }.to_not raise_error
120126
end
@@ -131,7 +137,7 @@
131137
# ensure virtual attribute referencing a relation with a select()
132138
# does not throw an exception due to multi-column select
133139
it "properly generates sub select" do
134-
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2
140+
TestClass.virtual_delegate :col1, :prefix => 'child', :to => :ref2, :type => :integer
135141
TestClass.create(:ref2 => child)
136142
expect { TestClass.select(:id, :child_col1).to_a }.to_not raise_error
137143
end
@@ -150,7 +156,7 @@ def self.connection
150156
end
151157
# TODO: -> { order(:col1) }
152158
TestClass.has_one :child, :class_name => 'TestOtherClass', :foreign_key => :ocol1
153-
TestClass.virtual_delegate :child_str, :to => "child.ostr"
159+
TestClass.virtual_delegate :child_str, :to => "child.ostr", :type => :string
154160
end
155161

156162
after do
@@ -185,7 +191,7 @@ def self.connection
185191
end
186192

187193
it "delegates to another table" do
188-
TestOtherClass.virtual_delegate :col1, :to => :oref1
194+
TestOtherClass.virtual_delegate :col1, :to => :oref1, :type => :integer
189195
TestOtherClass.create(:oref1 => TestClass.create)
190196
TestOtherClass.create(:oref1 => TestClass.create(:col1 => 99))
191197
tcs = TestOtherClass.select(:id, :ocol1, TestOtherClass.arel_table[:col1].as("x"))
@@ -198,7 +204,7 @@ def self.connection
198204
# this may fail in the future as our way of building queries may change
199205
# just want to make sure it changed due to intentional changes
200206
it "delegates to another table without alias" do
201-
TestOtherClass.virtual_delegate :col1, :to => :oref1
207+
TestOtherClass.virtual_delegate :col1, :to => :oref1, :type => :integer
202208
sql = TestOtherClass.select(:id, :ocol1, TestOtherClass.arel_table[:col1].as("x")).to_sql
203209
expect(sql).to match(/["`]test_classes["`].["`]col1["`]/i)
204210
end

0 commit comments

Comments
 (0)