acts_as_favoritor 4.0.2 → 5.0.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 +4 -4
- data/README.md +33 -53
- data/lib/acts_as_favoritor/configuration.rb +1 -2
- data/lib/acts_as_favoritor/favoritable.rb +28 -24
- data/lib/acts_as_favoritor/favoritor.rb +42 -36
- data/lib/acts_as_favoritor/favoritor_lib.rb +2 -6
- data/lib/acts_as_favoritor/version.rb +1 -1
- data/lib/generators/acts_as_favoritor_generator.rb +2 -1
- data/lib/generators/templates/migration.rb.erb +3 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64b49c4243f1a6d24e08294de2ee32e19f7b9587ed7f796c2d9d335e6083025a
|
4
|
+
data.tar.gz: dc8bc1751b08a7c9837a9a7f1ee1bf4f8059401d11147df8b1c8500fa58151fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb5c2de5270701e94c32b22c703796f309e53db7ad56f55a2171fbe9ebd600f4e7d85084fb5152fbb69539b29ecb0bf9d67f24a6f649ec0818c9089f80c17816
|
7
|
+
data.tar.gz: a58a52e5fa812dcc2e985f9be277663be0dc0d4ee3d90e25db362391132e38185e2fe18de6f3a84811b48565afe6caadaad7b38502d998f293ce1d1a2ddecfa2
|
data/README.md
CHANGED
@@ -1,42 +1,22 @@
|
|
1
1
|
# acts_as_favoritor
|
2
2
|
|
3
|
-
[](https://badge.fury.io/rb/acts_as_favoritor) 
|
4
|
-
|
5
3
|
acts_as_favoritor is a Rubygem to allow any ActiveRecord model to associate any other model including the option for multiple relationships per association with scopes.
|
6
4
|
|
7
5
|
You are able to differentiate followers, favorites, watchers, votes and whatever else you can imagine through a single relationship. This is accomplished by a double polymorphic relationship on the Favorite model. There is also built in support for blocking/un-blocking favorite records as well as caching.
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
## Table of Contents
|
12
|
-
|
13
|
-
* [Installation](#installation)
|
14
|
-
* [Usage](#usage)
|
15
|
-
* [Setup](#setup)
|
16
|
-
* [`acts_as_favoritor` methods](#acts_as_favoritor-methods)
|
17
|
-
* [`acts_as_favoritable` methods](#acts_as_favoritable-methods)
|
18
|
-
* [`Favorite` model](#favorite-model)
|
19
|
-
* [Scopes](#scopes)
|
20
|
-
* [Caching](#caching)
|
21
|
-
* [Configuration](#configuration)
|
22
|
-
* [Testing](#testing)
|
23
|
-
* [To do](#to-do)
|
24
|
-
* [Contributing](#contributing)
|
25
|
-
* [Semantic versioning](#semantic-versioning)
|
26
|
-
|
27
|
-
---
|
7
|
+
[This Medium article](https://medium.com/swlh/add-dynamic-like-dislike-buttons-to-your-rails-6-application-ccce8a234c43) gives a good introduction to this gem.
|
28
8
|
|
29
9
|
## Installation
|
30
10
|
|
31
|
-
|
11
|
+
You can add acts_as_favoritor to your `Gemfile` with:
|
32
12
|
|
33
13
|
```ruby
|
34
14
|
gem 'acts_as_favoritor'
|
35
15
|
```
|
36
16
|
|
37
|
-
And then
|
17
|
+
And then run:
|
38
18
|
|
39
|
-
$ bundle
|
19
|
+
$ bundle install
|
40
20
|
|
41
21
|
Or install it yourself as:
|
42
22
|
|
@@ -167,24 +147,25 @@ Using scopes with `acts_as_favoritor` enables you to Follow, Watch, Favorite, [.
|
|
167
147
|
|
168
148
|
By default all of your favorites are scoped to `'favorite'`.
|
169
149
|
|
170
|
-
You can create new scopes on the fly. Every single method takes `scope` as an option which expexts an array containing your scopes
|
150
|
+
You can create new scopes on the fly. Every single method takes `scope`/`scopes` as an option which expexts a symbol or an array of symbols containing your scopes.
|
171
151
|
|
172
152
|
So lets see how this works:
|
173
153
|
|
174
154
|
```ruby
|
175
155
|
user.favorite(book, scopes: [:favorite, :watching])
|
176
|
-
user.unfavorite(book,
|
156
|
+
user.unfavorite(book, scope: :watching)
|
177
157
|
second_user = User.find(2)
|
178
|
-
user.favorite(second_user,
|
158
|
+
user.favorite(second_user, scope: :follow)
|
179
159
|
```
|
180
160
|
|
181
161
|
That's simple!
|
182
162
|
|
183
|
-
When you call a method which returns something while specifying multiple scopes, the method returns the results in a hash with the scopes as keys:
|
163
|
+
When you call a method which returns something while specifying multiple scopes, the method returns the results in a hash with the scopes as keys when scopes are given as an array:
|
184
164
|
|
185
165
|
```ruby
|
186
166
|
user.favorited?(book, scopes: [:favorite, :watching]) # => { favorite: true, watching: false }
|
187
|
-
user.favorited?(book, scopes: [:favorite]) # => true
|
167
|
+
user.favorited?(book, scopes: [:favorite]) # => { favorite: true }
|
168
|
+
user.favorited?(book, scope: :favorite) # => true
|
188
169
|
```
|
189
170
|
|
190
171
|
`acts_as_favoritor` also provides some handy scopes for you to call on the `Favorite` model:
|
@@ -243,7 +224,7 @@ book.favoritable_favorite_cache # => 1
|
|
243
224
|
|
244
225
|
**Note:** These methods are available for every scope you are using.
|
245
226
|
|
246
|
-
|
227
|
+
The total counts all favorites that were recorded, while the score factors in favorites that were removed. In most use cases the score is the most useful.
|
247
228
|
|
248
229
|
## Configuration
|
249
230
|
|
@@ -259,42 +240,41 @@ end
|
|
259
240
|
|
260
241
|
**`cache`** Whether `acts_as_favoritor` uses caching or not. Takes a boolean. Defaults to `false`. Learn more about caching [here](#caching).
|
261
242
|
|
262
|
-
|
243
|
+
## Development
|
263
244
|
|
264
|
-
|
245
|
+
To start development you first have to fork this repository and locally clone your fork.
|
265
246
|
|
266
|
-
|
247
|
+
Install the projects dependencies by running:
|
267
248
|
|
268
|
-
|
269
|
-
2. Clone your forked git locally
|
270
|
-
3. Install dependencies
|
249
|
+
$ bundle install
|
271
250
|
|
272
|
-
|
251
|
+
### Testing
|
273
252
|
|
274
|
-
|
253
|
+
Tests are written with RSpec and can be found in `/spec`.
|
275
254
|
|
276
|
-
|
255
|
+
To run tests:
|
277
256
|
|
278
|
-
|
257
|
+
$ bundle exec rspec
|
279
258
|
|
280
|
-
|
259
|
+
To run RuboCop:
|
281
260
|
|
282
|
-
|
261
|
+
$ bundle exec rubocop
|
283
262
|
|
284
|
-
##
|
285
|
-
|
286
|
-
We use [GitHub projects](https://github.com/jonhue/acts_as_favoritor/projects/1) to coordinate the work on this project.
|
287
|
-
|
288
|
-
To propose your ideas, initiate the discussion by adding a [new issue](https://github.com/jonhue/acts_as_favoritor/issues/new).
|
263
|
+
## Contributing
|
289
264
|
|
290
|
-
|
265
|
+
We warmly welcome everyone who is intersted in contributing. Please reference our [contributing guidelines](CONTRIBUTING.md) and our [Code of Conduct](CODE_OF_CONDUCT.md).
|
291
266
|
|
292
|
-
##
|
267
|
+
## Releases
|
293
268
|
|
294
|
-
|
269
|
+
[Here](https://github.com/jonhue/acts_as_favoritor/releases) you can find details on all past releases. Unreleased breaking changes that are on the current `main` can be found [here](CHANGELOG.md).
|
295
270
|
|
296
|
-
|
271
|
+
acts_as_favoritor follows Semantic Versioning 2.0 as defined at http://semver.org. Reference our [security policy](SECURITY.md).
|
297
272
|
|
298
|
-
###
|
273
|
+
### Publishing
|
299
274
|
|
300
|
-
|
275
|
+
1. Review breaking changes and deprecations in `CHANGELOG.md`.
|
276
|
+
1. Change the gem version in `lib/acts_as_favoritor/version.rb`.
|
277
|
+
1. Reset `CHANGELOG.md`.
|
278
|
+
1. Create a pull request to merge the changes into `main`.
|
279
|
+
1. After the pull request was merged, create a new release listing the breaking changes and commits on `main` since the last release.
|
280
|
+
2. The release workflow will publish the gem to RubyGems.
|
@@ -44,37 +44,39 @@ module ActsAsFavoritor
|
|
44
44
|
method.to_s[/favoritable_(.+)_total/]
|
45
45
|
end
|
46
46
|
|
47
|
-
def favoritors(
|
48
|
-
|
49
|
-
|
47
|
+
def favoritors(scope: ActsAsFavoritor.configuration.default_scope,
|
48
|
+
scopes: nil)
|
49
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
50
|
+
favorited.includes(:favoritor).unblocked.send("#{s}_list")
|
50
51
|
.map(&:favoritor)
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
54
55
|
def favoritors_by_type(favoritor_type,
|
55
|
-
|
56
|
-
|
57
|
-
self.class.build_result_for_scopes
|
56
|
+
scope: ActsAsFavoritor.configuration.default_scope,
|
57
|
+
scopes: nil)
|
58
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
58
59
|
favoritor_type.constantize.includes(:favorites)
|
59
60
|
.where(favorites: {
|
60
61
|
blocked: false, favoritable_id: id,
|
61
|
-
favoritable_type: self.class.name, scope:
|
62
|
+
favoritable_type: self.class.name, scope: s
|
62
63
|
})
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
66
67
|
def favorited_by?(favoritor,
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
scope: ActsAsFavoritor.configuration.default_scope,
|
69
|
+
scopes: nil)
|
70
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
71
|
+
favorited.unblocked.send("#{s}_list").for_favoritor(favoritor)
|
70
72
|
.first.present?
|
71
73
|
end
|
72
74
|
end
|
73
75
|
|
74
|
-
def block(favoritor,
|
75
|
-
scopes:
|
76
|
-
self.class.build_result_for_scopes
|
77
|
-
get_favorite_for(favoritor,
|
76
|
+
def block(favoritor, scope: ActsAsFavoritor.configuration.default_scope,
|
77
|
+
scopes: nil)
|
78
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
79
|
+
get_favorite_for(favoritor, s)&.block! || Favorite.create(
|
78
80
|
favoritable: self,
|
79
81
|
favoritor: favoritor,
|
80
82
|
blocked: true,
|
@@ -83,24 +85,26 @@ module ActsAsFavoritor
|
|
83
85
|
end
|
84
86
|
end
|
85
87
|
|
86
|
-
def unblock(favoritor,
|
87
|
-
scopes:
|
88
|
-
self.class.build_result_for_scopes
|
89
|
-
get_favorite_for(favoritor,
|
88
|
+
def unblock(favoritor, scope: ActsAsFavoritor.configuration.default_scope,
|
89
|
+
scopes: nil)
|
90
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
91
|
+
get_favorite_for(favoritor, s)&.update(blocked: false)
|
90
92
|
end
|
91
93
|
end
|
92
94
|
|
93
95
|
def blocked?(favoritor,
|
94
|
-
|
95
|
-
|
96
|
-
|
96
|
+
scope: ActsAsFavoritor.configuration.default_scope,
|
97
|
+
scopes: nil)
|
98
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
99
|
+
favorited.blocked.send("#{s}_list").for_favoritor(favoritor).first
|
97
100
|
.present?
|
98
101
|
end
|
99
102
|
end
|
100
103
|
|
101
|
-
def blocked(
|
102
|
-
|
103
|
-
|
104
|
+
def blocked(scope: ActsAsFavoritor.configuration.default_scope,
|
105
|
+
scopes: nil)
|
106
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
107
|
+
favorited.includes(:favoritor).blocked.send("#{s}_list")
|
104
108
|
.map(&:favoritor)
|
105
109
|
end
|
106
110
|
end
|
@@ -45,81 +45,89 @@ module ActsAsFavoritor
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def favorite(favoritable,
|
48
|
-
|
49
|
-
|
48
|
+
scope: ActsAsFavoritor.configuration.default_scope,
|
49
|
+
scopes: nil)
|
50
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
50
51
|
return nil if self == favoritable
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
result = favorites.for_favoritable(favoritable).send("#{s}_list")
|
54
|
+
.first_or_create!
|
55
|
+
inc_cache(favoritable, s) if ActsAsFavoritor.configuration.cache
|
56
|
+
result
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
59
60
|
def unfavorite(favoritable,
|
60
|
-
|
61
|
-
|
62
|
-
|
61
|
+
scope: ActsAsFavoritor.configuration.default_scope,
|
62
|
+
scopes: nil)
|
63
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
64
|
+
favorite_record = get_favorite(favoritable, s)
|
63
65
|
return nil unless favorite_record.present?
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
+
result = favorite_record.destroy!
|
68
|
+
dec_cache(favoritable, s) if ActsAsFavoritor.configuration.cache
|
69
|
+
result
|
67
70
|
end
|
68
71
|
end
|
69
72
|
|
70
73
|
def favorited?(favoritable,
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
+
scope: ActsAsFavoritor.configuration.default_scope,
|
75
|
+
scopes: nil)
|
76
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
77
|
+
Favorite.unblocked.send("#{s}_list").for_favoritor(self)
|
74
78
|
.for_favoritable(favoritable).size.positive?
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
78
|
-
def all_favorites(
|
79
|
-
|
80
|
-
|
82
|
+
def all_favorites(scope: ActsAsFavoritor.configuration.default_scope,
|
83
|
+
scopes: nil)
|
84
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
85
|
+
favorites.unblocked.send("#{s}_list")
|
81
86
|
end
|
82
87
|
end
|
83
88
|
|
84
|
-
def all_favorited(
|
85
|
-
|
86
|
-
|
89
|
+
def all_favorited(scope: ActsAsFavoritor.configuration.default_scope,
|
90
|
+
scopes: nil)
|
91
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
92
|
+
favorites.unblocked.send("#{s}_list").includes(:favoritable)
|
87
93
|
.map(&:favoritable)
|
88
94
|
end
|
89
95
|
end
|
90
96
|
|
91
97
|
def favorites_by_type(favoritable_type,
|
92
|
-
|
93
|
-
|
94
|
-
self.class.build_result_for_scopes
|
95
|
-
favorites.unblocked.send("#{
|
98
|
+
scope: ActsAsFavoritor.configuration.default_scope,
|
99
|
+
scopes: nil)
|
100
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
101
|
+
favorites.unblocked.send("#{s}_list")
|
96
102
|
.for_favoritable_type(favoritable_type)
|
97
103
|
end
|
98
104
|
end
|
99
105
|
|
100
106
|
def favorited_by_type(favoritable_type,
|
101
|
-
|
102
|
-
|
103
|
-
self.class.build_result_for_scopes
|
107
|
+
scope: ActsAsFavoritor.configuration.default_scope,
|
108
|
+
scopes: nil)
|
109
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
104
110
|
favoritable_type.constantize.includes(:favorited)
|
105
111
|
.where(favorites: {
|
106
112
|
blocked: false, favoritor_id: id,
|
107
|
-
favoritor_type: self.class.name, scope:
|
113
|
+
favoritor_type: self.class.name, scope: s
|
108
114
|
})
|
109
115
|
end
|
110
116
|
end
|
111
117
|
|
112
118
|
def blocked_by?(favoritable,
|
113
|
-
|
114
|
-
|
115
|
-
|
119
|
+
scope: ActsAsFavoritor.configuration.default_scope,
|
120
|
+
scopes: nil)
|
121
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
122
|
+
Favorite.blocked.send("#{s}_list").for_favoritor(self)
|
116
123
|
.for_favoritable(favoritable).size.positive?
|
117
124
|
end
|
118
125
|
end
|
119
126
|
|
120
|
-
def blocked_by(
|
121
|
-
|
122
|
-
|
127
|
+
def blocked_by(scope: ActsAsFavoritor.configuration.default_scope,
|
128
|
+
scopes: nil)
|
129
|
+
self.class.build_result_for_scopes(scopes || scope) do |s|
|
130
|
+
favorites.includes(:favoritable).blocked.send("#{s}_list")
|
123
131
|
.map(&:favoritable)
|
124
132
|
end
|
125
133
|
end
|
@@ -151,9 +159,7 @@ module ActsAsFavoritor
|
|
151
159
|
|
152
160
|
favoritable.favoritable_score[scope] =
|
153
161
|
(favoritable.favoritable_score[scope] || 0) - 1
|
154
|
-
# rubocop:disable Metrics/LineLength
|
155
162
|
favoritable.favoritable_score.delete(scope) unless favoritable.favoritable_score[scope].positive?
|
156
|
-
# rubocop:enable Metrics/LineLength
|
157
163
|
favoritable.save!
|
158
164
|
end
|
159
165
|
# rubocop:enable Metrics/AbcSize
|
@@ -3,14 +3,10 @@
|
|
3
3
|
module ActsAsFavoritor
|
4
4
|
module FavoritorLib
|
5
5
|
def build_result_for_scopes(scopes)
|
6
|
+
return yield(scopes) unless scopes.is_a?(Array)
|
6
7
|
return if scopes.empty?
|
7
8
|
|
8
|
-
scopes
|
9
|
-
result = scopes.map { |scope| [scope, yield(scope)] }.to_h
|
10
|
-
|
11
|
-
return result[scopes.first] if scopes.size == 1
|
12
|
-
|
13
|
-
result
|
9
|
+
sanitized_scopes(scopes).map { |scope| [scope, yield(scope)] }.to_h
|
14
10
|
end
|
15
11
|
|
16
12
|
private
|
@@ -13,7 +13,8 @@ class ActsAsFavoritorGenerator < Rails::Generators::Base
|
|
13
13
|
if ActiveRecord::Base.timestamped_migrations
|
14
14
|
Time.now.utc.strftime('%Y%m%d%H%M%S')
|
15
15
|
else
|
16
|
-
format('
|
16
|
+
format('%<migration_number>.3d',
|
17
|
+
migration_number: current_migration_number(dirname) + 1)
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
@@ -18,6 +18,9 @@ class ActsAsFavoritorMigration < ActiveRecord::Migration<%= migration_version %>
|
|
18
18
|
add_index :favorites,
|
19
19
|
['favoritable_id', 'favoritable_type'],
|
20
20
|
name: 'fk_favoritables'
|
21
|
+
add_index :favorites,
|
22
|
+
['favoritable_id', 'favoritor_id', 'favoritable_type'],
|
23
|
+
name: 'uniq_favorites__and_favoritables', unique: true
|
21
24
|
end
|
22
25
|
|
23
26
|
def self.down
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_favoritor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonas Hübotter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -128,7 +128,7 @@ description: acts_as_favoritor is a Rubygem to allow any ActiveRecord model to a
|
|
128
128
|
and whatever else you can imagine through a single relationship. This is accomplished
|
129
129
|
by a double polymorphic relationship on the Favorite model. There is also built
|
130
130
|
in support for blocking/un-blocking favorite records as well as caching.
|
131
|
-
email:
|
131
|
+
email: jonas.huebotter@gmail.com
|
132
132
|
executables: []
|
133
133
|
extensions: []
|
134
134
|
extra_rdoc_files: []
|
@@ -159,14 +159,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
159
159
|
requirements:
|
160
160
|
- - ">="
|
161
161
|
- !ruby/object:Gem::Version
|
162
|
-
version: '2.
|
162
|
+
version: '2.5'
|
163
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
164
|
requirements:
|
165
165
|
- - ">="
|
166
166
|
- !ruby/object:Gem::Version
|
167
167
|
version: '0'
|
168
168
|
requirements: []
|
169
|
-
rubygems_version: 3.
|
169
|
+
rubygems_version: 3.2.22
|
170
170
|
signing_key:
|
171
171
|
specification_version: 4
|
172
172
|
summary: A Rubygem to add Favorite, Follow, Vote, etc. functionality to ActiveRecord
|