acts_as_favable 1.0.0 → 2.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 76ef9fc7c2c83e7e473c9f9b4e0a64bf3ea7b4e97e2ed6766b6bce11bced0f92
4
+ data.tar.gz: e2958f234f376103ee033856ecf65c437fbf75d25e3a08f3796b8ca49b0f20b8
5
+ SHA512:
6
+ metadata.gz: 24a9ca65d81b38fc244be954889d1a445158d73948abbf301faf1e999b591f03664708773018766ec753dde8882dbbc6465c89be99ff6003956c993c9205623a
7
+ data.tar.gz: 05a2db672c1ea50a38aa5f4f1a244116c81f2a11437c1dd3a8d842fe0b54ef97823d2f6a1e6a4792139d40de541786ae16d9383f1328a3302d71984a65948e55
data/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ ## Unreleased
6
+
7
+ ## 2.1.0 - 2026-09-21
8
+
9
+ - Establish Rails 7.2 as the minimum supported Rails version; compatibility with it is intentional and covered by CI.
10
+ - Define the generated `Favorite#user` association as optional by project policy, with a nullable `user_id` column.
11
+ - Modernize Active Record integration with `ActiveSupport.on_load` and `ActiveSupport::Concern`.
12
+ - Preserve the public `acts_as_favable` and `Favorite.find_*` APIs while using Rails' own polymorphic naming APIs for STI and namespaced models.
13
+ - Make the generator emit the migration version for the Rails version that is actually running instead of hard-coding Rails 8.0.
14
+ - Require a polymorphic favorite target in newly generated migrations.
15
+ - Remove the generated `default_scope`; use `recent` and `in_order` explicitly.
16
+ - Add real Active Record behavior tests and generator coverage.
17
+ - Add GitHub Actions coverage for Rails 7.2, 8.0, and 8.1 across Ruby 3.1 through 4.0.
18
+ - Modernize gem metadata, dependency bounds, packaging, and development documentation.
19
+ - Remove obsolete Rails plugin entry points (`init.rb` and `install.rb`).
20
+ - Upgrade CI checkout to `actions/checkout@v7`.
21
+ - Keep Minitest 5 while Ruby 3.1 remains supported and document that compatibility constraint.
22
+
23
+ ## 2.0.0 - 2025-07-28
24
+
25
+ - Added initial Rails 8 compatibility work.
26
+ - Updated the gem to modern keyword arguments for `has_many` options.
27
+ - Replaced deprecated Active Record APIs used by the original implementation.
28
+ - Updated generated model and migration templates for then-current Rails conventions.
data/README.markdown CHANGED
@@ -1,47 +1,171 @@
1
1
  Acts As Favable
2
2
  =================
3
3
 
4
- Allows for favorite refer to be added to multiple and different models.
4
+ `acts_as_favable` is a small Active Record extension for adding polymorphic favorites to multiple models.
5
5
 
6
- ## Resources
6
+ The gem keeps its original API while modernizing the integration for current Rails applications: lazy Active Record loading, Rails-aware polymorphic type handling, a version-aware generator, automated tests, and a CI compatibility matrix.
7
7
 
8
- ####Install(on Rails3)
8
+ ## Compatibility
9
9
 
10
- To install as a plugin
11
-
12
- rails plugin install http://github.com/yorzi/acts_as_favable.git
13
-
14
- To install as a gem
10
+ The minimum supported Rails version is **Rails 7.2**.
15
11
 
16
- sudo gem install acts_as_favable
12
+ The project is tested against:
17
13
 
18
- Generate your favorite model:
19
-
20
- rails generate favorite
21
-
22
- Then migrate your database:
23
-
24
- rake db:migrate
14
+ - Ruby 3.1 with Rails 7.2
15
+ - Ruby 3.2 with Rails 8.0
16
+ - Ruby 3.2, 3.3, 3.4, and 4.0 with Rails 8.1
17
+
18
+ Rails 8.1 is the primary current target, while Rails 7.2 is an intentionally supported compatibility floor rather than a best-effort legacy lane. Changes to the gem should continue to preserve Rails 7.2 compatibility unless the minimum supported version is explicitly raised in a future release.
19
+
20
+ Applications should still follow the upstream Rails maintenance policy when choosing a production Rails version.
21
+
22
+ ## Installation
23
+
24
+ Add the gem to your application's `Gemfile`:
25
+
26
+ ```ruby
27
+ gem "acts_as_favable"
28
+ ```
29
+
30
+ Then install dependencies and generate the model and migration:
31
+
32
+ ```bash
33
+ bundle install
34
+ bin/rails generate favorite
35
+ bin/rails db:migrate
36
+ ```
37
+
38
+ The generator uses the migration version of the Rails version running your application. It does not hard-code a specific Rails migration version.
25
39
 
