association_scope 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6737d583c54a2ce44c51f9313544bc2b73d5d083b86fa502b6e82bbca3c48d1
4
- data.tar.gz: b85b28120cf9b7ac32a92f47db2ce4526391734188e9c13fcdfcb0762c177ba3
3
+ metadata.gz: 67d2f037f4c3007105757fe5b90f5307eb56614979e7cd4fa83d9036b5584321
4
+ data.tar.gz: d775072058420799584cf18dc27d80c246070dfd2ae1246e084f0a25acf3aa44
5
5
  SHA512:
6
- metadata.gz: 162342ebf690b58e11a7ebb201073ac17bbeec4bd57e4b51c5f88a1ee2b1077182e98430e604d343fc31a237f615cafd7a736fcf99beb700dd4ee004d401d74f
7
- data.tar.gz: 17e05e72a62217351f2d7bca06d6e0d2477ee9445df53cfb16681e728630cca3e6b2309b490fb50d6e5d6d175e1e0d7ecbb65fd81889eb54cdc714ff219006a9
6
+ metadata.gz: 5aa81882d47e6207b82deb659f43f3010e83d985fe1bed9a411e29c5796082509c4d19f4435bfdbb9d8a636878c06ac3dde49e7543bf5f7b7db38ec4583d0504
7
+ data.tar.gz: 22d3f940c21d6e1722eef994d0294a80d6e3f80a87a3bbadba1f457f1eeb6ef54fecc6ef3c9d761100213dcdc669f04c5f242cc8e95f4546151639f15727eb25
data/README.md CHANGED
@@ -19,7 +19,7 @@ class Topic < ApplicationRecord
19
19
  scope :of_users, -> (users) { joins(:user).where(users: users) }
20
20
  end
21
21
  ```
22
- over and over again across all of my models to write `Topic.of_users(current_user.friends)` when I wanted to write `current_user.friends.topics` instead.
22
+ over and over again across all of my models to write something like `Topic.of_users(current_user.friends)` when I wanted to write `current_user.friends.topics` instead.
23
23
  And `belongs_to` is the easiest part.
24
24
 
25
25
  When you have this problem, the AssociationScope gem is for you!
@@ -57,6 +57,23 @@ Topic.all.users
57
57
  ```
58
58
  to retrieve the users of all of the topics of your application.
59
59
 
60
+ ### Migration from `.of_model`
61
+ When you already use any form of `.of_model` scope, you can replace it with association scopes:
62
+
63
+ ```ruby
64
+ # replace
65
+ Topic.of_users(current_user.friends)
66
+ # with
67
+ current_user.friends.topics
68
+ ```
69
+ When you chain scopes, you have to merge with the previous scope:
70
+ ```ruby
71
+ # replace
72
+ scope.of_users(users)
73
+ # with
74
+ users.topics.merge(scope)
75
+ ```
76
+
60
77
  ## Known Issues
61
78
  * This gem works with `reflections`.
62
79
  To make this work, the `has_association_scope_on` call has to be below your association definitions.
@@ -11,7 +11,7 @@ module AssociationScope
11
11
  end
12
12
 
13
13
  def message
14
- "Association #{association} missing in #{missing_in}!"
14
+ "Association :#{association} missing in #{missing_in}!"
15
15
  end
16
16
  end
17
17
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AssociationScope
4
+ class PolymorphicAssociationError < StandardError
5
+ attr_accessor :association,
6
+ :model
7
+
8
+ def initialize(association: nil, model: nil)
9
+ @association = association
10
+ @model = model
11
+ end
12
+
13
+ def message
14
+ "Association :#{association} is polymorph in #{model}!"
15
+ end
16
+ end
17
+ end
@@ -4,22 +4,16 @@ module AssociationScope
4
4
  class Scope
5
5
  class BelongsToReflection < Scope
6
6
  def apply
7
+ if reflection_details.options[:polymorphic]
8
+ raise PolymorphicAssociationError.new association: association, model: model
9
+ end
10
+
7
11
  association = @association
8
- details = model.reflections[association]
9
- class_name = details.options[:class_name]&.constantize || association.camelize.constantize
12
+ class_name = reflection_details.options[:class_name]&.constantize || association.camelize.constantize
13
+ foreign_key = reflection_details.options[:foreign_key]
10
14
  association_name = association.to_s.underscore.to_sym
11
- foreign_key = details.options[:foreign_key]
12
15
  own_table_name = class_name.to_s.pluralize.underscore
