acts_as_favoritor 4.0.3 → 5.0.3

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: 45ca952d9906033e84ecc6ff24aca3934457d803c51f979d59c561847b1d61d6
4
- data.tar.gz: 941c85b77b52b66360a6ba7df70227c2e7cc32fc5fe0230f6191e2d20e6afd3e
3
+ metadata.gz: c785314efa34b1f88cfee3d6c39acef924fb989e6a2654c65241a07facd707b0
4
+ data.tar.gz: 28dfbd0a05eab1723e871df1aec6657aabae38875402f03f5f2347ccedb7bc22
5
5
  SHA512:
6
- metadata.gz: bae098e81f7b219469fd3e2a18446914f46fe9ba65edc58f8f36ecd1ade9393f9a877ea8b96795abb4bd7324357fac01bdf2910a630a58828b9c5a984914076c
7
- data.tar.gz: 0adfa2859658a591c472279295197c7c97bf3af1157210e992fafa384fc0dd083c6e7f3b791395b84e0638b25ff25c8ab25a20ee04996ec1975fe75df0b0b1f1
6
+ metadata.gz: af2a517dc943fa69ea7d5442beced5d086a31a9586e1587fecf4ae3c0ad57ab9579099731ec5d92e794075b3d804e0facf7605fa196cdb3531edfb1f4d9855d0
7
+ data.tar.gz: 5e19c65f8f122686cf452f3690f18856e0e235d443e0772c8e4c4468d1b43bea2a46653e495f68d18dc0591ac6e725c2f53f8e3de7cbc5f6ddc0c2b89b9664a4
data/README.md CHANGED
@@ -4,38 +4,19 @@ acts_as_favoritor is a Rubygem to allow any ActiveRecord model to associate any
4
4
 
5
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.
6
6
 
