activerecord-deprecated_finders 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/.travis.yml +8 -0
- data/Gemfile +10 -0
- data/LICENSE +22 -0
- data/README.md +15 -0
- data/Rakefile +28 -0
- data/activerecord-deprecated_finders.gemspec +21 -0
- data/lib/active_record/deprecated_finders.rb +10 -0
- data/lib/active_record/deprecated_finders/association_builder.rb +78 -0
- data/lib/active_record/deprecated_finders/base.rb +151 -0
- data/lib/active_record/deprecated_finders/collection_proxy.rb +32 -0
- data/lib/active_record/deprecated_finders/dynamic_matchers.rb +204 -0
- data/lib/active_record/deprecated_finders/relation.rb +176 -0
- data/lib/active_record/deprecated_finders/version.rb +5 -0
- data/test/associations_test.rb +67 -0
- data/test/calculate_test.rb +15 -0
- data/test/default_scope_test.rb +35 -0
- data/test/dynamic_methods_test.rb +133 -0
- data/test/find_in_batches_test.rb +18 -0
- data/test/finder_options_test.rb +86 -0
- data/test/finder_test.rb +69 -0
- data/test/helper.rb +37 -0
- data/test/scope_test.rb +17 -0
- data/test/scoped_test.rb +20 -0
- data/test/update_all_test.rb +24 -0
- data/test/with_scope_test.rb +36 -0
- metadata +131 -0
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'active_record/relation'
|
2
|
+
require 'active_support/core_ext/module/aliasing'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
class Relation
|
6
|
+
module DeprecatedMethods
|
7
|
+
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset, :extend,
|
8
|
+
:order, :select, :readonly, :group, :having, :from, :lock ]
|
9
|
+
|
10
|
+
# The silence_deprecation arg is for internal use, where we have already output a
|
11
|
+
# deprecation further up the call stack.
|
12
|
+
def apply_finder_options(options, silence_deprecation = false)
|
13
|
+
ActiveSupport::Deprecation.warn("#apply_finder_options is deprecated") unless silence_deprecation
|
14
|
+
|
15
|
+
relation = clone
|
16
|
+
return relation unless options
|
17
|
+
|
18
|
+
options.assert_valid_keys(VALID_FIND_OPTIONS)
|
19
|
+
finders = options.dup
|
20
|
+
finders.delete_if { |key, value| value.nil? && key != :limit }
|
21
|
+
|
22
|
+
((VALID_FIND_OPTIONS - [:conditions, :include, :extend]) & finders.keys).each do |finder|
|
23
|
+
relation = relation.send(finder, finders[finder])
|
24
|
+
end
|
25
|
+
|
26
|
+
relation = relation.where(finders[:conditions]) if options.has_key?(:conditions)
|
27
|
+
relation = relation.includes(finders[:include]) if options.has_key?(:include)
|
28
|
+
relation = relation.extending(finders[:extend]) if options.has_key?(:extend)
|
29
|
+
|
30
|
+
relation
|
31
|
+
end
|
32
|
+
|
33
|
+
def update_all_with_deprecated_options(updates, conditions = nil, options = {})
|
34
|
+
scope = self
|
35
|
+
|
36
|
+
if conditions
|
37
|
+
scope = where(conditions)
|
38
|
+
|
39
|
+
ActiveSupport::Deprecation.warn(
|
40
|
+
"Relation#update_all with conditions is deprecated. Please use " \
|
41
|
+
"Item.where(color: 'red').update_all(...) rather than " \
|
42
|
+
"Item.update_all(..., color: 'red')."
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
if options.present?
|
47
|
+
scope = scope.apply_finder_options(options.slice(:limit, :order), true)
|
48
|
+
|
49
|
+
ActiveSupport::Deprecation.warn(
|
50
|
+
"Relation#update_all with :limit / :order options is deprecated. " \
|
51
|
+
"Please use e.g. Post.limit(1).order(:foo).update_all instead."
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
scope.update_all_without_deprecated_options(updates)
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_in_batches(options = {}, &block)
|
59
|
+
if (finder_options = options.except(:start, :batch_size)).present?
|
60
|
+
ActiveSupport::Deprecation.warn(
|
61
|
+
"Relation#find_in_batches with finder options is deprecated. Please build " \
|
62
|
+
"a scope and then call find_in_batches on it instead."
|
63
|
+
)
|
64
|
+
|
65
|
+
raise "You can't specify an order, it's forced to be #{batch_order}" if options[:order].present?
|
66
|
+
raise "You can't specify a limit, it's forced to be the batch_size" if options[:limit].present?
|
67
|
+
|
68
|
+
apply_finder_options(finder_options, true).
|
69
|
+
find_in_batches(options.slice(:start, :batch_size), &block)
|
70
|
+
else
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def calculate(operation, column_name, options = {})
|
76
|
+
if options.except(:distinct).present?
|
77
|
+
ActiveSupport::Deprecation.warn(
|
78
|
+
"Relation#calculate with finder options is deprecated. Please build " \
|
79
|
+
"a scope and then call find_in_batches on it instead."
|
80
|
+
)
|
81
|
+
|
82
|
+
apply_finder_options(options.except(:distinct), true)
|
83
|
+
.calculate(operation, column_name, :distinct => options[:distinct])
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def find(*args)
|
90
|
+
options = args.extract_options!
|
91
|
+
|
92
|
+
if options.present?
|
93
|
+
scope = apply_finder_options(options, true)
|
94
|
+
|
95
|
+
case finder = args.first
|
96
|
+
when :first, :last, :all
|
97
|
+
ActiveSupport::Deprecation.warn(
|
98
|
+
"Calling #find(#{finder.inspect}) is deprecated. Please call " \
|
99
|
+
"##{finder} directly instead. You have also used finder options. " \
|
100
|
+
"These are also deprecated. Please build a scope instead of using " \
|
101
|
+
"finder options."
|
102
|
+
)
|
103
|
+
|
104
|
+
scope.send(finder)
|
105
|
+
else
|
106
|
+
ActiveSupport::Deprecation.warn(
|
107
|
+
"Passing options to #find is deprecated. Please build a scope " \
|
108
|
+
"and then call #find on it."
|
109
|
+
)
|
110
|
+
|
111
|
+
scope.find(*args)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
case finder = args.first
|
115
|
+
when :first, :last, :all
|
116
|
+
ActiveSupport::Deprecation.warn(
|
117
|
+
"Calling #find(#{finder.inspect}) is deprecated. Please call " \
|
118
|
+
"##{finder} directly instead."
|
119
|
+
)
|
120
|
+
|
121
|
+
send(finder)
|
122
|
+
else
|
123
|
+
super
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def first(*args)
|
129
|
+
if args.empty?
|
130
|
+
super
|
131
|
+
else
|
132
|
+
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
|
133
|
+
super
|
134
|
+
else
|
135
|
+
ActiveSupport::Deprecation.warn(
|
136
|
+
"Relation#first with finder options is deprecated. Please build " \
|
137
|
+
"a scope and then call #first on it instead."
|
138
|
+
)
|
139
|
+
|
140
|
+
apply_finder_options(args.first, true).first
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def last(*args)
|
146
|
+
if args.empty?
|
147
|
+
super
|
148
|
+
else
|
149
|
+
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
|
150
|
+
super
|
151
|
+
else
|
152
|
+
ActiveSupport::Deprecation.warn(
|
153
|
+
"Relation#last with finder options is deprecated. Please build " \
|
154
|
+
"a scope and then call #last on it instead."
|
155
|
+
)
|
156
|
+
|
157
|
+
apply_finder_options(args.first, true).last
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def all(*args)
|
163
|
+
ActiveSupport::Deprecation.warn(
|
164
|
+
"Relation#all is deprecated. If you want to eager-load a relation, you can " \
|
165
|
+
"call #load (e.g. `Post.where(published: true).load`). If you want " \
|
166
|
+
"to get an array of records from a relation, you can call #to_a (e.g. " \
|
167
|
+
"`Post.where(published: true).to_a`)."
|
168
|
+
)
|
169
|
+
apply_finder_options(args.first, true).to_a
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
include DeprecatedMethods
|
174
|
+
alias_method_chain :update_all, :deprecated_options
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe 'associations' do
|
4
|
+
before do
|
5
|
+
@klass = Class.new(ActiveRecord::Base)
|
6
|
+
def @klass.name; 'Post'; end
|
7
|
+
@klass.table_name = 'posts'
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'translates hash scope options into scopes' do
|
11
|
+
extension = Module.new
|
12
|
+
|
13
|
+
assert_deprecated do
|
14
|
+
@klass.has_many :comments, readonly: 'a', order: 'b', limit: 'c', group: 'd', having: 'e',
|
15
|
+
offset: 'f', select: 'g', uniq: 'h', include: 'i', conditions: 'j',
|
16
|
+
extend: extension
|
17
|
+
end
|
18
|
+
|
19
|
+
scope = @klass.new.comments
|
20
|
+
|
21
|
+
scope.readonly_value.must_equal 'a'
|
22
|
+
scope.order_values.must_equal ['b']
|
23
|
+
scope.limit_value.must_equal 'c'
|
24
|
+
scope.group_values.must_equal ['d']
|
25
|
+
scope.having_values.must_equal ['e']
|
26
|
+
scope.offset_value.must_equal 'f'
|
27
|
+
scope.select_values.must_equal ['g']
|
28
|
+
scope.uniq_value.must_equal 'h'
|
29
|
+
scope.includes_values.must_equal ['i']
|
30
|
+
scope.where_values.must_include 'j'
|
31
|
+
scope.extensions.must_equal [extension]
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'supports proc where values' do
|
35
|
+
ActiveSupport::Deprecation.silence do
|
36
|
+
@klass.has_many :comments, conditions: proc { 'omg' }
|
37
|
+
end
|
38
|
+
@klass.new.comments.where_values.must_include 'omg'
|
39
|
+
@klass.joins(:comments).to_sql.must_include 'omg'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'supports proc where values which access the owner' do
|
43
|
+
ActiveSupport::Deprecation.silence do
|
44
|
+
@klass.has_many :comments, conditions: proc { title }
|
45
|
+
end
|
46
|
+
@klass.new(title: 'omg').comments.where_values.must_include 'omg'
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'allows an extend option plus a block extension' do
|
50
|
+
mod = Module.new { def foo; 'foo'; end }
|
51
|
+
ActiveSupport::Deprecation.silence do
|
52
|
+
@klass.has_many(:comments, extend: mod) { def bar; 'bar'; end }
|
53
|
+
end
|
54
|
+
|
55
|
+
obj = @klass.new
|
56
|
+
obj.comments.foo.must_equal 'foo'
|
57
|
+
obj.comments.bar.must_equal 'bar'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "allows a declaration with a scope with no options" do
|
61
|
+
ActiveSupport::Deprecation.silence do
|
62
|
+
@klass.has_many :comments, -> { limit 5 }
|
63
|
+
end
|
64
|
+
scope = @klass.new.comments
|
65
|
+
scope.limit_value.must_equal 5
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe 'calculate' do
|
4
|
+
after do
|
5
|
+
Post.destroy_all
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'supports finder options' do
|
9
|
+
Post.create id: 1
|
10
|
+
Post.create id: 2, title: 'foo'
|
11
|
+
Post.create id: 3, title: 'foo'
|
12
|
+
|
13
|
+
assert_deprecated { Post.calculate(:sum, :id, conditions: { title: 'foo' }) }.must_equal 5
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe 'default scope' do
|
4
|
+
before do
|
5
|
+
Post.create(id: 1, title: 'foo lol')
|
6
|
+
Post.create(id: 2, title: 'foo omg')
|
7
|
+
Post.create(id: 3)
|
8
|
+
|
9
|
+
@klass = Class.new(Post)
|
10
|
+
@klass.table_name = 'posts'
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
Post.delete_all
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'works with a finder hash' do
|
18
|
+
assert_deprecated { @klass.default_scope conditions: { id: 1 } }
|
19
|
+
@klass.all.map(&:id).must_equal [1]
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'works with a finder hash and a scope' do
|
23
|
+
@klass.default_scope { @klass.where("title like '%foo%'") }
|
24
|
+
ActiveSupport::Deprecation.silence do
|
25
|
+
@klass.default_scope conditions: "title like '%omg%'"
|
26
|
+
end
|
27
|
+
|
28
|
+
@klass.all.map(&:id).must_equal [2]
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'works with a block that returns a hash' do
|
32
|
+
@klass.default_scope { { conditions: { id: 1 } } }
|
33
|
+
assert_deprecated { @klass.all.to_a }.map(&:id).must_equal [1]
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe 'dynamic_methods' do
|
4
|
+
before do
|
5
|
+
@posts = [
|
6
|
+
Post.create(title: 'foo', category: '1'),
|
7
|
+
Post.create(title: 'bar', category: '1'),
|
8
|
+
Post.create(title: 'bar', category: '2')
|
9
|
+
]
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
Post.delete_all
|
14
|
+
Comment.delete_all
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'supports find_all_by' do
|
18
|
+
assert_deprecated do
|
19
|
+
Post.find_all_by_title('bar').must_equal [@posts[1], @posts[2]]
|
20
|
+
Post.find_all_by_title_and_category('bar', '2').must_equal [@posts[2]]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'supports find_all_by with finder options' do
|
25
|
+
assert_deprecated do
|
26
|
+
Post.find_all_by_title('bar', conditions: { category: '1' }).must_equal [@posts[1]]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'supports find_last_by' do
|
31
|
+
assert_deprecated do
|
32
|
+
Post.find_last_by_title('foo').must_equal @posts[0]
|
33
|
+
Post.find_last_by_title('bar').must_equal @posts[2]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'supports find_last_by with finder options' do
|
38
|
+
assert_deprecated do
|
39
|
+
Post.find_last_by_title('bar', conditions: { category: '1' }).must_equal @posts[1]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'supports scoped_by' do
|
44
|
+
scope = assert_deprecated { Post.scoped_by_title('bar') }
|
45
|
+
scope.is_a?(ActiveRecord::Relation).must_equal true
|
46
|
+
scope.to_a.must_equal [@posts[1], @posts[2]]
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'supports find_or_initialize_by' do
|
50
|
+
assert_deprecated { Post.find_or_initialize_by_title_and_category('bar', '1').must_equal @posts[1] }
|
51
|
+
|
52
|
+
post = assert_deprecated { Post.find_or_initialize_by_title_and_category('bar', '3') }
|
53
|
+
post.new_record?.must_equal true
|
54
|
+
post.title.must_equal 'bar'
|
55
|
+
post.category.must_equal '3'
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'supports find_or_create_by' do
|
59
|
+
assert_deprecated { Post.find_or_create_by_title_and_category('bar', '1').must_equal @posts[1] }
|
60
|
+
|
61
|
+
post = assert_deprecated { Post.find_or_create_by_title_and_category('bar', '3') }
|
62
|
+
post.new_record?.must_equal false
|
63
|
+
post.title.must_equal 'bar'
|
64
|
+
post.category.must_equal '3'
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'supports find_or_create_by!' do
|
68
|
+
assert_deprecated { Post.find_or_create_by_title_and_category!('bar', '1').must_equal @posts[1] }
|
69
|
+
|
70
|
+
post = assert_deprecated { Post.find_or_create_by_title_and_category!('bar', '3') }
|
71
|
+
post.new_record?.must_equal false
|
72
|
+
post.title.must_equal 'bar'
|
73
|
+
post.category.must_equal '3'
|
74
|
+
|
75
|
+
klass = Class.new(ActiveRecord::Base)
|
76
|
+
def klass.name; 'Post'; end
|
77
|
+
klass.table_name = 'posts'
|
78
|
+
klass.validates_presence_of :category
|
79
|
+
|
80
|
+
lambda {
|
81
|
+
ActiveSupport::Deprecation.silence { klass.find_or_create_by_title!('z') }
|
82
|
+
}.must_raise ActiveRecord::RecordInvalid
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'supports find_by with finder options' do
|
86
|
+
assert_deprecated do
|
87
|
+
Post.find_by_title('bar', conditions: { category: '2' }).must_equal @posts[2]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'supports find_by! with finder options' do
|
92
|
+
assert_deprecated do
|
93
|
+
Post.find_by_title!('bar', conditions: { category: '2' }).must_equal @posts[2]
|
94
|
+
end
|
95
|
+
|
96
|
+
lambda {
|
97
|
+
assert_deprecated { Post.find_by_title!('bar', conditions: { category: '3' }) }
|
98
|
+
}.must_raise ActiveRecord::RecordNotFound
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'supports find_by with a block' do
|
102
|
+
assert_deprecated do
|
103
|
+
Post.find_by_title('foo') { |r| [r, 'block'] }.must_equal [@posts[0], 'block']
|
104
|
+
Post.find_by_title('baz') { |r| [r, 'block'] }.must_equal nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'supports find_by! with a block' do
|
109
|
+
assert_deprecated do
|
110
|
+
Post.find_by_title!('foo') { |r| [r, 'block'] }.must_equal [@posts[0], 'block']
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'adds to an association when find_or_initialize_by is called' do
|
115
|
+
post = @posts.first
|
116
|
+
comment = ActiveSupport::Deprecation.silence { post.comments.find_or_initialize_by_title('omg') }
|
117
|
+
post.comments.must_equal [comment]
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'adds to an association when find_or_create_by is called' do
|
121
|
+
post = @posts.first
|
122
|
+
post.comments.load_target
|
123
|
+
|
124
|
+
comment = ActiveSupport::Deprecation.silence { post.comments.find_or_create_by_title('omg') }
|
125
|
+
post.comments.must_equal [comment]
|
126
|
+
post.reload.comments.must_equal [comment]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "doesn't mess with method_missing for non-find_or_{initialize|create}_by methods" do
|
130
|
+
post = @posts.first
|
131
|
+
post.comments.lol.must_equal 'lol'
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe 'find_in_batches' do
|
4
|
+
after do
|
5
|
+
Post.destroy_all
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'accepts finder options' do
|
9
|
+
foo = Post.create title: 'foo'
|
10
|
+
Post.create title: 'bar'
|
11
|
+
|
12
|
+
assert_deprecated do
|
13
|
+
Post.find_in_batches(conditions: "title = 'foo'") do |records|
|
14
|
+
records.must_equal [foo]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|