where_exists 1.1.3 → 1.2.2

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
- SHA1:
3
- metadata.gz: 053b8ce3825e7f5eeb8faa98a85d5e2fc92c4edf
4
- data.tar.gz: 4aefc7de26143e6b72b62f99113fea19f6737b2e
2
+ SHA256:
3
+ metadata.gz: 28bde73cd6a1857a0762a1fd489258ad40b44cea344afba4357cbe7fa83cdf41
4
+ data.tar.gz: ed7a98cb6a7391cb955c911f0063f9eb901e86305b0b7ddb3e01b9a209371476
5
5
  SHA512:
6
- metadata.gz: e3b5343d68abd33b091752e49c4689215655e515d785052478022bd33f743d621e196c1bbab623a57d67db1e46bcc3ea3a8949b4170955b09674b371f389b5fa
7
- data.tar.gz: 166df723c753b0b755eb46b51c9f4acac4f795ac887fb2d1d9ed18ec27ee76b78c783d5f32d8d1fbf29e70ac2a7589b0e4877fd6c02deb1315fddb5925c70226
6
+ metadata.gz: 943e345289ac9f2a2d44a5428a559c8a22adb11713b26ac0e7893fd28ccbb9577a092bbae50fa9eec960c72497ca5d902892209ce7c83d9c2b291fc017e0d5ab
7
+ data.tar.gz: 509c56167e4998c662bf21efa637de8495cc5d2974421041d8264f66de16f99a2c223463cfd494b35f64bffb39b8511696822405e2609b649ff876f685ffd4cc
@@ -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
@@ -47,10 +47,12 @@ module WhereExists
47
47
  raise ArgumentError.new("where_exists: not supported association – #{inspection}")
48
48
  end
49
49
 
50
- queries_sql = queries.map { |query|
51
- query = yield query if block_given?
52
- "EXISTS (" + query.to_sql + ")"
53
- }.join(" OR ")
50
+ queries_sql =
51
+ queries.map do |query|
52
+ query = yield query if block_given?
53
+ "EXISTS (" + query.to_sql + ")"
54
+ end
55
+ queries_sql.join(" OR ")
54
56
  end
55
57
 
56
58
  def where_exists_for_belongs_to_query(association, where_parameters)
@@ -59,7 +61,9 @@ module WhereExists
59
61
  association_scope = association.scope
60
62
 
61
63
  if polymorphic
62
- associated_models = self.select("DISTINCT #{connection.quote_column_name(association.foreign_type)}").pluck(association.foreign_type).map(&:constantize)
64
+ associated_models = self.select("DISTINCT #{connection.quote_column_name(association.foreign_type)}").
65
+ where("#{connection.quote_column_name(association.foreign_type)} IS NOT NULL").pluck(association.foreign_type).
66
+ uniq.map(&:classify).map(&:constantize)
63
67
  else
64
68
  associated_models = [association.klass]
65
69
  end
@@ -80,8 +84,10 @@ module WhereExists
80
84
  query = query.instance_exec(&association_scope)
81
85
  end
82
86
  if polymorphic
83
- other_type = connection.quote(associated_model.name)
84
- query = query.where("#{self_type} = #{other_type}")
87
+ other_types = [associated_model.name, associated_model.table_name]
88
+ other_types << associated_model.polymorphic_name if associated_model.respond_to?(:polymorphic_name)
89
+
90
+ query = query.where("#{self_type} IN (?)", other_types.uniq)
85
91
  end
86
92
  queries.push query
87
93
  end
@@ -127,8 +133,14 @@ module WhereExists
127
133
 
128
134
  if association.options[:as]
129
135
  other_types = quote_table_and_column_name(associated_model.table_name, association.type)
130
- self_class = connection.quote(self.name)
131
- result = result.where("#{other_types} = #{self_class}")
136
+ class_values = [self.name, self.table_name]
137
+ class_values << self.polymorphic_name if associated_model.respond_to?(:polymorphic_name)
138
+
139
+ result = result.where("#{other_types} IN (?)", class_values.uniq)
140
+ end
141
+
142
+ if association_scope
143
+ result = result.instance_exec(&association_scope)
132
144
  end
133
145
 
134
146
  if next_association[:association]
@@ -139,10 +151,6 @@ module WhereExists
139
151
  result = result.where(*where_parameters)
140
152
  end
141
153
 
142
- if association_scope
143
- result = result.instance_exec(&association_scope)
144
- end
145
-
146
154
  [result]
147
155
  end
148
156
 
@@ -153,11 +161,9 @@ module WhereExists
153
161
 
154
162
  primary_key = association.options[:primary_key] || self.primary_key
155
163
 
