where_exists 1.1.4 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9264d4a29619fa91e69b9648228c2597564b087e81d11012bfe6e1708337ac7d
4
- data.tar.gz: cd071c68e39c82aa182c35f99e5871dd0ddeec3b3bbdb63e5aa12dbfc2ee088e
3
+ metadata.gz: 397b2a3fc406fb516d6f060ae46b25580a764c668476859737ee07fbd979c15b
4
+ data.tar.gz: 1c23ab279b89ede28edb71e3b951f7587ab2a7b27605bba607888f0b89e03c58
5
5
  SHA512:
6
- metadata.gz: 33621afb28c864019a32ef912bcda6edbd481ea26b4eabef5965796ce8bfd23f8e37f4ed56ddce72e34bf0f286e8759b1132ee39ffd95a3b329ad2cdbfce2fdb
7
- data.tar.gz: dfe4dee7dc35c9a5fe4a3bbe4441a4647da72d9f541c4f0c98f564df784e394b27da5776d1c9389b4e879b102bbd701af5db4052a32b80bd6b7e2d5264c9ba0c
6
+ metadata.gz: 454c6302e62cbc669c8d800bab1305b2e83402f46ed2499a4caf373cfaa23547cbaf261163fc28cd2fe224a31c7f5bb927a5baf09deb04c856de49c481b5fc75
7
+ data.tar.gz: b32e53db604284721d96afd9b1fa7ac204277dda4cc27f4851ac1918760980fa64c17392917ca770a712541f5ab132bedaa2f0f102ac6c20fa50354d16e18ad1
data/MIT-LICENSE CHANGED
File without changes
data/README.markdown ADDED
@@ -0,0 +1,168 @@
1
+ # Where Exists
2
+ **Rails way to harness the power of SQL EXISTS condition**<br>
3
+ [![Gem Version](https://badge.fury.io/rb/where_exists.svg)](http://badge.fury.io/rb/where_exists)
4
+
5
+ ## Description
6
+
7
+ <img src="http://i.imgur.com/psLfPoW.gif" alt="Exists" align="right" width="100" height="200">
8
+
9
+ This gem does exactly two things:
10
+
11
+ * Selects each model object for which there is a certain associated object
12
+ * Selects each model object for which there aren't any certain associated objects
13
+
14
+ It uses SQL [EXISTS condition](http://www.techonthenet.com/sql/exists.php) to do it fast, and extends ActiveRecord with `where_exists` and `where_not_exists` methods to make its usage simple and straightforward.
15
+
16
+ ## Quick start
17
+
18
+ Add gem to Gemfile:
19
+
20
+ gem 'where_exists'
21
+
22
+ and run `bundle install` as usual.
23
+
24
+ And now you have `where_exists` and `where_not_exists` methods available for your ActiveRecord models and relations.
25
+
26
+ Syntax:
27
+
28
+ ```ruby
29
+ Model.where_exists(association, additional_finder_parameters)
30
+ ```
31
+
32
+ Supported Rails versions: >= 4.2.
33
+
34
+ ## Example of usage
35
+
36
+ Given there is User model:
37
+
38
+ ```ruby
39
+ class User < ActiveRecord::Base
40
+ has_many :connections
41
+ has_many :groups, through: :connections
42
+ end
43
+ ```
44
+
45
+ And Group:
46
+
47
+ ```ruby
48
+ class Group < ActiveRecord::Base
49
+ has_many :connections
50
+ has_many :users, through: :connections
51
+ end
52
+ ```
53
+
54
+ And standard many-to-many Connection:
55
+
56
+ ```ruby
57
+ class Connection
58
+ belongs_to :user
59
+ belongs_to :group
60
+ end
61
+ ```
62
+
63
+ What I want to do is to:
64
+
65
+ * Select users who don't belong to given set of Groups (groups with ids `[4,5,6]`)
66
+ * Select users who belong to one set of Groups (`[1,2,3]`) and don't belong to another (`[4,5,6]`)
67
+ * Select users who don't belong to a Group
68
+
69
+ Also, I don't want to:
70
+
71
+ * Fetch a lot of data from database to manipulate it with Ruby code. I know that will be inefficient in terms of CPU and memory (Ruby is much slower than any commonly used DB engine, and typically I want to rely on DB engine to do the heavy lifting)
72
+ * I tried queries like `User.joins(:group).where(group_id: [1,2,3]).where.not(group_id: [4,5,6])` and they return wrong results (some users from the result set belong to groups 4,5,6 *as well as* 1,2,3)
73
+ * I don't want to do `join` merely for the sake of only checking for existence, because I know that that is a pretty complex (i.e. CPU/memory-intensive) operation for DB
74
+
75
+ <sub><sup>If you wonder how to do that without the gem (i.e. essentially by writing SQL EXISTS statement manually) see that [StackOverflow answer](http://stackoverflow.com/a/32016347/5029266) (disclosure: it's self-answered question of a contributor of this gem).</sup></sub>
76
+
77
+ And now you are able to do all these things (and more) as simple as:
78
+
79
+ > Select only users who don't belong to given set of Groups (groups with ids `[4,5,6]`)
80
+
81
+ ```ruby
82
+ # It's really neat, isn't it?
83
+ User.where_exists(:groups, id: [4,5,6])
84
+ ```
85
+
86
+ <sub><sup>Notice that the second argument is `where` parameters for Group model</sup></sub>
87
+
88
+ > Select only users who belong to one set of Groups (`[1,2,3]`) and don't belong to another (`[4,5,6]`)
89
+
90
+ ```ruby
91
+ # Chain-able like you expect them to be.
92
+ #
93
+ # Additional finder parameters is anything that
94
+ # could be fed to 'where' method.
95
+ #
96
+ # Let's use 'name' instead of 'id' here, for example.
97
+
98
+ User.where_exists(:groups, name: ['first','second','third']).
99
+ where_not_exists(:groups, name: ['fourth','fifth','sixth'])
100
+ ```
101
+
102
+ <sub><sup>It is possible to add as much attributes to the criteria as it is necessary, just as with regular `where(...)`</sub></sup>
103
+
104
+ > Select only users who don't belong to a Group
105
+
106
+ ```ruby
107
+ # And that's just its basic capabilities
108
+ User.where_not_exists(:groups)
109
+ ```
110
+
111
+ <sub><sup>Adding parameters (the second argument) to `where_not_exists` method is feasible as well, if you have such requirements.</sup></sub>
112
+
113
+
114
+ > Re-use existing scopes
115
+
116
+ ```ruby
117
+ User.where_exists(:groups) do |groups_scope|
118
+ groups_scope.activated_since(Time.now)
119
+ end
120
+
121
+ User.where_exists(:groups, &:approved)
122
+ ```
123
+ <sub><sup>If you pass a block to `where_exists`, the scope of the relation will be yielded to your block so you can re-use existing scopes.</sup></sub>
124
+
125
+
126
+
127
+ ## Additional capabilities
128
+
129
+ **Q**: Does it support both `has_many` and `belongs_to` association type?<br>
130
+ **A**: Yes.
131
+
132
+
133
+ **Q**: Does it support polymorphic associations?<br>
134
+ **A**: Yes, both ways.
135
+
136
+
137
+ **Q**: Does it support multi-level (recursive) `:through` associations?<br>
138
+ **A**: You bet. (Now you can forget complex EXISTS or JOIN statetements in a pretty wide variety of similar cases.)
139
+
140
+
141
+ **Q**: Does it support `where` parameters with interpolation, e.g. `parent.where_exists(:child, 'fieldA > ?', 1)`?<br>
142
+ **A**: Yes.
143
+
144
+
145
+ **Q**: Does it take into account default association condition, e.g. `has_many :drafts, -> { where published: nil }`?<br>
146
+ **A**: Yes.
147
+
148
+ ## Contributing
149
+
150
+ If you find that this gem lacks certain possibilities that you would have found useful, don't hesitate to create a [feature request](https://github.com/EugZol/where_exists/issues).
151
+
152
+ Also,
153
+
154
+ * Report bugs
155
+ * Submit pull request with new features or bug fixes
156
+ * Enhance or clarify the documentation that you are reading
157
+
158
+ To run tests: `bundle exec rake test`
159
+
160
+ ## License
161
+
162
+ This project uses MIT license. See [`MIT-LICENSE`](https://github.com/EugZol/where_exists/blob/master/MIT-LICENSE) file for full text.
163
+
164
+ ## Alternatives
165
+
166
+ One known alternative is https://github.com/MaxLap/activerecord_where_assoc
167
+
168
+ A comprehensive comparison is made by MaxLap here: https://github.com/MaxLap/activerecord_where_assoc/blob/master/ALTERNATIVES_PROBLEMS.md
data/Rakefile CHANGED
File without changes
data/lib/where_exists.rb CHANGED
@@ -20,7 +20,11 @@ module WhereExists
20
20
  not_string = "NOT "
21
21
  end
22
22
 
23
- self.where("#{not_string}(#{queries_sql})")
23
+ if queries_sql.empty?
24
+ does_exist ? self.none : self.all
25
+ else
26
+ self.where("#{not_string}(#{queries_sql})")
27
+ end
24
28
  end
25
29
 
26
30
  def build_exists_string(association_name, *where_parameters, &block)
@@ -61,7 +65,9 @@ module WhereExists
61
65
  association_scope = association.scope
62
66
 
63
67
  if polymorphic
64
- associated_models = self.select("DISTINCT #{connection.quote_column_name(association.foreign_type)}").pluck(association.foreign_type).map(&:constantize)
68
+ associated_models = self.select("DISTINCT #{connection.quote_column_name(association.foreign_type)}").
69
+ where("#{connection.quote_column_name(association.foreign_type)} IS NOT NULL").pluck(association.foreign_type).
70
+ uniq.map(&:classify).map(&:constantize)
65
71
  else
66
72
  associated_models = [association.klass]
67
73
  end
@@ -82,8 +88,10 @@ module WhereExists
82
88
  query = query.instance_exec(&association_scope)
83
89
  end
84
90
  if polymorphic
85
- other_type = connection.quote(associated_model.name)
86
- query = query.where("#{self_type} = #{other_type}")
91
+ other_types = [associated_model.name, associated_model.table_name]
92
+ other_types << associated_model.polymorphic_name if associated_model.respond_to?(:polymorphic_name)
93
+
94
+ query = query.where("#{self_type} IN (?)", other_types.uniq)
87
95
  end
88
96
  queries.push query
89
97
  end
@@ -129,8 +137,14 @@ module WhereExists
129
137
 
130
138
  if association.options[:as]
131
139
  other_types = quote_table_and_column_name(associated_model.table_name, association.type)
132
- self_class = connection.quote(self.name)
133
- result = result.where("#{other_types} = #{self_class}")
140
+ class_values = [self.name, self.table_name]
141
+ class_values << self.polymorphic_name if associated_model.respond_to?(:polymorphic_name)
142
+
143
+ result = result.where("#{other_types} IN (?)", class_values.uniq)
144
+ end
145
+
146
+ if association_scope
147
+ result = result.instance_exec(&association_scope)
134
148
  end
135
149
 
136
150
  if next_association[:association]
@@ -141,10 +155,6 @@ module WhereExists
141
155
  result = result.where(*where_parameters)
142
156
  end
143
157
 
144
- if association_scope
145
- result = result.instance_exec(&association_scope)
146
- end
147
-
148
158
  [result]
149
159
  end
150
160
 
@@ -155,11 +165,9 @@ module WhereExists
155
165
 
156
166
  primary_key = association.options[:primary_key] || self.primary_key
157
167
 
158
- join_table = [self.table_name, associated_model.table_name].sort.join("_")
159
-
160
168
  self_ids = quote_table_and_column_name(self.table_name, primary_key)
161
- join_ids = quote_table_and_column_name(join_table, association.foreign_key)
162
- associated_join_ids = quote_table_and_column_name(join_table, "#{associated_model.name.downcase}_id")
169
+ join_ids = quote_table_and_column_name(association.join_table, association.foreign_key)
170
+ associated_join_ids = quote_table_and_column_name(association.join_table, association.association_foreign_key)
163
171
  associated_ids = quote_table_and_column_name(associated_model.table_name, associated_model.primary_key)
164
172
 
165
173
  result =
@@ -167,7 +175,7 @@ module WhereExists
167
175
  select("1").
168
176
  joins(
169
177
  <<-SQL
170
- INNER JOIN #{connection.quote_table_name(join_table)}
178
+ INNER JOIN #{connection.quote_table_name(association.join_table)}
171
179
  ON #{associated_ids} = #{associated_join_ids}
172
180
  SQL
173
181
  ).
@@ -198,13 +206,13 @@ module WhereExists
198
206
 
199
207
  if next_association[:next_association] && next_association[:next_association][:association]
200
208
  subq = str.match(/\([^\(\)]+\)/mi)[0]
201
- str.sub!(subq,
209
+ str.sub!(subq) do
202
210
  "(#{subq} AND (#{loop_nested_association(
203
211
  next_association[:association],
204
212
  next_association[:next_association],
205
213
  true
206
214
  )}))"
207
- )
215
+ end
208
216
  end
209
217
 
210
218
  nested ? str : [query.where(str)]
@@ -1,3 +1,3 @@
1
1
  module WhereExists
2
- VERSION = "1.1.4"
2
+ VERSION = "1.2.3"
3
3
  end
@@ -60,4 +60,33 @@ class BelongsToPolymorphicTest < Minitest::Test
60
60
  assert_equal 1, result.length
61
61
  assert_equal orphaned_child.id, result.first.id
62
62
  end
63
+
64
+ def test_no_entities_or_empty_child_relation
65
+ result = BelongsToPolymorphicChild.where_not_exists(:polymorphic_entity)
66
+ assert_equal 0, result.length
67
+
68
+ _first_child = BelongsToPolymorphicChild.create!
69
+ result = BelongsToPolymorphicChild.where_not_exists(:polymorphic_entity)
70
+ assert_equal 1, result.length
71
+
72
+ result = BelongsToPolymorphicChild.where_exists(:polymorphic_entity)
73
+ assert_equal 0, result.length
74
+ end
75
+
76
+ def test_table_name_based_lookup
77
+ first_entity = FirstPolymorphicEntity.create!
78
+ second_entity = SecondPolymorphicEntity.create! id: first_entity.id + 1
79
+
80
+ first_child = BelongsToPolymorphicChild.create!(polymorphic_entity_id: first_entity.id, polymorphic_entity_type: first_entity.class.table_name)
81
+ second_child = BelongsToPolymorphicChild.create!(polymorphic_entity_id: second_entity.id, polymorphic_entity_type: second_entity.class.table_name)
82
+ orphaned_child = BelongsToPolymorphicChild.create!(polymorphic_entity_id: second_entity.id, polymorphic_entity_type: first_entity.class.table_name)
83
+
84
+ result = BelongsToPolymorphicChild.where_exists(:polymorphic_entity)
85
+ assert_equal 2, result.length
86
+ assert_equal [first_child, second_child].map(&:id).sort, result.map(&:id).sort
87
+
88
+ result = BelongsToPolymorphicChild.where_not_exists(:polymorphic_entity)
89
+ assert_equal 1, result.length
90
+ assert_equal [orphaned_child].map(&:id).sort, result.map(&:id).sort
91
+ end
63
92
  end
File without changes
data/test/db/test.db CHANGED
Binary file
File without changes
File without changes
@@ -35,10 +35,17 @@ class HasManyPolymorphicTest < Minitest::Test
35
35
  child = HasManyPolymorphicChild.create!
36
36
 
37
37
  irrelevant_entity = IrrelevantPolymorphicEntity.create!(children: [child])
38
- _relevant_entity = RelevantPolymorphicEntity.create!(id: irrelevant_entity.id)
38
+ relevant_entity = RelevantPolymorphicEntity.create!(id: irrelevant_entity.id)
39
+
40
+ assert_equal 0, RelevantPolymorphicEntity.where_exists(:children).length
41
+ assert_equal 1, IrrelevantPolymorphicEntity.where_exists(:children).length
42
+
43
+ child.update!(polymorphic_thing_type: RelevantPolymorphicEntity.table_name)
39
44
 
40
45
  result = RelevantPolymorphicEntity.where_exists(:children)
41
46
 
42
- assert_equal 0, result.length
47
+ assert_equal 0, IrrelevantPolymorphicEntity.where_exists(:children).length
48
+ assert_equal 1, result.length
49
+ assert_equal relevant_entity.id, result.first&.id
43
50
  end
44
51
  end
File without changes
@@ -1,34 +1,71 @@
1
1
  require_relative 'test_helper'
2
2
 
3
- ActiveRecord::Migration.create_table :projects, :force => true do |t|
3
+ ActiveRecord::Migration.create_table :projects, force: true do |t|
4
4
  t.string :name
5
5
  end
6
6
 
7
- ActiveRecord::Migration.create_table :tasks, :force => true do |t|
7
+ ActiveRecord::Migration.create_table :tasks, force: true do |t|
8
8
  t.string :name
9
9
  t.integer :project_id
10
10
  end
11
11
 
12
- ActiveRecord::Migration.create_table :line_items, :force => true do |t|
12
+ ActiveRecord::Migration.create_table :line_items, force: true do |t|
13
13
  t.string :name
14
14
  t.integer :invoice_id
15
15
  t.integer :task_id
16
16
  end
17
17
 
18
- ActiveRecord::Migration.create_table :work_details, :force => true do |t|
18
+ ActiveRecord::Migration.create_table :work_details, force: true do |t|
19
19
  t.string :name
20
20
  t.integer :line_item_id
21
21
  end
22
22
 
23
- ActiveRecord::Migration.create_table :invoices, :force => true do |t|
23
+ ActiveRecord::Migration.create_table :invoices, force: true do |t|
24
24
  t.string :name
25
25
  end
26
26
 
27
+ ActiveRecord::Migration.create_table :blobs, force: true do |t|
28
+ end
29
+
30
+ ActiveRecord::Migration.create_table :attachments, force: true do |t|
31
+ t.string :name, null: false
32
+ t.references :record, null: false, polymorphic: true, index: false
33
+ t.references :blob, null: false
34
+
35
+ t.datetime :created_at, null: false
36
+
37
+ t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_attachments_uniqueness", unique: true
38
+ end
39
+
40
+ class Attachment < ActiveRecord::Base
41
+ belongs_to :record, polymorphic: true, touch: true
42
+ belongs_to :blob
43
+ end
44
+
45
+ class Blob < ActiveRecord::Base
46
+ has_many :attachments
47
+
48
+ scope :unattached, -> { left_joins(:attachments).where(Attachment.table_name => { blob_id: nil }) }
49
+
50
+ before_destroy(prepend: true) do
51
+ raise ActiveRecord::InvalidForeignKey if attachments.exists?
52
+ end
53
+ end
54
+
55
+
56
+
27
57
  class Project < ActiveRecord::Base
28
58
  has_many :tasks
29
59
  has_many :invoices, :through => :tasks
30
60
  has_many :project_line_items, :through => :tasks, :source => :line_items
31
61
  has_many :work_details, :through => :project_line_items
62
+
63
+ has_many :attachments, as: :record
64
+ has_many :blobs, through: :attachments, source: :blob
65
+ has_many :relevant_attachments, -> { where(name: "relevant") }, as: :record, class_name: "Attachment", inverse_of: :record, dependent: false
66
+ has_many :relevant_blobs, through: :relevant_attachments, class_name: "Blob", source: :blob
67
+ has_many :irrelevant_attachments, -> { where(name: "irrelevant") }, as: :record, class_name: "Attachment", inverse_of: :record, dependent: false
68
+ has_many :irrelevant_blobs, through: :irrelevant_attachments, class_name: "Blob", source: :blob
32
69
  end
33
70
 
34
71
  class Task < ActiveRecord::Base
@@ -36,6 +73,7 @@ class Task < ActiveRecord::Base
36
73
 
37
74
  has_many :invoices, :through => :line_items
38
75
  has_many :line_items
76
+ has_many :scoped_line_items, -> { where(name: 'relevant') }, class_name: 'LineItem'
39
77
  end
40
78
 
41
79
  class LineItem < ActiveRecord::Base
@@ -94,12 +132,16 @@ class HasManyThroughTest < Minitest::Test
94
132
  invoice = Invoice.create!(name: 'relevant')
95
133
  irrelevant_invoice = Invoice.create!(name: 'irrelevant')
96
134
 
97
- line_item = LineItem.create!(task: task, invoice: invoice)
98
- irrelevant_line_item = LineItem.create!(task: irrelevant_task, invoice: irrelevant_invoice)
135
+ line_item = LineItem.create!(name: 'relevant', task: task, invoice: invoice)
136
+ irrelevant_line_item = LineItem.create!(name: 'relevant', task: irrelevant_task, invoice: irrelevant_invoice)
99
137
 
100
138
  _work_detail = WorkDetail.create!(line_item: line_item, name: 'relevant')
101
139
  _irrelevant_work_detail = WorkDetail.create!(line_item: irrelevant_line_item, name: 'irrelevant')
102
140
 
141
+ blob = Blob.create!()
142
+ _relevant_attachment = Attachment.create!(name: 'relevant', blob: blob, record: project)
143
+ _irrelevant_attachment = Attachment.create!(name: 'irrelevant', blob: blob, record: irrelevant_project)
144
+
103
145
  result = Project.where_exists(:invoices, name: 'relevant')
104
146
 
105
147
  assert_equal 1, result.length
@@ -124,5 +166,28 @@ class HasManyThroughTest < Minitest::Test
124
166
 
125
167
  assert_equal 1, result.length
126
168
  assert_equal irrelevant_project.id, result.first.id
169
+
170
+ result = Task.where_exists(:scoped_line_items)
171
+
172
+ assert_equal 2, result.length
173
+
174
+ result = Project.where_exists(:relevant_blobs)
175
+
176
+ assert_equal 1, result.length
177
+ assert_equal project.id, result.first.id
178
+
179
+ result = Project.where_not_exists(:relevant_blobs)
180
+
181
+ assert_equal 1, result.length
182
+ assert_equal irrelevant_project.id, result.first.id
183
+
184
+ result = Project.where_exists(:blobs)
185
+
186
+ assert_equal 2, result.length
187
+
188
+ result = Project.where_not_exists(:blobs)
189
+
190
+ assert_equal 0, result.length
191
+
127
192
  end
128
193
  end
data/test/test_helper.rb CHANGED
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: where_exists
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugene Zolotarev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-25 00:00:00.000000000 Z
11
+ date: 2021-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '4.2'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6'
22
+ version: '6.2'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,21 +29,21 @@ dependencies:
29
29
  version: '4.2'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6'
32
+ version: '6.2'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: sqlite3
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.3'
39
+ version: '1.4'
40
40
  type: :development
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '1.3'
46
+ version: '1.4'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: minitest
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,7 @@ extensions: []
94
94
  extra_rdoc_files: []
95
95
  files:
96
96
  - MIT-LICENSE
97
+ - README.markdown
97
98
  - Rakefile
98
99
  - lib/where_exists.rb
99
100
  - lib/where_exists/version.rb
@@ -125,18 +126,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
126
  - !ruby/object:Gem::Version
126
127
  version: '0'
127
128
  requirements: []
128
- rubyforge_project:
129
- rubygems_version: 2.7.7
129
+ rubygems_version: 3.1.2
130
130
  signing_key:
131
131
  specification_version: 4
132
132
  summary: "#where_exists extension of ActiveRecord"
133
133
  test_files:
134
+ - test/has_and_belongs_to_many.rb
134
135
  - test/belongs_to_polymorphic_test.rb
135
- - test/belongs_to_test.rb
136
+ - test/has_many_through_test.rb
136
137
  - test/db/test.db
137
- - test/documentation_test.rb
138
- - test/has_and_belongs_to_many.rb
138
+ - test/test_helper.rb
139
139
  - test/has_many_polymorphic_test.rb
140
140
  - test/has_many_test.rb
141
- - test/has_many_through_test.rb
142
- - test/test_helper.rb
141
+ - test/documentation_test.rb
142
+ - test/belongs_to_test.rb