7
- ---
8
-
9
- ## Table of Contents
10
-
11
- * [Installation](#installation)
12
- * [Usage](#usage)
13
- * [Setup](#setup)
14
- * [`acts_as_favoritor` methods](#acts_as_favoritor-methods)
15
- * [`acts_as_favoritable` methods](#acts_as_favoritable-methods)
16
- * [`Favorite` model](#favorite-model)
17
- * [Scopes](#scopes)
18
- * [Caching](#caching)
19
- * [Configuration](#configuration)
20
- * [Testing](#testing)
21
- * [Release](#release)
22
- * [To do](#to-do)
23
- * [Contributing](#contributing)
24
- * [Semantic versioning](#semantic-versioning)
25
-
26
- ---
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.
27
8
 
28
9
  ## Installation
29
10
 
30
- acts_as_favoritor works with Rails 5.0 onwards. You can add it to your `Gemfile` with:
11
+ You can add acts_as_favoritor to your `Gemfile` with:
31
12
 
32
13
  ```ruby
33
14
  gem 'acts_as_favoritor'
34
15
  ```
35
16
 
36
- And then execute:
17
+ And then run:
37
18
 
38
- $ bundle
19
+ $ bundle install
39
20
 
40
21
  Or install it yourself as:
41
22
 
@@ -166,24 +147,25 @@ Using scopes with `acts_as_favoritor` enables you to Follow, Watch, Favorite, [.
166
147
 
167
148
  By default all of your favorites are scoped to `'favorite'`.
168
149
 
169
- You can create new scopes on the fly. Every single method takes `scope` as an option which expexts an array containing your scopes as strings.
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.
170
151
 
171
152
  So lets see how this works:
172
153
 
173
154
  ```ruby
174
155
  user.favorite(book, scopes: [:favorite, :watching])
175
- user.unfavorite(book, scopes: [:watching])
156
+ user.unfavorite(book, scope: :watching)
176
157
  second_user = User.find(2)
177
- user.favorite(second_user, scopes: [:follow])
158
+ user.favorite(second_user, scope: :follow)
178
159
  ```
179
160
 
180
161
  That's simple!
181
162
 
182
- 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:
183
164
 
184
165
  ```ruby
185
166
  user.favorited?(book, scopes: [:favorite, :watching]) # => { favorite: true, watching: false }
186
- user.favorited?(book, scopes: [:favorite]) # => true
167
+ user.favorited?(book, scopes: [:favorite]) # => { favorite: true }
168
+ user.favorited?(book, scope: :favorite) # => true
187
169
  ```
188
170
 
189
171
  `acts_as_favoritor` also provides some handy scopes for you to call on the `Favorite` model:
@@ -242,7 +224,7 @@ book.favoritable_favorite_cache # => 1
242
224
 
243
225
  **Note:** These methods are available for every scope you are using.
244
226
 
245
- ---
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.
246
228
 
247
229
  ## Configuration
248
230
 
@@ -258,51 +240,41 @@ end
258
240
 
259
241
  **`cache`** Whether `acts_as_favoritor` uses caching or not. Takes a boolean. Defaults to `false`. Learn more about caching [here](#caching).
260
242
 
261
- ---
243
+ ## Development
262
244
 
263
- ## Testing
245
+ To start development you first have to fork this repository and locally clone your fork.
264
246
 
265
- 1. Fork this repository
266
- 2. Clone your forked git locally
267
- 3. Install dependencies
247
+ Install the projects dependencies by running:
268
248
 
269
- `$ bundle install`
249
+ $ bundle install
270
250
 
271
- 4. Run tests
251
+ ### Testing
272
252
 
273
- `$ bundle exec rspec`
253
+ Tests are written with RSpec and can be found in `/spec`.
274
254
 
275
- 5. Run RuboCop
255
+ To run tests:
276
256
 
277
- `$ bundle exec rubocop`
257
+ $ bundle exec rspec
278
258
 
279
- ---
259
+ To run RuboCop:
280
260
 
281
- ## Release
261
+ $ bundle exec rubocop
282
262
 
283
- 1. Review breaking changes and deprecations in `CHANGELOG.md`
284
- 2. Change the gem version in `lib/acts_as_favoritor/version.rb`
285
- 3. Reset `CHANGELOG.md`
286
- 4. Create a pull request to merge the changes into `master`
287
- 5. After the pull request was merged, create a new release listing the breaking changes and commits on `master` since the last release.
288
- 6. The release workflow will publish the gems to RubyGems and the GitHub Package Registry
289
-
290
- ---
291
-
292
- ## To do
293
-
294
- We use [GitHub projects](https://github.com/jonhue/acts_as_favoritor/projects/1) to coordinate the work on this project.
295
-
296
- To propose your ideas, initiate the discussion by adding a [new issue](https://github.com/jonhue/acts_as_favoritor/issues/new).
263
+ ## Contributing
297
264
 
298
- ---
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).
299
266
 
300
- ## Contributing
267
+ ## Releases
301
268
 
302
- We hope that you will consider contributing to acts_as_favoritor. Please read this short overview for some information about how to get started:
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).
303
270
 
304
- [Learn more about contributing to this repository](CONTRIBUTING.md), [Code of Conduct](CODE_OF_CONDUCT.md)
271
+ acts_as_favoritor follows Semantic Versioning 2.0 as defined at http://semver.org. Reference our [security policy](SECURITY.md).
305
272
 
306
- ### Semantic Versioning
273
+ ### Publishing
307
274
 
308
- acts_as_favoritor follows Semantic Versioning 2.0 as defined at http://semver.org.
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.
@@ -14,8 +14,7 @@ module ActsAsFavoritor
14
14
  DEFAULT_SCOPE = :favorite
15
15
  DEFAULT_CACHE = false
16
16
 
17
- attr_accessor :default_scope
18
- attr_accessor :cache
17
+ attr_accessor :cache, :default_scope
19
18
 
20
19
  def initialize
21
20
  @default_scope = DEFAULT_SCOPE
@@ -44,37 +44,39 @@ module ActsAsFavoritor
44
44
  method.to_s[/favoritable_(.+)_total/]
45
45
  end
46
46
 
47
- def favoritors(scopes: [ActsAsFavoritor.configuration.default_scope])
48
- self.class.build_result_for_scopes scopes do |scope|
49
- favorited.includes(:favoritor).unblocked.send("#{scope}_list")
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
- scopes: [ActsAsFavoritor.configuration
56
- .default_scope])
57
- self.class.build_result_for_scopes scopes do |scope|
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: 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
- scopes: [ActsAsFavoritor.configuration.default_scope])
68
- self.class.build_result_for_scopes scopes do |scope|
69
- favorited.unblocked.send("#{scope}_list").for_favoritor(favoritor)
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: [ActsAsFavoritor.configuration.default_scope])
76
- self.class.build_result_for_scopes scopes do |scope|
77
- get_favorite_for(favoritor, scope)&.block! || Favorite.create(
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: [ActsAsFavoritor.configuration.default_scope])
88
- self.class.build_result_for_scopes scopes do |scope|
89
- get_favorite_for(favoritor, scope)&.update(blocked: false)
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
- scopes: [ActsAsFavoritor.configuration.default_scope])
95
- self.class.build_result_for_scopes scopes do |scope|
96
- favorited.blocked.send("#{scope}_list").for_favoritor(favoritor).first
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(scopes: [ActsAsFavoritor.configuration.default_scope])
102
- self.class.build_result_for_scopes scopes do |scope|
103
- favorited.includes(:favoritor).blocked.send("#{scope}_list")
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,90 @@ module ActsAsFavoritor
45
45
  end
46
46
 
47
47
  def favorite(favoritable,
48
- scopes: [ActsAsFavoritor.configuration.default_scope])
49
- self.class.build_result_for_scopes scopes do |scope|
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
- inc_cache(favoritable, scope) if ActsAsFavoritor.configuration.cache
53
-
54
- favorites.for_favoritable(favoritable).send("#{scope}_list")
55
- .first_or_create!
53
+ favorites.for_favoritable(favoritable).send("#{s}_list")
54
+ .first_or_create! do |new_record|
55
+ inc_cache(favoritable, s) if ActsAsFavoritor.configuration.cache
56
+ new_record
57
+ end
56
58
  end
57
59
  end
58
60
 
59
61
  def unfavorite(favoritable,
60
- scopes: [ActsAsFavoritor.configuration.default_scope])
61
- self.class.build_result_for_scopes scopes do |scope|
62
- favorite_record = get_favorite(favoritable, scope)
62
+ scope: ActsAsFavoritor.configuration.default_scope,
63
+ scopes: nil)
64
+ self.class.build_result_for_scopes(scopes || scope) do |s|
65
+ favorite_record = get_favorite(favoritable, s)
63
66
  return nil unless favorite_record.present?
64
67
 
65
- dec_cache(favoritable, scope) if ActsAsFavoritor.configuration.cache
66
- favorite_record.destroy!
68
+ result = favorite_record.destroy!
69
+ dec_cache(favoritable, s) if ActsAsFavoritor.configuration.cache && result.destroyed?
70
+ result
67
71
  end
68
72
  end
69
73
 
70
74
  def favorited?(favoritable,
71
- scopes: [ActsAsFavoritor.configuration.default_scope])
72
- self.class.build_result_for_scopes scopes do |scope|
73
- Favorite.unblocked.send("#{scope}_list").for_favoritor(self)
75
+ scope: ActsAsFavoritor.configuration.default_scope,
76
+ scopes: nil)
77
+ self.class.build_result_for_scopes(scopes || scope) do |s|
78
+ Favorite.unblocked.send("#{s}_list").for_favoritor(self)
74
79
  .for_favoritable(favoritable).size.positive?
75
80
  end
76
81
  end
77
82
 
78
- def all_favorites(scopes: [ActsAsFavoritor.configuration.default_scope])
79
- self.class.build_result_for_scopes scopes do |scope|
80
- favorites.unblocked.send("#{scope}_list")
83
+ def all_favorites(scope: ActsAsFavoritor.configuration.default_scope,
84
+ scopes: nil)
85
+ self.class.build_result_for_scopes(scopes || scope) do |s|
86
+ favorites.unblocked.send("#{s}_list")
81
87
  end
82
88
  end
83
89
 
84
- def all_favorited(scopes: [ActsAsFavoritor.configuration.default_scope])
85
- self.class.build_result_for_scopes scopes do |scope|
86
- favorites.unblocked.send("#{scope}_list").includes(:favoritable)
90
+ def all_favorited(scope: ActsAsFavoritor.configuration.default_scope,
91
+ scopes: nil)
92
+ self.class.build_result_for_scopes(scopes || scope) do |s|
93
+ favorites.unblocked.send("#{s}_list").includes(:favoritable)
87
94
  .map(&:favoritable)
88
95
  end
89
96
  end
90
97
 
91
98
  def favorites_by_type(favoritable_type,
92
- scopes: [ActsAsFavoritor.configuration
93
- .default_scope])
94
- self.class.build_result_for_scopes scopes do |scope|
95
- favorites.unblocked.send("#{scope}_list")
99
+ scope: ActsAsFavoritor.configuration.default_scope,
100
+ scopes: nil)
101
+ self.class.build_result_for_scopes(scopes || scope) do |s|
102
+ favorites.unblocked.send("#{s}_list")
96
103
  .for_favoritable_type(favoritable_type)
97
104
  end
98
105
  end
99
106
 
100
107
  def favorited_by_type(favoritable_type,
101
- scopes: [ActsAsFavoritor.configuration
102
- .default_scope])
103
- self.class.build_result_for_scopes scopes do |scope|
108
+ scope: ActsAsFavoritor.configuration.default_scope,
109
+ scopes: nil)
110
+ self.class.build_result_for_scopes(scopes || scope) do |s|
104
111
  favoritable_type.constantize.includes(:favorited)
105
112
  .where(favorites: {
106
113
  blocked: false, favoritor_id: id,
107
- favoritor_type: self.class.name, scope: scope
114
+ favoritor_type: self.class.name, scope: s
108
115
  })
109
116
  end
110
117
  end
111
118
 
112
119
  def blocked_by?(favoritable,
113
- scopes: [ActsAsFavoritor.configuration.default_scope])
114
- self.class.build_result_for_scopes scopes do |scope|
115
- Favorite.blocked.send("#{scope}_list").for_favoritor(self)
120
+ scope: ActsAsFavoritor.configuration.default_scope,
121
+ scopes: nil)
122
+ self.class.build_result_for_scopes(scopes || scope) do |s|
123
+ Favorite.blocked.send("#{s}_list").for_favoritor(self)
116
124
  .for_favoritable(favoritable).size.positive?
117
125
  end
118
126
  end
119
127
 
120
- def blocked_by(scopes: [ActsAsFavoritor.configuration.default_scope])
121
- self.class.build_result_for_scopes scopes do |scope|
122
- favorites.includes(:favoritable).blocked.send("#{scope}_list")
128
+ def blocked_by(scope: ActsAsFavoritor.configuration.default_scope,
129
+ scopes: nil)
130
+ self.class.build_result_for_scopes(scopes || scope) do |s|
131
+ favorites.includes(:favoritable).blocked.send("#{s}_list")
123
132
  .map(&:favoritable)
124
133
  end
125
134
  end
@@ -151,9 +160,7 @@ module ActsAsFavoritor
151
160
 
152
161
  favoritable.favoritable_score[scope] =
153
162
  (favoritable.favoritable_score[scope] || 0) - 1
154
- unless favoritable.favoritable_score[scope].positive?
155
- favoritable.favoritable_score.delete(scope)
156
- end
163
+ favoritable.favoritable_score.delete(scope) unless favoritable.favoritable_score[scope].positive?
157
164
  favoritable.save!
158
165
  end
159
166
  # 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 = sanitized_scopes(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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActsAsFavoritor
4
- VERSION = '4.0.3'
4
+ VERSION = '5.0.3'
5
5
  end
@@ -18,6 +18,10 @@ 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_type', 'favoritable_id', 'favoritor_type',
23
+ 'favoritor_id', 'scope'],
24
+ name: 'uniq_favorites__and_favoritables', unique: true
21
25
  end
22
26
 
23
27
  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.0.3
4
+ version: 5.0.3
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: 2019-10-10 00:00:00.000000000 Z
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: me@jonhue.me
131
+ email: jonas.huebotter@gmail.com
132
132
  executables: []
133
133
  extensions: []
134
134
  extra_rdoc_files: []
@@ -166,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
166
  - !ruby/object:Gem::Version
167
167
  version: '0'
168
168
  requirements: []
169
- rubygems_version: 3.0.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