acts_as_favoritor 4.0.2 → 5.0.2

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: ba4bae7bff5166a5903eccb9ed03fdc8905844309dac8b509d805dc945f09a4e
4
- data.tar.gz: 61061b39d5f29094fe329c00aac91df4988667522c945f859c4762381da4a117
3
+ metadata.gz: 64b49c4243f1a6d24e08294de2ee32e19f7b9587ed7f796c2d9d335e6083025a
4
+ data.tar.gz: dc8bc1751b08a7c9837a9a7f1ee1bf4f8059401d11147df8b1c8500fa58151fb
5
5
  SHA512:
6
- metadata.gz: eb97712eb98769614cd99a910633ec0b397feec7d55282f42884915c8246732f0b1b611ace2dae13c5360c998ba49f3ac02b0c9a8a7421b9ac2a3e57714493e0
7
- data.tar.gz: 726d2a2aec78589821dabc017d5f53b8a142d961a3caa21eae436d5d6cbda4b231d613305ae8099aae4340addc09be508b68d09479b104d199c3fc586ec1c0cc
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
- [![Gem Version](https://badge.fury.io/rb/acts_as_favoritor.svg)](https://badge.fury.io/rb/acts_as_favoritor) ![Travis](https://travis-ci.org/jonhue/acts_as_favoritor.svg?branch=master)
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
- 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:
32
12
 
33
13
  ```ruby
34
14
  gem 'acts_as_favoritor'
35
15
  ```
36
16
 
37
- And then execute:
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 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.
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, scopes: [:watching])
156
+ user.unfavorite(book, scope: :watching)
177
157
  second_user = User.find(2)
178
- user.favorite(second_user, scopes: [:follow])
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
- ## Testing
245
+ To start development you first have to fork this repository and locally clone your fork.
265
246
 
266
- Tests are written with Shoulda on top of `Test::Unit` with Factory Girl being used instead of fixtures. Tests are run using rake.
247
+ Install the projects dependencies by running:
267
248
 
268
- 1. Fork this repository
269
- 2. Clone your forked git locally
270
- 3. Install dependencies
249
+ $ bundle install
271
250
 
272
- `$ bundle install`
251
+ ### Testing
273
252
 
274
- 4. Run tests
253
+ Tests are written with RSpec and can be found in `/spec`.
275
254
 
276
- `$ bundle exec rspec`
255
+ To run tests:
277
256
 
278
- 5. Run RuboCop
257
+ $ bundle exec rspec
279
258
 
280
- `$ bundle exec rubocop`
259
+ To run RuboCop:
281
260
 
282
- ---
261
+ $ bundle exec rubocop
283
262
 
284
- ## To do
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
- ## Contributing
267
+ ## Releases
293
268
 
294
- 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).
295
270
 
296
- [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).
297
272
 
298
- ### Semantic Versioning
273
+ ### Publishing
299
274
 
300
- 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,89 @@ 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
+ 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
- scopes: [ActsAsFavoritor.configuration.default_scope])
61
- self.class.build_result_for_scopes scopes do |scope|
62
- favorite_record = get_favorite(favoritable, scope)
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
- dec_cache(favoritable, scope) if ActsAsFavoritor.configuration.cache
66
- favorite_record.destroy!
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
- scopes: [ActsAsFavoritor.configuration.default_scope])
72
- self.class.build_result_for_scopes scopes do |scope|
73
- Favorite.unblocked.send("#{scope}_list").for_favoritor(self)
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(scopes: [ActsAsFavoritor.configuration.default_scope])
79
- self.class.build_result_for_scopes scopes do |scope|
80
- favorites.unblocked.send("#{scope}_list")
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(scopes: [ActsAsFavoritor.configuration.default_scope])
85
- self.class.build_result_for_scopes scopes do |scope|
86
- favorites.unblocked.send("#{scope}_list").includes(:favoritable)
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
- scopes: [ActsAsFavoritor.configuration
93
- .default_scope])
94
- self.class.build_result_for_scopes scopes do |scope|
95
- favorites.unblocked.send("#{scope}_list")
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
- scopes: [ActsAsFavoritor.configuration
102
- .default_scope])
103
- self.class.build_result_for_scopes scopes do |scope|
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: 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
- scopes: [ActsAsFavoritor.configuration.default_scope])
114
- self.class.build_result_for_scopes scopes do |scope|
115
- Favorite.blocked.send("#{scope}_list").for_favoritor(self)
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(scopes: [ActsAsFavoritor.configuration.default_scope])
121
- self.class.build_result_for_scopes scopes do |scope|
122
- favorites.includes(:favoritable).blocked.send("#{scope}_list")
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 = 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.2'
4
+ VERSION = '5.0.2'
5
5
  end
@@ -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('%.3d', current_migration_number(dirname) + 1)
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.0.2
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: 2019-05-17 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: []
@@ -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.3'
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.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