26
40
  ## Usage
27
- #### Make your ActiveRecord model act as favable.
28
41
 
29
- class Model < ActiveRecord::Base
30
- acts_as_favable
31
- end
32
-
33
- ####mark a favorite flag to a model instance
34
-
35
- favable = Model.create
36
- favable.favorites.create(:note => "I like this and will make it one of my favorites")
42
+ Make any Active Record model favable:
43
+
44
+ ```ruby
45
+ class Article < ApplicationRecord
46
+ acts_as_favable
47
+ end
48
+ ```
49
+
50
+ Create favorites through the association:
51
+
52
+ ```ruby
53
+ article = Article.find(1)
54
+ article.favorites.create!(note: "Read this again")
55
+ ```
56
+
57
+ ### Optional user association
58
+
59
+ The generated `Favorite` model intentionally defines `user` as optional:
60
+
61
+ ```ruby
62
+ class Favorite < ApplicationRecord
63
+ include ActsAsFavable::Favorite
64
+
65
+ belongs_to :favable, polymorphic: true
66
+ belongs_to :user, optional: true
67
+ end
68
+ ```
69
+
70
+ This is the default gem policy. A favorite can exist without a user:
71
+
72
+ ```ruby
73
+ article.favorites.create!(note: "Read this again")
74
+ ```
75
+
76
+ Applications that associate favorites with users can still pass one normally:
77
+
78
+ ```ruby
79
+ article.favorites.create!(
80
+ note: "Read this again",
81
+ user: current_user
82
+ )
83
+ ```
84
+
85
+ If every favorite in a particular application must belong to a user, that application can tighten the generated model to `belongs_to :user` and make `user_id` non-null in its migration before running it. The gem itself will continue to generate an optional user association by default.
86
+
87
+ ## Querying favorites
88
+
89
+ The generated `Favorite` model includes two explicit ordering scopes:
90
+
91
+ ```ruby
92
+ article.favorites.recent
93
+ article.favorites.in_order
94
+ ```
95
+
96
+ The original finder API is also supported:
97
+
98
+ ```ruby
99
+ Article.find_favorites_for(article)
100
+ Article.find_favorites_by_user(user)
101
+
102
+ Favorite.find_favorites_by_user(user)
103
+ Favorite.find_favorites_for_favable(Article.polymorphic_name, article.id)
104
+ Favorite.find_favable(favorite.favable_type, favorite.favable_id)
105
+ ```
106
+
107
+ `acts_as_favable` uses Active Record's polymorphic naming APIs, so finder behavior follows Rails' STI and namespacing rules instead of reimplementing them.
108
+
109
+ ## Association options
110
+
111
+ Options passed to `acts_as_favable` are forwarded to the generated `has_many :favorites` association. The default is `dependent: :destroy`.
112
+
113
+ ```ruby
114
+ class AuditRecord < ApplicationRecord
115
+ acts_as_favable dependent: :delete_all
116
+ end
117
+ ```
118
+
119
+ ## Generated files
120
+
121
+ `bin/rails generate favorite` creates:
122
+
123
+ ```text
124
+ app/models/favorite.rb
125
+ db/migrate/<timestamp>_create_favorites.rb
126
+ ```
127
+
128
+ The migration creates indexed `favable_type`, `favable_id`, and `user_id` columns. The polymorphic target is required; `user_id` is nullable by design.
129
+
130
+ ## Upgrading from older versions
131
+
132
+ Older versions of this project originated as a Rails plugin. Modern Rails applications do not use the historical `init.rb` or `install.rb` plugin entry points.
133
+
134
+ If you are upgrading an existing application, review your existing `favorites` table and model before running the generator. The generator is intended for new installations; it should not replace an existing migration or model without review.
135
+
136
+ The generated model no longer adds a `default_scope`. Use `recent` or `in_order` explicitly where ordering matters. Existing application models are not changed automatically.
137
+
138
+ ## Development
139
+
140
+ Install dependencies and run the test suite:
141
+
142
+ ```bash
143
+ bundle install
144
+ bundle exec rake test
145
+ ```
146
+
147
+ Run against a specific supported Rails series:
148
+
149
+ ```bash
150
+ RAILS_VERSION=7.2 bundle exec rake test
151
+ RAILS_VERSION=8.0 bundle exec rake test
152
+ RAILS_VERSION=8.1 bundle exec rake test
153
+ ```
154
+
155
+ Rails 7.2 is the compatibility floor and must remain represented in CI while it is a supported gem target.
156
+
157
+ Build the gem locally:
158
+
159
+ ```bash
160
+ bundle exec rake build
161
+ ```
37
162
 
