activerecord_where_assoc 1.1.0 → 1.1.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/EXAMPLES.md +4 -3
- data/README.md +36 -11
- data/lib/active_record_where_assoc/active_record_compat.rb +11 -1
- data/lib/active_record_where_assoc/core_logic.rb +40 -21
- data/lib/active_record_where_assoc/relation_returning_methods.rb +9 -5
- data/lib/active_record_where_assoc/version.rb +1 -1
- metadata +3 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd0fae20ed7a2ae8fac19fda0df7f70b9b6a842a6519684c66c571dbf2f57732
|
4
|
+
data.tar.gz: f570a564494a52517dde7aad62c79b571ab3d1e49d651f32ac2bb86b301fa4f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 240832561dd8eb5cc93ff3ebc239a0aedf8f9f79520a6404ffe6ac8f9d1b2cacd5f0057d85066ed889b62f16b5e85125acb8b943c91fa72ab0450a366d7d7569
|
7
|
+
data.tar.gz: 060f842df0bd69b72ac0e6f0a64ef222b347047d693046abe83a9bfdd6797109e202bcccc32f75a3e7bc4349f1b5a50c94982102571a699b113e65331ebca459
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 1.1.3 - 2022-08-16
|
4
|
+
|
5
|
+
* Add support for associations defined on abstract models
|
6
|
+
|
7
|
+
# 1.1.2 - 2020-12-24
|
8
|
+
|
9
|
+
* Add compatiblity for Rails 6.1
|
10
|
+
|
11
|
+
# 1.1.1 - 2020-04-13
|
12
|
+
|
13
|
+
* Fix handling for ActiveRecord's NullRelation (MyModel.none) in block and association's conditions.
|
14
|
+
|
3
15
|
# 1.1.0 - 2020-02-24
|
4
16
|
|
5
17
|
* Added methods which return the SQL used by this gem: `assoc_exists_sql`, `assoc_not_exists_sql`, `compare_assoc_count_sql`, `only_assoc_count_sql`
|
data/EXAMPLES.md
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
SELECT "users".* FROM "users"
|
1
2
|
Here are some example usages of the gem, along with the generated SQL.
|
2
3
|
|
3
4
|
Each of those methods can be chained with scoping methods, so they can be used on `Post`, `my_user.posts`, `Post.where('hello')` or inside a scope. Note that for the `*_sql` variants, those should preferably be used on classes only, because otherwise, it could be confusing for a reader.
|
@@ -107,13 +108,13 @@ User.where_assoc_exists(:posts).or(User.where_assoc_exists(:comments))
|
|
107
108
|
```
|
108
109
|
```sql
|
109
110
|
SELECT "users".* FROM "users"
|
110
|
-
WHERE (
|
111
|
+
WHERE (EXISTS (
|
111
112
|
SELECT 1 FROM "posts"
|
112
113
|
WHERE "posts"."author_id" = "users"."id"
|
113
|
-
)
|
114
|
+
) OR EXISTS (
|
114
115
|
SELECT 1 FROM "comments"
|
115
116
|
WHERE "comments"."author_id" = "users"."id"
|
116
|
-
))
|
117
|
+
))
|
117
118
|
```
|
118
119
|
|
119
120
|
---
|
data/README.md
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
# ActiveRecord Where Assoc
|
2
2
|
|
3
|
-
|
4
|
-
[](https://coveralls.io/github/MaxLap/activerecord_where_assoc)
|
3
|
+

|
5
4
|
[](https://codeclimate.com/github/MaxLap/activerecord_where_assoc)
|
6
|
-
[](https://codeclimate.com/github/MaxLap/activerecord_where_assoc)
|
7
5
|
|
8
6
|
This gem makes it easy to do conditions based on the associations of your records in ActiveRecord (Rails). (Using SQL's `EXISTS` operator)
|
9
7
|
|
10
8
|
```ruby
|
11
9
|
# Find my_post's comments that were not made by an admin
|
12
10
|
my_post.comments.where_assoc_not_exists(:author, is_admin: true).where(...)
|
13
|
-
|
11
|
+
|
14
12
|
# Find every posts that have comments by an admin
|
15
13
|
Post.where_assoc_exists([:comments, :author], &:admins).where(...)
|
16
|
-
|
14
|
+
|
17
15
|
# Find my_user's posts that have at least 5 non-spam comments (not_spam is a scope on comments)
|
18
16
|
my_user.posts.where_assoc_count(5, :>=, :comments) { |comments| comments.not_spam }.where(...)
|
19
17
|
```
|
@@ -39,9 +37,8 @@ These methods have many advantages over the alternative ways of achieving the si
|
|
39
37
|
|
40
38
|
## Installation
|
41
39
|
|
42
|
-
Rails 4.1 to
|
43
|
-
|
44
|
-
The gem only depends on the `activerecord` gem.
|
40
|
+
Rails 4.1 to 7.0 are supported with Ruby 2.1 to 3.1. Tested against SQLite3, PostgreSQL and MySQL. The gem
|
41
|
+
only depends on the `activerecord` gem.
|
45
42
|
|
46
43
|
Add this line to your application's Gemfile:
|
47
44
|
|
@@ -53,7 +50,7 @@ And then execute:
|
|
53
50
|
|
54
51
|
$ bundle install
|
55
52
|
|
56
|
-
Or install it yourself
|
53
|
+
Or install it yourself with:
|
57
54
|
|
58
55
|
$ gem install activerecord_where_assoc
|
59
56
|
|
@@ -83,8 +80,8 @@ where_assoc_not_exists(association_name, conditions, options, &block)
|
|
83
80
|
where_assoc_count(left_operand, operator, association_name, conditions, options, &block)
|
84
81
|
```
|
85
82
|
|
86
|
-
* These methods add a condition (a `#where`)
|
87
|
-
* You can specify condition on the association, so you could check only comments that are made by an admin.
|
83
|
+
* These methods add a condition (a `#where`) that checks if the association exists (or not)
|
84
|
+
* You can specify condition on the association, so you could check only for comments that are made by an admin.
|
88
85
|
* Each method returns a new relation, meaning you can chain `#where`, `#order`, `limit`, etc.
|
89
86
|
* common arguments:
|
90
87
|
* association_name: the association we are doing the condition on.
|
@@ -120,6 +117,21 @@ where_assoc_count(left_operand, operator, association_name, conditions, options,
|
|
120
117
|
supports infinite ranges and exclusive end
|
121
118
|
* operator: one of `:<`, `:<=`, `:==`, `:!=`, `:>=`, `:>`
|
122
119
|
|
120
|
+
## Intuition
|
121
|
+
|
122
|
+
Here is the basic intuition for the methods:
|
123
|
+
|
124
|
+
`#where_assoc_exists` filters the models, returning those *where* a record for the *association* matching a condition (by default any record in the association) *exists*.
|
125
|
+
|
126
|
+
`#where_assoc_not_exists` is the exact opposite of `#where_assoc_exists`. Filters the models, returning those *where* a record for the *association* matching a condition (by default any record in the association) do *not exists*
|
127
|
+
|
128
|
+
`#where_assoc_count` the more specific version of `#where_assoc_exists`. Filters the models, returning those *where* a record for the *association* matching a condition (by default any record in the association) do *not exists*
|
129
|
+
|
130
|
+
The condition that you may need on the record can be quite complicated. For this reason, you can pass a block to these methods.
|
131
|
+
The block will receive a relation on records of the association. Your job is then to call `where` and scopes to specify what you want to exist (or to not exist if using `#where_assoc_not_exists`).
|
132
|
+
|
133
|
+
So if you have `User.where_assoc_exists(:comments) {|rel| rel.where("content ilike '%github.com%'") }`, `rel` is a relation is on `Comment`, and you are specifying what you want to exist. So now we are looking for users that made a comment containing 'github.com'.
|
134
|
+
|
123
135
|
## Usage tips
|
124
136
|
|
125
137
|
### Nested associations
|
@@ -222,6 +234,19 @@ It is pretty complicated to support `#limit` and `#offset` of the `has_* :throug
|
|
222
234
|
|
223
235
|
Note that the support of `#limit` and `#offset` for the `:source` and `:through` parts is a feature. I consider `ActiveRecord` wrong for not handling them correctly.
|
224
236
|
|
237
|
+
## Another recommended gem
|
238
|
+
|
239
|
+
If you feel a need for this gem's feature, you may also be interested in another gem I made: [activerecord_follow_assoc](https://github.com/MaxLap/activerecord_follow_assoc).
|
240
|
+
|
241
|
+
It allows you to follow an association of your choice while building a query (a scope). You start querying posts, and then you change to querying the authors of those posts. For simple cases, it's possible that both `where_assoc` and `follow_assoc` can build the query your need, but each can handle different situations. Here is an example:
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
# Find every posts that have comments by an admin
|
245
|
+
Post.where_assoc_exists([:comments, :author], &:admins)
|
246
|
+
```
|
247
|
+
|
248
|
+
This could be done with `follow_assoc`: `User.admins.follow_assoc(:comments, :post)`. But if you wanted conditions on a second association, then `follow_assoc` wouldn't work. On the other hand, if you received a scope on users and wanted their posts, then `follow_assoc` would be a nicer tool for the job. It all depends on the context where you need to do the query and what starting point you have.
|
249
|
+
|
225
250
|
## Development
|
226
251
|
|
227
252
|
After checking out the repo, run `bundle install` to install dependencies.
|
@@ -2,7 +2,17 @@
|
|
2
2
|
|
3
3
|
module ActiveRecordWhereAssoc
|
4
4
|
module ActiveRecordCompat
|
5
|
-
if ActiveRecord.gem_version >= Gem::Version.new("
|
5
|
+
if ActiveRecord.gem_version >= Gem::Version.new("6.1.0.rc1")
|
6
|
+
JoinKeys = Struct.new(:key, :foreign_key)
|
7
|
+
def self.join_keys(reflection, poly_belongs_to_klass)
|
8
|
+
if poly_belongs_to_klass
|
9
|
+
JoinKeys.new(reflection.join_primary_key(poly_belongs_to_klass), reflection.join_foreign_key)
|
10
|
+
else
|
11
|
+
JoinKeys.new(reflection.join_primary_key, reflection.join_foreign_key)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
elsif ActiveRecord.gem_version >= Gem::Version.new("5.1")
|
6
16
|
def self.join_keys(reflection, poly_belongs_to_klass)
|
7
17
|
if poly_belongs_to_klass
|
8
18
|
reflection.get_join_keys(poly_belongs_to_klass)
|
@@ -13,11 +13,12 @@ module ActiveRecordWhereAssoc
|
|
13
13
|
# => "EXISTS (SELECT... *relation1*) OR EXISTS (SELECT... *relation2*)"
|
14
14
|
def self.sql_for_any_exists(relations)
|
15
15
|
relations = [relations] unless relations.is_a?(Array)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
relations = relations.reject { |rel| rel.is_a?(ActiveRecord::NullRelation) }
|
17
|
+
sqls = relations.map { |rel| "EXISTS (#{rel.select('1').to_sql})" }
|
18
|
+
if sqls.size > 1
|
19
|
+
"(#{sqls.join(" OR ")})" # Parens needed when embedding the sql in a `where`, because the OR could make things wrong
|
20
|
+
elsif sqls.size == 1
|
21
|
+
sqls.first
|
21
22
|
else
|
22
23
|
"0=1"
|
23
24
|
end
|
@@ -30,10 +31,11 @@ module ActiveRecordWhereAssoc
|
|
30
31
|
|
31
32
|
# Returns the SQL for getting the sum of of the received relations
|
32
33
|
# => "SUM((SELECT... *relation1*)) + SUM((SELECT... *relation2*))"
|
33
|
-
def self.sql_for_sum_of_counts(
|
34
|
-
|
34
|
+
def self.sql_for_sum_of_counts(relations)
|
35
|
+
relations = [relations] unless relations.is_a?(Array)
|
36
|
+
relations = relations.reject { |rel| rel.is_a?(ActiveRecord::NullRelation) }
|
35
37
|
# Need the double parentheses
|
36
|
-
|
38
|
+
relations.map { |rel| "SUM((#{rel.to_sql}))" }.join(" + ").presence || "0"
|
37
39
|
end
|
38
40
|
|
39
41
|
# Block used when nesting associations for a where_assoc_count
|
@@ -83,7 +85,7 @@ module ActiveRecordWhereAssoc
|
|
83
85
|
end
|
84
86
|
|
85
87
|
nested_relations = relations_on_association(record_class, association_names, given_conditions, options, deepest_scope_mod, NestWithSumBlock)
|
86
|
-
|
88
|
+
nested_relations = nested_relations.reject { |rel| rel.is_a?(ActiveRecord::NullRelation) }
|
87
89
|
nested_relations.map { |nr| "COALESCE((#{nr.to_sql}), 0)" }.join(" + ").presence || "0"
|
88
90
|
end
|
89
91
|
|
@@ -139,7 +141,7 @@ module ActiveRecordWhereAssoc
|
|
139
141
|
# Each step, we get all of the scoping lambdas that were defined on associations that apply for
|
140
142
|
# the reflection's target
|
141
143
|
# Basically, we start from the deepest part of the query and wrap it up
|
142
|
-
reflection_chain,
|
144
|
+
reflection_chain, constraints_chain = ActiveRecordCompat.chained_reflection_and_chained_constraints(final_reflection)
|
143
145
|
skip_next = false
|
144
146
|
|
145
147
|
reflection_chain.each_with_index do |reflection, i|
|
@@ -151,7 +153,7 @@ module ActiveRecordWhereAssoc
|
|
151
153
|
# the 2nd part of has_and_belongs_to_many is handled at the same time as the first.
|
152
154
|
skip_next = true if actually_has_and_belongs_to_many?(reflection)
|
153
155
|
|
154
|
-
init_scopes = initial_scopes_from_reflection(reflection_chain[i..-1],
|
156
|
+
init_scopes = initial_scopes_from_reflection(record_class, reflection_chain[i..-1], constraints_chain[i], options)
|
155
157
|
current_scopes = init_scopes.map do |alias_scope, current_scope, klass_scope|
|
156
158
|
current_scope = process_association_step_limits(current_scope, reflection, record_class, options)
|
157
159
|
|
@@ -195,13 +197,13 @@ module ActiveRecordWhereAssoc
|
|
195
197
|
end
|
196
198
|
|
197
199
|
# Can return multiple pairs for polymorphic belongs_to, one per table to look into
|
198
|
-
def self.initial_scopes_from_reflection(reflection_chain, assoc_scopes, options)
|
200
|
+
def self.initial_scopes_from_reflection(record_class, reflection_chain, assoc_scopes, options)
|
199
201
|
reflection = reflection_chain.first
|
200
202
|
actual_source_reflection = user_defined_actual_source_reflection(reflection)
|
201
203
|
|
202
204
|
on_poly_belongs_to = option_value(options, :poly_belongs_to) if poly_belongs_to?(actual_source_reflection)
|
203
205
|
|
204
|
-
classes_with_scope = classes_with_scope_for_reflection(reflection, options)
|
206
|
+
classes_with_scope = classes_with_scope_for_reflection(record_class, reflection, options)
|
205
207
|
|
206
208
|
assoc_scope_allowed_lim_off = assoc_scope_to_keep_lim_off_from(reflection)
|
207
209
|
|
@@ -223,18 +225,18 @@ module ActiveRecordWhereAssoc
|
|
223
225
|
# would be great, except we cannot add a given_conditions afterward because we are on the wrong "base class",
|
224
226
|
# and we can't do #merge because of the LEW crap.
|
225
227
|
# So we must do the joins ourself!
|
226
|
-
_wrapper, sub_join_contraints = wrapper_and_join_constraints(reflection)
|
228
|
+
_wrapper, sub_join_contraints = wrapper_and_join_constraints(record_class, reflection)
|
227
229
|
next_reflection = reflection_chain[1]
|
228
230
|
|
229
231
|
current_scope = current_scope.joins(<<-SQL)
|
230
232
|
INNER JOIN #{next_reflection.klass.quoted_table_name} ON #{sub_join_contraints.to_sql}
|
231
233
|
SQL
|
232
234
|
|
233
|
-
alias_scope,
|
235
|
+
alias_scope, join_constraints = wrapper_and_join_constraints(record_class, next_reflection, habtm_other_reflection: reflection)
|
234
236
|
elsif on_poly_belongs_to
|
235
|
-
alias_scope,
|
237
|
+
alias_scope, join_constraints = wrapper_and_join_constraints(record_class, reflection, poly_belongs_to_klass: klass)
|
236
238
|
else
|
237
|
-
alias_scope,
|
239
|
+
alias_scope, join_constraints = wrapper_and_join_constraints(record_class, reflection)
|
238
240
|
end
|
239
241
|
|
240
242
|
assoc_scopes.each do |callable|
|
@@ -254,7 +256,7 @@ module ActiveRecordWhereAssoc
|
|
254
256
|
current_scope = current_scope.merge(relation)
|
255
257
|
end
|
256
258
|
|
257
|
-
[alias_scope, current_scope.where(
|
259
|
+
[alias_scope, current_scope.where(join_constraints), klass_scope]
|
258
260
|
end
|
259
261
|
end
|
260
262
|
|
@@ -270,7 +272,7 @@ module ActiveRecordWhereAssoc
|
|
270
272
|
user_defined_actual_source_reflection(reflection).scope
|
271
273
|
end
|
272
274
|
|
273
|
-
def self.classes_with_scope_for_reflection(reflection, options)
|
275
|
+
def self.classes_with_scope_for_reflection(record_class, reflection, options)
|
274
276
|
actual_source_reflection = user_defined_actual_source_reflection(reflection)
|
275
277
|
|
276
278
|
if poly_belongs_to?(actual_source_reflection)
|
@@ -281,7 +283,15 @@ module ActiveRecordWhereAssoc
|
|
281
283
|
else
|
282
284
|
case on_poly_belongs_to
|
283
285
|
when :pluck
|
284
|
-
|
286
|
+
model_for_ids = actual_source_reflection.active_record
|
287
|
+
|
288
|
+
if model_for_ids.abstract_class
|
289
|
+
# When the reflection is defined on an abstract model, we fallback to the model
|
290
|
+
# on which this was called
|
291
|
+
model_for_ids = record_class
|
292
|
+
end
|
293
|
+
|
294
|
+
class_names = model_for_ids.distinct.pluck(actual_source_reflection.foreign_type)
|
285
295
|
class_names.compact.map!(&:safe_constantize).compact
|
286
296
|
when Array, Hash
|
287
297
|
array = on_poly_belongs_to.to_a
|
@@ -323,6 +333,9 @@ module ActiveRecordWhereAssoc
|
|
323
333
|
return current_scope.unscope(:limit, :offset, :order)
|
324
334
|
end
|
325
335
|
|
336
|
+
# No need to do transformations if this is already a NullRelation
|
337
|
+
return current_scope if current_scope.is_a?(ActiveRecord::NullRelation)
|
338
|
+
|
326
339
|
current_scope = current_scope.limit(1) if reflection.macro == :has_one
|
327
340
|
|
328
341
|
# Order is useless without either limit or offset
|
@@ -386,7 +399,7 @@ module ActiveRecordWhereAssoc
|
|
386
399
|
alias_scope
|
387
400
|
end
|
388
401
|
|
389
|
-
def self.wrapper_and_join_constraints(reflection, options = {})
|
402
|
+
def self.wrapper_and_join_constraints(record_class, reflection, options = {})
|
390
403
|
poly_belongs_to_klass = options[:poly_belongs_to_klass]
|
391
404
|
join_keys = ActiveRecordCompat.join_keys(reflection, poly_belongs_to_klass)
|
392
405
|
|
@@ -395,6 +408,12 @@ module ActiveRecordWhereAssoc
|
|
395
408
|
|
396
409
|
table = (poly_belongs_to_klass || reflection.klass).arel_table
|
397
410
|
foreign_klass = reflection.send(:actual_source_reflection).active_record
|
411
|
+
if foreign_klass.abstract_class
|
412
|
+
# When the reflection is defined on an abstract model, we fallback to the model
|
413
|
+
# on which this was called
|
414
|
+
foreign_klass = record_class
|
415
|
+
end
|
416
|
+
|
398
417
|
foreign_table = foreign_klass.arel_table
|
399
418
|
|
400
419
|
habtm_other_reflection = options[:habtm_other_reflection]
|
@@ -58,8 +58,12 @@ module ActiveRecordWhereAssoc
|
|
58
58
|
# Post.where_assoc_exists([:comments, :replies])
|
59
59
|
#
|
60
60
|
# === Condition
|
61
|
-
# After the +association_name+ argument, you can pass
|
62
|
-
#
|
61
|
+
# After the +association_name+ argument, you can pass conditions on your association to
|
62
|
+
# specify which of its records you care about. For example, you could only want Posts that
|
63
|
+
# have a comment marked as spam, so all you care about are comments marked as spam.
|
64
|
+
#
|
65
|
+
# Another way to look at this is that you are filtering your association (using a +#where+)
|
66
|
+
# and checking if a record of that association is still found, and you do this for each of you records.
|
63
67
|
#
|
64
68
|
# This +condition+ argument is passed directly to +#where+, so you can pass in the following:
|
65
69
|
#
|
@@ -91,13 +95,13 @@ module ActiveRecordWhereAssoc
|
|
91
95
|
#
|
92
96
|
# === Block
|
93
97
|
# The block is used to add more complex conditions. The effect is the same as the condition
|
94
|
-
# parameter
|
95
|
-
#
|
98
|
+
# parameter. You are specifying which records in the association you care about, but using
|
99
|
+
# a block lets you use any scoping methods, such as +#where+, +#joins+, nested
|
96
100
|
# +#where_assoc_*+, scopes on the model, etc.
|
97
101
|
#
|
98
102
|
# Note that using +#joins+ might lead to unexpected results when using #where_assoc_count,
|
99
103
|
# since if the joins adds rows, it will change the resulting count. It probably makes more
|
100
|
-
# sense to, again, use one of the +where_assoc_*+ methods.
|
104
|
+
# sense to, again, use one of the +where_assoc_*+ methods (they can be nested).
|
101
105
|
#
|
102
106
|
# There are 2 ways of using the block for adding conditions to the association.
|
103
107
|
#
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord_where_assoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maxime Handfield Lapointe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -80,20 +80,6 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '10.0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: coveralls
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: deep-cover
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -204,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
204
190
|
- !ruby/object:Gem::Version
|
205
191
|
version: '0'
|
206
192
|
requirements: []
|
207
|
-
rubygems_version: 3.
|
193
|
+
rubygems_version: 3.3.7
|
208
194
|
signing_key:
|
209
195
|
specification_version: 4
|
210
196
|
summary: Make ActiveRecord do conditions on your associations
|