13
-
14
- inverse_reflection = class_name.reflections[model.to_s.underscore.singularize] || class_name.reflections[model.to_s.underscore.pluralize]
15
- case inverse_reflection&.source_reflection&.class&.to_s&.split("::")&.last
16
- when "HasOneReflection"
17
- table_name = model.to_s.underscore.to_sym
18
- when "HasManyReflection"
19
- table_name = model.to_s.underscore.pluralize.to_sym
20
- else
21
- raise AssociationMissingError.new missing_in: class_name, association: model.to_s.underscore.pluralize
22
- end
16
+ table_name = table_name class_name
23
17
 
24
18
  model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
25
19
  scope association.pluralize, -> do
@@ -36,6 +30,27 @@ module AssociationScope
36
30
  end
37
31
  RUBY
38
32
  end
33
+
34
+ private
35
+
36
+ def table_name(class_name)
37
+ case inverse_reflection(class_name)&.source_reflection&.class&.to_s&.split("::")&.last
38
+ when "HasOneReflection"
39
+ model.to_s.underscore.to_sym
40
+ when "HasManyReflection"
41
+ model.to_s.underscore.pluralize.to_sym
42
+ else
43
+ raise AssociationMissingError.new missing_in: class_name, association: model.to_s.underscore.pluralize
44
+ end
45
+ end
46
+
47
+ def inverse_reflection(class_name)
48
+ class_name.reflections[model.to_s.underscore.singularize] || class_name.reflections[model.to_s.underscore.pluralize]
49
+ end
50
+
51
+ def reflection_details
52
+ model.reflections[association]
53
+ end
39
54
  end
40
55
  end
41
56
  end
@@ -5,13 +5,12 @@ module AssociationScope
5
5
  class HasAndBelongsToManyReflection < Scope
6
6
  def apply
7
7
  association = @association.pluralize
8
- details = model.reflections[association]
9
- class_name = details.options[:class_name]&.constantize || association.singularize.camelize.constantize
8
+ class_name = reflection_details.options[:class_name]&.constantize || association.singularize.camelize.constantize
10
9
  table_name = model.to_s.underscore.pluralize.to_sym
11
10
 
12
- model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
13
- raise AssociationMissingError.new(missing_in: class_name, association: table_name) unless class_name.reflections.has_key?(table_name.to_s)
11
+ raise AssociationMissingError.new(missing_in: class_name, association: table_name) unless class_name.reflections.has_key?(table_name.to_s)
14
12
 
13
+ model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
15
14
  scope association, -> do
16
15
  class_name
17
16
  .joins(table_name)
@@ -20,6 +19,12 @@ module AssociationScope
20
19
  end
21
20
  RUBY
22
21
  end
22
+
23
+ private
24
+
25
+ def reflection_details
26
+ model.reflections[association]
27
+ end
23
28
  end
24
29
  end
25
30
  end
@@ -4,14 +4,14 @@ module AssociationScope
4
4
  class Scope
5
5
  class HasManyReflection < Scope
6
6
  def apply
7
- details = model.reflections[@association]
8
- class_name = details.options[:class_name]&.constantize || association.singularize.camelize.constantize
7
+ class_name = reflection_details.options[:class_name]&.constantize || association.singularize.camelize.constantize
8
+
9
9
  association = @association.pluralize
10
- column_name = model.to_s.underscore
10
+ column_name = reflection_details.options[:as] || model.to_s.underscore
11
11
 
12
- model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
13
- raise AssociationMissingError.new(missing_in: class_name, association: column_name) unless class_name.reflections.has_key?(column_name)
12
+ raise AssociationMissingError.new(missing_in: class_name, association: column_name) unless class_name.reflections.has_key?(column_name.to_s)
14
13
 
14
+ model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
15
15
  scope association, -> do
16
16
  class_name
17
17
  .where(column_name => self)
@@ -19,6 +19,12 @@ module AssociationScope
19
19
  end
20
20
  RUBY
21
21
  end
22
+
23
+ private
24
+
25
+ def reflection_details
26
+ model.reflections[@association]
27
+ end
22
28
  end
23
29
  end
24
30
  end
@@ -3,6 +3,7 @@
3
3
  module AssociationScope
4
4
  class Scope
5
5
  class HasOneReflection < HasManyReflection
6
+ # works the same way like has_many reflections
6
7
  end
7
8
  end
8
9
  end
@@ -4,24 +4,14 @@ module AssociationScope
4
4
  class Scope