38
- ####Fetch favorites for a favable model:
163
+ See `CONTRIBUTING.md` for contribution guidelines and `CHANGELOG.md` for notable changes.
39
164
 
40
- favable = Model.find(1)
41
- favorites = favable.favorites.recent.limit(10).all
165
+ ## License
42
166
 
43
- Attention: This plugin/gem is heavily influenced by Acts As Taggable and almost copied from acts_at_commentable.
167
+ MIT. See `MIT-LICENSE`.
44
168
 
45
- ## More
169
+ ## Credits
46
170
 
47
- Blog post..
171
+ The original implementation was influenced by the early Rails `acts_as_*` plugin ecosystem, including `acts_as_taggable` and `acts_as_commentable`-style projects.
@@ -0,0 +1,3 @@
1
+ module ActsAsFavable
2
+ VERSION = "2.1.0"
3
+ end
@@ -1,2 +1,11 @@
1
- require 'favable_methods'
2
- require 'favorite_methods'
1
+ require "active_record"
2
+ require "active_support"
3
+ require "active_support/lazy_load_hooks"
4
+
5
+ require_relative "acts_as_favable/version"
6
+ require_relative "favable_methods"
7
+ require_relative "favorite_methods"
8
+
9
+ ActiveSupport.on_load(:active_record) do
10
+ include Acts::Favable unless ancestors.include?(Acts::Favable)
11
+ end
@@ -1,44 +1,37 @@
1
- require 'active_record'
1
+ require "active_support/concern"
2
2
 
3
- module Acts #:nodoc:
4
- module Favable #:nodoc:
3
+ module Acts
4
+ module Favable
5
+ extend ActiveSupport::Concern
5
6
 
6
- def self.included(base)
7
- base.extend ClassMethods
8
- end
7
+ class_methods do
8
+ def acts_as_favable(options = {})
9
+ association_options = { as: :favable, dependent: :destroy }.merge(options)
10
+ has_many :favorites, **association_options
9
11
 
10
- module ClassMethods
11
- def acts_as_favable(options={})
12
- has_many :favorites, {:as => :favable, :dependent => :destroy}.merge(options)
13
12
  include Acts::Favable::InstanceMethods
14
13
  extend Acts::Favable::SingletonMethods
15
14
  end
16
15
  end
17
-
16
+
18
17
  module SingletonMethods
19
- def find_favorites_for(obj)
20
- favable = ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s
21
- Favorite.find_favorites_for_favable(favable, obj.id)
18
+ def find_favorites_for(record)
19
+ Favorite.find_favorites_for_favable(polymorphic_name, record.id)
22
20
  end
23
-
24
- def find_favorites_by_user(user)
25
- favable = ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s
26
- Favorite.where(["user_id = ? and favable_type = ?", user.id, favable]).order("created_at DESC")
21
+
22
+ def find_favorites_by_user(user)
23
+ Favorite.where(user_id: user.id, favable_type: polymorphic_name).recent
27
24
  end
28
25
  end
29
-
30
- # This module contains instance methods
26
+
31
27
  module InstanceMethods
32
28
  def favorites_ordered_by_submitted
33
- Favorite.find_favorites_for_favable(self.class.name, id)
29
+ Favorite.find_favorites_for_favable(self.class.polymorphic_name, id)
34
30
  end
35
31
 
36
32
  def add_favorite(favorite)
37
33
  favorites << favorite
38
34
  end
39
35
  end