156
- join_table = [self.table_name, associated_model.table_name].sort.join("_")
157
-
158
164
  self_ids = quote_table_and_column_name(self.table_name, primary_key)
159
- join_ids = quote_table_and_column_name(join_table, association.foreign_key)
160
- associated_join_ids = quote_table_and_column_name(join_table, "#{associated_model.name.downcase}_id")
165
+ join_ids = quote_table_and_column_name(association.join_table, association.foreign_key)
166
+ associated_join_ids = quote_table_and_column_name(association.join_table, association.association_foreign_key)
161
167
  associated_ids = quote_table_and_column_name(associated_model.table_name, associated_model.primary_key)
162
168
 
163
169
  result =
@@ -165,7 +171,7 @@ module WhereExists
165
171
  select("1").
166
172
  joins(
167
173
  <<-SQL
168
- INNER JOIN #{connection.quote_table_name(join_table)}
174
+ INNER JOIN #{connection.quote_table_name(association.join_table)}
169
175
  ON #{associated_ids} = #{associated_join_ids}
170
176
  SQL
171
177
  ).
@@ -196,13 +202,13 @@ module WhereExists
196
202
 
197
203
  if next_association[:next_association] && next_association[:next_association][:association]
198
204
  subq = str.match(/\([^\(\)]+\)/mi)[0]
199
- str.sub!(subq,
205
+ str.sub!(subq) do
200
206
  "(#{subq} AND (#{loop_nested_association(
201
207
  next_association[:association],
202
208
  next_association[:next_association],
203
209
  true
204
210
  )}))"
205
- )
211
+ end
206
212
  end
207
213
 
208
214
  nested ? str : [query.where(str)]
@@ -1,3 +1,3 @@
1
1
  module WhereExists
2
- VERSION = "1.1.3"
2
+ VERSION = "1.2.2"
3
3
  end
@@ -60,4 +60,21 @@ 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_table_name_based_lookup
65
+ first_entity = FirstPolymorphicEntity.create!
66
+ second_entity = SecondPolymorphicEntity.create! id: first_entity.id + 1
67
+
68
+ first_child = BelongsToPolymorphicChild.create!(polymorphic_entity_id: first_entity.id, polymorphic_entity_type: first_entity.class.table_name)
69
+ second_child = BelongsToPolymorphicChild.create!(polymorphic_entity_id: second_entity.id, polymorphic_entity_type: second_entity.class.table_name)
70
+ orphaned_child = BelongsToPolymorphicChild.create!(polymorphic_entity_id: second_entity.id, polymorphic_entity_type: first_entity.class.table_name)
71
+
72
+ result = BelongsToPolymorphicChild.where_exists(:polymorphic_entity)
73
+ assert_equal 2, result.length
74
+ assert_equal [first_child, second_child].map(&:id).sort, result.map(&:id).sort
75
+
76
+ result = BelongsToPolymorphicChild.where_not_exists(:polymorphic_entity)
77
+ assert_equal 1, result.length
78
+ assert_equal [orphaned_child].map(&:id).sort, result.map(&:id).sort
79
+ end
63
80
  end
Binary file
@@ -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
@@ -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
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.3
4
+ version: 1.2.2
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-21 00:00:00.000000000 Z
11
+ date: 2020-12-13 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,11 +94,13 @@ 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
100
101
  - test/belongs_to_polymorphic_test.rb
101
102
  - test/belongs_to_test.rb
103
+ - test/db/test.db
102
104
  - test/documentation_test.rb
103
105
  - test/has_and_belongs_to_many.rb
104
106
  - test/has_many_polymorphic_test.rb
@@ -124,17 +126,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
126
  - !ruby/object:Gem::Version
125
127
  version: '0'
126
128
  requirements: []
127
- rubyforge_project:
128
- rubygems_version: 2.6.11
129
+ rubygems_version: 3.0.6
129
130
  signing_key:
130
131
  specification_version: 4
131
132
  summary: "#where_exists extension of ActiveRecord"
132
133
  test_files:
133
- - test/belongs_to_polymorphic_test.rb
134
- - test/belongs_to_test.rb
135
- - test/documentation_test.rb
136
134
  - test/has_and_belongs_to_many.rb
137
- - test/has_many_polymorphic_test.rb
138
- - test/has_many_test.rb
135
+ - test/belongs_to_polymorphic_test.rb
139
136
  - test/has_many_through_test.rb
137
+ - test/db/test.db
140
138
  - test/test_helper.rb
139
+ - test/has_many_polymorphic_test.rb
140
+ - test/has_many_test.rb
141
+ - test/documentation_test.rb
142
+ - test/belongs_to_test.rb