5
5
  class ThroughReflection < Scope
6
6
  def apply
7
- details = model.reflections[@association]
8
7
  association = @association
9
- class_name = details.options[:class_name]&.constantize || association.singularize.camelize.constantize
8
+ class_name = reflection_details.options[:class_name]&.constantize || association.singularize.camelize.constantize
9
+ first_join = inverse_reflection(class_name)&.options&.fetch(:through, nil) || inverse_reflection(class_name)&.options&.fetch(:source, nil)
10
+ second_join = compute_second_join class_name
10
11
 
11
- inverse = details.options[:inverse_of]&.to_s || model.to_s.underscore
12
- inverse_reflection = class_name.reflections[inverse.singularize] || class_name.reflections[inverse.pluralize]
13
-
14
- first_join = inverse_reflection&.options&.fetch(:through, nil) || inverse_reflection&.options&.fetch(:source, nil)
15
-
16
- reflection_type = inverse_reflection&.source_reflection&.class&.to_s&.split("::")&.last
17
- second_join = if %w[HasOneReflection BelongsToReflection].include?(reflection_type)
18
- model.to_s.underscore.to_sym
19
- else
20
- model.to_s.underscore.pluralize.to_sym
21
- end
12
+ raise AssociationMissingError.new missing_in: class_name, association: inverse unless inverse_reflection(class_name)
22
13
 
23
14
  model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
24
- raise AssociationMissingError.new missing_in: class_name, association: inverse unless inverse_reflection
25
15
  scope association.pluralize, -> do
26
16
  class_name
27
17
  .joins(first_join => second_join)
@@ -29,6 +19,32 @@ module AssociationScope
29
19
  end
30
20
  RUBY
31
21
  end
22
+
23
+ private
24
+
25
+ def reflection_details
26
+ model.reflections[association]
27
+ end
28
+
29
+ def inverse
30
+ reflection_details.options[:inverse_of]&.to_s || model.to_s.underscore
31
+ end
32
+
33
+ def inverse_reflection class_name
34
+ class_name.reflections[inverse.singularize] || class_name.reflections[inverse.pluralize]
35
+ end
36
+
37
+ def reflection_type class_name
38
+ inverse_reflection(class_name)&.source_reflection&.class&.to_s&.split("::")&.last
39
+ end
40
+
41
+ def compute_second_join class_name
42
+ if %w[HasOneReflection BelongsToReflection].include?(reflection_type(class_name))
43
+ model.to_s.underscore.to_sym
44
+ else
45
+ model.to_s.underscore.pluralize.to_sym
46
+ end
47
+ end
32
48
  end
33
49
  end
34
50
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AssociationScope
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -9,6 +9,7 @@ require "association_scope/scope/has_and_belongs_to_many_reflection"
9
9
  require "association_scope/scope/through_reflection"
10
10
 
11
11
  require "association_scope/errors/association_missing_error"
12
+ require "association_scope/errors/polymorphic_association_error"
12
13
 
13
14
  module AssociationScope
14
15
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: association_scope
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - datae
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-07 00:00:00.000000000 Z
11
+ date: 2021-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: awesome_print
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.9.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.9.2
69
83
  description: AssociationScope adds useful scopes targeting Associations in ActiveRecord.
70
84
  email:
71
85
  - accounts@datae.de
@@ -78,6 +92,7 @@ files:
78
92
  - Rakefile
79
93
  - lib/association_scope.rb
80
94
  - lib/association_scope/errors/association_missing_error.rb
95
+ - lib/association_scope/errors/polymorphic_association_error.rb
81
96
  - lib/association_scope/scope.rb
82
97
  - lib/association_scope/scope/belongs_to_reflection.rb
83
98
  - lib/association_scope/scope/has_and_belongs_to_many_reflection.rb
@@ -100,14 +115,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
100
115
  requirements:
101
116
  - - ">="
102
117
  - !ruby/object:Gem::Version
103
- version: '0'
118
+ version: 2.6.8
104
119
  required_rubygems_version: !ruby/object:Gem::Requirement
105
120
  requirements:
106
121
  - - ">="
107
122
  - !ruby/object:Gem::Version
108
123
  version: '0'
109
124
  requirements: []
110
- rubygems_version: 3.1.4
125
+ rubygems_version: 3.2.25
111
126
  signing_key:
112
127
  specification_version: 4
113
128
  summary: AssociationScope adds useful scopes targeting Associations in ActiveRecord.