40
-
41
36
  end
42
37
  end
43
-
44
- ActiveRecord::Base.send(:include, Acts::Favable)
@@ -1,24 +1,26 @@
1
+ require "active_support/concern"
2
+
1
3
  module ActsAsFavable
2
4
  module Favorite
3
-
4
- def self.included(favorite_model)
5
- favorite_model.extend Finders
6
- favorite_model.scope :in_order, favorite_model.order('created_at ASC')
7
- favorite_model.scope :recent, favorite_model.order('created_at DESC')
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ scope :in_order, -> { order(created_at: :asc) }
9
+ scope :recent, -> { order(created_at: :desc) }
8
10
  end
9
-
10
- module Finders
11
+
12
+ class_methods do
11
13
  def find_favorites_by_user(user)
12
- where(["user_id = ?", user.id]).order("created_at DESC")
14
+ where(user_id: user.id).recent
13
15
  end
14
16
 
15
- def find_favorites_for_favable(favable_str, favable_id)
16
- where(["favable_type = ? and favable_id = ?", favable_str, favable_id]).order("created_at DESC")
17
+ def find_favorites_for_favable(favable_type, favable_id)
18
+ where(favable_type: favable_type, favable_id: favable_id).recent
17
19
  end
18
20
 
19
- def find_favable(favable_str, favable_id)
20
- favable_str.constantize.find(favable_id)
21
+ def find_favable(favable_type, favable_id)
22
+ ActiveRecord::Base.polymorphic_class_for(favable_type).find(favable_id)
21
23
  end
22
24
  end
23
25
  end
24
- end
26
+ end
@@ -0,0 +1,9 @@
1
+ Description:
2
+ Creates a Favorite model and a version-compatible favorites migration.
3
+
4
+ Example:
5
+ bin/rails generate favorite
6
+
7
+ Generated files:
8
+ app/models/favorite.rb
9
+ db/migrate/<timestamp>_create_favorites.rb
@@ -1,17 +1,21 @@
1
- require 'rails/generators/migration'
1
+ require "active_record"
2
+ require "rails/generators"
3
+ require "rails/generators/migration"
2
4
 
3
5
  class FavoriteGenerator < Rails::Generators::Base
4
6
  include Rails::Generators::Migration
5
7
 
6
- def self.source_root
7
- @_acts_as_favable_source_root ||= File.expand_path("../templates", __FILE__)
8
- end
8
+ source_root File.expand_path("templates", __dir__)
9
9
 
10
- def self.next_migration_number(path)
11
- Time.now.utc.strftime("%Y%m%d%H%M%S")
10
+ def self.next_migration_number(dirname)
11
+ if ActiveRecord.timestamped_migrations
12
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
13
+ else
14
+ format("%.3d", current_migration_number(dirname) + 1)
15
+ end
12
16
  end
13
17
 
14
- def create_model_file
18
+ def create_favorite_files
15
19
  template "favorite.rb", "app/models/favorite.rb"
16
20
  migration_template "create_favorites.rb", "db/migrate/create_favorites.rb"
17
21
  end
@@ -1,18 +1,10 @@
1
- class CreateFavorites < ActiveRecord::Migration
2
- def self.up
1
+ class CreateFavorites < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
3
  create_table :favorites do |t|
4
- t.string :note, :limit => 50, :default => ""
5
- t.references :favable, :polymorphic => true
6
- t.references :user
4
+ t.string :note, limit: 50, default: ""
5
+ t.references :favable, polymorphic: true, null: false, index: true
6
+ t.references :user, null: true, index: true
7
7
  t.timestamps
8
8
  end
9
-
10
- add_index :favorites, :favable_type
11
- add_index :favorites, :favable_id
12
- add_index :favorites, :user_id
13
9
  end
14
-
15
- def self.down
16
- drop_table :favorites
17
- end
18
- end
10
+ end
@@ -1,11 +1,6 @@
1
- class Favorite < ActiveRecord::Base
2
-
1
+ class Favorite < ApplicationRecord
3
2
  include ActsAsFavable::Favorite
4
3
 
