rails_interactable 1.0.1

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: a5ec34551df901686b4d9b3ce19380f91e8eda188a0c1f07d178a086bf2e26a7
4
+ data.tar.gz: d01ef574f2271418dece99138aa68d293a0cbdfc9fcfc99289ee7d14ef09a7c9
5
+ SHA512:
6
+ metadata.gz: 791979c3e82e8756551e4bb90cd8580def1fe4ac1948d69db7817dbfa3f594989e1995f37d1d788261d0ad857639029f940434df2fcce951a0cc39797a3ff23d
7
+ data.tar.gz: 50f22c6c4ac2680f886e910c58766242b01c381edec4dedf36516c2a6dcff475da4b56b08b6a527114bed90c6693ec10faa9e79bb2f64766ddbac826f83786c3
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright aric.zheng
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # RailsInteractable
2
+ > Add like/favorite interactions to Rails models.
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ ```ruby
9
+ gem "rails_interactable"
10
+ ```
11
+
12
+ And then execute:
13
+ ```bash
14
+ $ bundle install
15
+ ```
16
+
17
+ Or install it yourself as:
18
+ ```bash
19
+ $ gem install rails_interactable
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ 1. **Generate Migration and Initializer**: Run the generator to create the necessary database migration and configuration initializer.
25
+ ```sh
26
+ rails generate rails_interactable:install
27
+ ```
28
+ This command creates:
29
+ * A migration file (`db/migrate/xxx_create_interactions.rb`) for the `interactions` table.
30
+ * An initializer file (`config/initializers/rails_interactable.rb`) to configure interaction types.
31
+
32
+ 2. **Run the Migration**: Execute the generated migration to create the `interactions` table in your database.
33
+ ```sh
34
+ rails db:migrate
35
+ ```
36
+
37
+ 3. **Configure Interaction Types**: Edit `config/initializers/rails_interactable.rb` to define the types of interactions your application supports. You can also define aliases for convenience.
38
+ ```ruby
39
+ # config/initializers/rails_interactable.rb
40
+ RailsInteractable.interaction_types = {
41
+ like: { alias: :liked_by? },
42
+ favorite: { alias: :favorited_by? }
43
+ # Add more types as needed, e.g.:
44
+ # bookmark: { alias: :bookmarked_by? }
45
+ }
46
+ ```
47
+
48
+ 4. **Make Models Interactable (as Target)**: Add `acts_as_interactable` to the models that can receive interactions (e.g., `Post`, `Video`).
49
+ ```ruby
50
+ # app/models/post.rb
51
+ class Post < ApplicationRecord
52
+ belongs_to :user
53
+ acts_as_interactable # Generates methods like post.likes, post.add_like(user), etc.
54
+ end
55
+ ```
56
+
57
+ 5. **Make Models an Operator**: Add `acts_as_operator` to the models that perform interactions (e.g., `User`).
58
+ ```ruby
59
+ # app/models/user.rb
60
+ class User < ApplicationRecord
61
+ has_many :posts, dependent: :destroy
62
+ acts_as_operator # Generates methods like user.liked, user.liked_of(Post), user.liked?(post), etc.
63
+ end
64
+ ```
65
+
66
+ ## API
67
+
68
+ ### On Interactable Models (e.g., `Post`)
69
+
70
+ * **Check Interaction**: `post.interacted_by_like?(user)` / `post.liked_by?(user)` (if alias configured)
71
+ * **Get Interactors**: `post.likes` (list of users who liked), `post.like_ids` (list of user IDs)
72
+ * **Get Count**: `post.like_count`
73
+ * **Add Interaction**: `post.add_like(user)`
74
+ * **Remove Interaction**: `post.remove_like(user)`
75
+ * **Toggle Interaction**: `post.toggle_like(user)`
76
+ * **Generic Check**: `post.interacted_by?(user, 'like')`
77
+ * **Generic Add/Remove/Toggle**: `post.add_interaction(user, 'like')`, `post.remove_interaction(user, 'like')`, `post.toggle_interaction(user, 'like')`
78
+
79
+ ### On Operator Models (e.g., `User`)
80
+
81
+ * **Check Interaction**: `user.liked?(post)` / `user.favorited?(post)`
82
+ * **Get Interacted Targets**: `user.liked` (all liked items), `user.favorited` (all favorited items)
83
+ * **Get Interacted Target IDs**: `user.liked_ids` (IDs of all liked items), `user.favorited_ids` (IDs of all favorited items)
84
+ * **Get Interacted Targets of Specific Type and Model**: `user.liked_of(Post)` (all Posts liked by user), `user.favorited_of(Post)` (all Posts favorited by user)
85
+ * **Get Interacted Target IDs of Specific Type and Model**: `user.liked_ids_of(Post)` (IDs of Posts liked by user), `user.favorited_ids_of(Post)` (IDs of Posts favorited by user)
86
+ * **Get Interaction Records**: `user.like_interactions`, `user.favorite_interactions`
87
+
88
+ ## Resources
89
+ - https://chat.qwen.ai/c/4d8b4f97-785b-4aa0-87db-29e7671aa3c5
90
+
91
+ ## License
92
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ require "bundler/gem_tasks"
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module RailsInteractable
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module RailsInteractable
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module RailsInteractable
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module RailsInteractable
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module RailsInteractable
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ # app/models/rails_interactable/interaction.rb
2
+ module RailsInteractable
3
+ class Interaction < ApplicationRecord
4
+ self.table_name = 'rails_interactions'
5
+
6
+ belongs_to :operator, polymorphic: true
7
+ belongs_to :target, polymorphic: true
8
+
9
+ validates :interaction_type, presence: true
10
+ validates :operator, presence: true
11
+ validates :target, presence: true
12
+ validates :operator_type, :operator_id, :target_type, :target_id, :interaction_type, presence: true
13
+ validates :operator_id, uniqueness: { scope: [:operator_type, :target_type, :target_id, :interaction_type] }
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Rails interactable</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= yield :head %>
9
+
10
+ <%= stylesheet_link_tag "rails_interactable/application", media: "all" %>
11
+ </head>
12
+ <body>
13
+
14
+ <%= yield %>
15
+
16
+ </body>
17
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ RailsInteractable::Engine.routes.draw do
2
+ end
@@ -0,0 +1,32 @@
1
+ # lib/generators/rails_interactable/install_generator.rb
2
+ require 'rails/generators'
3
+ require 'rails/generators/migration'
4
+
5
+ module RailsInteractable
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+
9
+ source_root File.join(File.dirname(__FILE__), 'templates')
10
+
11
+ def copy_initializer
12
+ template 'initializer.rb', 'config/initializers/rails_interactable.rb'
13
+ end
14
+
15
+ # lib/generators/rails_interactable/install_generator.rb
16
+ def copy_migration
17
+ migration_template 'create_interactions.rb.tt', 'db/migrate/create_interactions.rb'
18
+ end
19
+
20
+ private
21
+
22
+ def migration_timestamp
23
+ Time.current.strftime("%Y%m%d%H%M%S")
24
+ end
25
+
26
+ # ActiveRecord::Generators::Base 会自动提供这个方法,但 Base 需要自己实现
27
+ def self.next_migration_number(dirname)
28
+ next_migration_number = current_migration_number(dirname) + 1
29
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ # lib/generators/rails_interactable/templates/create_interactions.rb.tt
2
+ class CreateInteractions < ActiveRecord::Migration[<%= ActiveRecord::VERSION::MAJOR %>.<%= ActiveRecord::VERSION::MINOR %>]
3
+ def change
4
+ create_table :rails_interactions do |t|
5
+ # 使用 interaction_type 而不是 type
6
+ t.string :interaction_type, null: false
7
+ t.references :operator, polymorphic: true, null: false, index: { name: 'index_interactions_on_op_type_and_op_id' }
8
+ t.references :target, polymorphic: true, null: false, index: { name: 'index_interactions_on_tgt_type_and_tgt_id' }
9
+
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :interactions, [:operator_type, :operator_id, :interaction_type, :target_type, :target_id], unique: true, name: 'index_unique_interaction'
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ # lib/generators/rails_interactable/templates/initializer.rb
2
+ RailsInteractable.interaction_types = {
3
+ like: { alias: :liked_by? },
4
+ favorite: { alias: :favorited_by? }
5
+ # 可以添加更多类型
6
+ # comment: {},
7
+ # share: { alias: :shared_by? }
8
+ }
@@ -0,0 +1,33 @@
1
+ # lib/rails_interactable/engine.rb
2
+ require 'rails'
3
+ require_relative '../rails_interactable'
4
+
5
+ module RailsInteractable
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace RailsInteractable
8
+
9
+ # 加载插件内部的迁移
10
+ initializer "rails_interactable.load_migrations" do
11
+ config.paths["db/migrate"].expanded.each do |expanded_path|
12
+ Rails.application.config.paths["db/migrate"] << expanded_path
13
+ end
14
+ end
15
+
16
+ # 配置初始化
17
+ # 注意:如果配置在插件内部初始化,可能在 dummy app 中被覆盖
18
+ # 更好的方式是让使用者在 config/initializers 中配置
19
+ # initializer "rails_interactable.configure" do |app|
20
+ # RailsInteractable.interaction_types = {
21
+ # like: { alias: :liked_by? },
22
+ # favorite: { alias: :favorited_by? }
23
+ # }
24
+ # end
25
+
26
+ # 混入模块
27
+ initializer "rails_interactable.active_record" do
28
+ ActiveSupport.on_load :active_record do
29
+ include RailsInteractable
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module RailsInteractable
2
+ VERSION = "1.0.1"
3
+ end
@@ -0,0 +1,279 @@
1
+ # lib/rails_interactable.rb
2
+ require "rails_interactable/engine"
3
+
4
+ module RailsInteractable
5
+ # 存储全局配置
6
+ mattr_accessor :interaction_types, default: {}
7
+
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ # 模型只需声明自己是可互动的 (作为 target)
12
+ def acts_as_interactable
13
+ include InstanceMethods
14
+ # 在模型类被加载时,根据全局配置动态定义方法
15
+ RailsInteractable.interaction_types.each do |type, config|
16
+ define_interaction_methods_for_type(type, config)
17
+ end
18
+ end
19
+
20
+ # 模型声明自己是互动的操作者 (operator)
21
+ def acts_as_operator
22
+ include OperatorInstanceMethods
23
+ # 在模型类被加载时,根据全局配置动态定义方法 (operator 角度)
24
+ RailsInteractable.interaction_types.each do |type, config|
25
+ define_operator_interaction_methods_for_type(type, config)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ # 动态定义与特定互动类型相关的方法 (target 角度)
32
+ def define_interaction_methods_for_type(type, config)
33
+ type_sym = type.to_sym
34
+ type_str = type.to_s
35
+
36
+ # 1. 检查互动状态: interacted_by_TYPE?(operator)
37
+ define_method "interacted_by_#{type_sym}?" do |operator|
38
+ RailsInteractable::Interaction.where(
39
+ target: self,
40
+ operator: operator,
41
+ interaction_type: type_str
42
+ ).exists?
43
+ end
44
+
45
+ # 2. 获取互动者列表: TYPEers
46
+ define_method "#{type_sym}s" do
47
+ # 重用 interactors 方法的逻辑
48
+ interactors(type_str)
49
+ end
50
+
51
+ # 2.5. 获取互动者ID列表: TYPE_ids
52
+ define_method "#{type_sym}_ids" do
53
+ # 重用 interactors_ids 方法的逻辑
54
+ interactors_ids(type_str)
55
+ end
56
+
57
+ # 3. 获取互动计数: TYPE_count
58
+ define_method "#{type_sym}_count" do
59
+ RailsInteractable::Interaction.where(target: self, interaction_type: type_str).count
60
+ end
61
+
62
+ # 4. 添加互动: add_TYPE(operator)
63
+ define_method "add_#{type_sym}" do |operator|
64
+ unless RailsInteractable::Interaction.where(
65
+ target: self,
66
+ operator: operator,
67
+ interaction_type: type_str
68
+ ).exists?
69
+ RailsInteractable::Interaction.create!(
70
+ target: self,
71
+ operator: operator,
72
+ interaction_type: type_str
73
+ )
74
+ end
75
+ end
76
+
77
+ # 5. 移除互动: remove_TYPE(operator)
78
+ define_method "remove_#{type_sym}" do |operator|
79
+ interaction = RailsInteractable::Interaction.where(
80
+ target: self,
81
+ operator: operator,
82
+ interaction_type: type_str
83
+ ).first
84
+ interaction&.destroy
85
+ end
86
+
87
+ # 6. 切换互动: toggle_TYPE(operator)
88
+ define_method "toggle_#{type_sym}" do |operator|
89
+ if send("interacted_by_#{type_sym}?", operator)
90
+ send("remove_#{type_sym}", operator)
91
+ else
92
+ send("add_#{type_sym}", operator)
93
+ end
94
+ end
95
+
96
+ # 7. 根据配置添加别名等
97
+ if config && config[:alias]
98
+ alias_method config[:alias], "interacted_by_#{type_sym}?"
99
+ end
100
+ end
101
+
102
+ # 动态定义与特定互动类型相关的方法 (operator 角度)
103
+ def define_operator_interaction_methods_for_type(type, config)
104
+ type_sym = type.to_sym
105
+ type_str = type.to_s
106
+
107
+ # 1. 获取操作者发起的特定类型互动的目标对象: TYPEd (e.g., user.liked, user.favorited)
108
+ define_method "#{type_sym}d" do
109
+ targets_of_type(type_str)
110
+ end
111
+
112
+ # 1.5. 获取操作者发起的特定类型、特定目标模型的互动对象: TYPEd_of(TargetModel) (e.g., user.liked_of(Post), user.favorited_of(Post))
113
+ define_method "#{type_sym}d_of" do |target_class|
114
+ targets_of_type_and_class(type_str, target_class)
115
+ end
116
+
117
+ # 2. 获取操作者发起的特定类型互动的目标对象ID: TYPEd_ids (e.g., user.liked_ids, user.favorited_ids)
118
+ define_method "#{type_sym}_ids" do
119
+ target_ids_of_type(type_str)
120
+ end
121
+
122
+ # 2.5. 获取操作者发起的特定类型、特定目标模型的互动对象ID: TYPEd_ids_of(TargetModel) (e.g., user.liked_ids_of(Post), user.favorited_ids_of(Post))
123
+ define_method "#{type_sym}_ids_of" do |target_class|
124
+ target_ids_of_type_and_class(type_str, target_class)
125
+ end
126
+
127
+ # 3. 检查操作者是否对某个目标执行了特定类型互动: TYPEd?(target) (e.g., user.liked?(post), user.favorited?(post))
128
+ define_method "#{type_sym}d?" do |target|
129
+ interacted_with?(target, type_str)
130
+ end
131
+
132
+ # 4. 获取操作者发起的特定类型互动记录: TYPE_interactions (e.g., user.like_interactions, user.favorite_interactions)
133
+ define_method "#{type_sym}_interactions" do
134
+ interactions_of_type(type_str)
135
+ end
136
+ end
137
+ end
138
+
139
+ module InstanceMethods
140
+ # 通用方法 - 使用 interaction_type
141
+ def interacted_by?(operator, type)
142
+ RailsInteractable::Interaction.where(
143
+ target: self,
144
+ operator: operator,
145
+ interaction_type: type.to_s
146
+ ).exists?
147
+ end
148
+
149
+ # 修改 interactors 方法,移除 joins,避免多态关联加载错误
150
+ def interactors(type)
151
+ # 首先获取所有相关交互的 operator_type 和 operator_id
152
+ operator_data = RailsInteractable::Interaction
153
+ .where(target: self, interaction_type: type.to_s)
154
+ .pluck(:operator_type, :operator_id)
155
+
156
+ # 按 operator_type 分组
157
+ operators_by_type = operator_data.group_by(&:first).transform_values { |group| group.map(&:last).uniq }
158
+
159
+ # 为每种类型批量查询对应的模型实例
160
+ results = []
161
+ operators_by_type.each do |operator_type, operator_ids|
162
+ operator_class = operator_type.constantize
163
+ instances = operator_class.where(id: operator_ids)
164
+ results.concat(instances)
165
+ end
166
+
167
+ results
168
+ end
169
+
170
+ # 新增:获取互动者ID列表
171
+ def interactors_ids(type)
172
+ RailsInteractable::Interaction
173
+ .where(target: self, interaction_type: type.to_s)
174
+ .pluck(:operator_id)
175
+ .uniq
176
+ end
177
+
178
+ def interaction_count(type)
179
+ RailsInteractable::Interaction.where(target: self, interaction_type: type.to_s).count
180
+ end
181
+
182
+ # 通用方法
183
+ def add_interaction(operator, type)
184
+ unless RailsInteractable::Interaction.where(
185
+ target: self,
186
+ operator: operator,
187
+ interaction_type: type.to_s
188
+ ).exists?
189
+ RailsInteractable::Interaction.create!(
190
+ target: self,
191
+ operator: operator,
192
+ interaction_type: type.to_s
193
+ )
194
+ end
195
+ end
196
+
197
+ def remove_interaction(operator, type)
198
+ interaction = RailsInteractable::Interaction.where(
199
+ target: self,
200
+ operator: operator,
201
+ interaction_type: type.to_s
202
+ ).first
203
+ interaction&.destroy
204
+ end
205
+
206
+ def toggle_interaction(operator, type)
207
+ if interacted_by?(operator, type)
208
+ remove_interaction(operator, type)
209
+ else
210
+ add_interaction(operator, type)
211
+ end
212
+ end
213
+ end
214
+
215
+ # 新增:Operator 相关的实例方法
216
+ module OperatorInstanceMethods
217
+ # 通用方法:获取操作者发起的特定类型互动
218
+ def interactions_of_type(type)
219
+ RailsInteractable::Interaction.where(
220
+ operator: self,
221
+ interaction_type: type.to_s
222
+ )
223
+ end
224
+
225
+ # 通用方法:获取操作者发起的特定类型互动的目标对象
226
+ def targets_of_type(type)
227
+ interaction_targets = RailsInteractable::Interaction
228
+ .where(operator: self, interaction_type: type.to_s)
229
+ .pluck(:target_type, :target_id)
230
+
231
+ targets_by_type = interaction_targets.group_by(&:first).transform_values { |group| group.map(&:last).uniq }
232
+
233
+ results = []
234
+ targets_by_type.each do |target_type, target_ids|
235
+ target_class = target_type.constantize
236
+ instances = target_class.where(id: target_ids)
237
+ results.concat(instances)
238
+ end
239
+
240
+ results
241
+ end
242
+
243
+ # 新增:获取操作者发起的特定类型、特定目标模型的互动对象
244
+ def targets_of_type_and_class(type, target_class)
245
+ target_class_name = target_class.name
246
+ interaction_target_ids = RailsInteractable::Interaction
247
+ .where(operator: self, interaction_type: type.to_s, target_type: target_class_name)
248
+ .pluck(:target_id)
249
+
250
+ target_class.where(id: interaction_target_ids)
251
+ end
252
+
253
+ # 通用方法:获取操作者发起的特定类型互动的目标对象ID
254
+ def target_ids_of_type(type)
255
+ RailsInteractable::Interaction
256
+ .where(operator: self, interaction_type: type.to_s)
257
+ .pluck(:target_id)
258
+ .uniq
259
+ end
260
+
261
+ # 新增:获取操作者发起的特定类型、特定目标模型的互动对象ID
262
+ def target_ids_of_type_and_class(type, target_class)
263
+ target_class_name = target_class.name
264
+ RailsInteractable::Interaction
265
+ .where(operator: self, interaction_type: type.to_s, target_type: target_class_name)
266
+ .pluck(:target_id)
267
+ .uniq
268
+ end
269
+
270
+ # 通用方法:检查操作者是否对某个目标执行了特定类型互动
271
+ def interacted_with?(target, type)
272
+ RailsInteractable::Interaction.where(
273
+ operator: self,
274
+ target: target,
275
+ interaction_type: type.to_s
276
+ ).exists?
277
+ end
278
+ end
279
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :rails_interactable do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_interactable
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - aric.zheng
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-11-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 8.1.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 8.1.1
27
+ description: A Rails gem for adding like, favorite, and other interaction features
28
+ to models via dynamic method generation.
29
+ email:
30
+ - 1290657123@qq.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - MIT-LICENSE
36
+ - README.md
37
+ - Rakefile
38
+ - app/assets/stylesheets/rails_interactable/application.css
39
+ - app/controllers/rails_interactable/application_controller.rb
40
+ - app/helpers/rails_interactable/application_helper.rb
41
+ - app/jobs/rails_interactable/application_job.rb
42
+ - app/mailers/rails_interactable/application_mailer.rb
43
+ - app/models/rails_interactable/application_record.rb
44
+ - app/models/rails_interactable/interaction.rb
45
+ - app/views/layouts/rails_interactable/application.html.erb
46
+ - config/routes.rb
47
+ - lib/generators/rails_interactable/install_generator.rb
48
+ - lib/generators/rails_interactable/templates/create_interactions.rb.tt
49
+ - lib/generators/rails_interactable/templates/initializer.rb
50
+ - lib/rails_interactable.rb
51
+ - lib/rails_interactable/engine.rb
52
+ - lib/rails_interactable/version.rb
53
+ - lib/tasks/rails_interactable_tasks.rake
54
+ homepage: https://github.com/afeiship/rails_interactable
55
+ licenses:
56
+ - MIT
57
+ metadata:
58
+ homepage_uri: https://github.com/afeiship/rails_interactable
59
+ source_code_uri: https://github.com/afeiship/rails_interactable
60
+ changelog_uri: https://github.com/afeiship/rails_interactable/blob/main/CHANGELOG.md
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubygems_version: 3.5.22
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Add like/favorite interactions to Rails models.
80
+ test_files: []