5
- belongs_to :favable, :polymorphic => true
6
-
7
- default_scope :order => 'created_at ASC'
8
-
9
- # NOTE: Favorite belongs to a user
10
- belongs_to :user
11
- end
4
+ belongs_to :favable, polymorphic: true
5
+ belongs_to :user, optional: true
6
+ end
metadata CHANGED
@@ -1,77 +1,109 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: acts_as_favable
3
- version: !ruby/object:Gem::Version
4
- hash: 23
5
- prerelease: false
6
- segments:
7
- - 1
8
- - 0
9
- - 0
10
- version: 1.0.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.1.0
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Andy Wang
14
- autorequire: acts_as_favable
15
8
  bindir: bin
16
9
  cert_chain: []
17
-
18
- date: 2010-11-29 00:00:00 +08:00
19
- default_executable:
20
- dependencies: []
21
-
22
- description: Plugin/Gem that provides favorites functionality
23
- email: wangyaodi@gmail.com
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activerecord
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.2'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '8.2'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '7.2'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '8.2'
32
+ - !ruby/object:Gem::Dependency
33
+ name: activesupport
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '7.2'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '8.2'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '7.2'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '8.2'
52
+ - !ruby/object:Gem::Dependency
53
+ name: rake
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - "~>"
57
+ - !ruby/object:Gem::Version
58
+ version: '13.0'
59
+ type: :development
60
+ prerelease: false
61
+ version_requirements: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - "~>"
64
+ - !ruby/object:Gem::Version
65
+ version: '13.0'
66
+ description: A small Active Record extension that adds polymorphic favorite associations,
67
+ finders, and a Rails generator.
68
+ email:
69
+ - wangyaodi@gmail.com
24
70
  executables: []
25
-
26
71
  extensions: []
27
-
28
- extra_rdoc_files:
29
- - README.markdown
30
- - MIT-LICENSE
31
- files:
72
+ extra_rdoc_files: []
73
+ files:
74
+ - CHANGELOG.md
32
75
  - MIT-LICENSE
33
76
  - README.markdown
34
77
  - lib/acts_as_favable.rb
35
- - lib/favorite_methods.rb
78
+ - lib/acts_as_favable/version.rb
36
79
  - lib/favable_methods.rb
80
+ - lib/favorite_methods.rb
81
+ - lib/generators/favorite/USAGE
37
82
  - lib/generators/favorite/favorite_generator.rb
38
- - lib/generators/favorite/templates/favorite.rb
39
83
  - lib/generators/favorite/templates/create_favorites.rb
40
- - init.rb
41
- - install.rb
42
- has_rdoc: true
84
+ - lib/generators/favorite/templates/favorite.rb
43
85
  homepage: https://github.com/yorzi/acts_as_favable
44
- licenses: []
45
-
46
- post_install_message:
86
+ licenses:
87
+ - MIT
88
+ metadata:
89
+ source_code_uri: https://github.com/yorzi/acts_as_favable
90
+ bug_tracker_uri: https://github.com/yorzi/acts_as_favable/issues
91
+ changelog_uri: https://github.com/yorzi/acts_as_favable/blob/main/CHANGELOG.md
47
92
  rdoc_options: []
48
-
49
- require_paths:
93
+ require_paths:
50
94
  - lib
51
- required_ruby_version: !ruby/object:Gem::Requirement
52
- none: false
53
- requirements:
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
54
97
  - - ">="
55
- - !ruby/object:Gem::Version
56
- hash: 3
57
- segments:
58
- - 0
59
- version: "0"
60
- required_rubygems_version: !ruby/object:Gem::Requirement
61
- none: false
62
- requirements:
98
+ - !ruby/object:Gem::Version
99
+ version: '3.1'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
63
102
  - - ">="
64
- - !ruby/object:Gem::Version
65
- hash: 3
66
- segments:
67
- - 0
68
- version: "0"
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
69
105
  requirements: []
70
-
71
- rubyforge_project:
72
- rubygems_version: 1.3.7
73
- signing_key:
74
- specification_version: 1
75
- summary: Plugin/gem that provides favorite functionality
106
+ rubygems_version: 3.6.9
107
+ specification_version: 4
108
+ summary: Add polymorphic favorites to Active Record models
76
109
  test_files: []
77
-
data/init.rb DELETED
@@ -1 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'rails', 'init')
data/install.rb DELETED
@@ -1,2 +0,0 @@
1
- puts "To create the favorite model please run:"
2
- puts "rails generate favorite"