action-store 0.3.3 → 1.1.0

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: d3f20d025cda1c0724c4b9b053288efb85d714069d90fff728c59affc3a47da0
4
- data.tar.gz: c94553d106707178ffd85c2c2e2aef41feaaa040441faf4fca96356ec46a5fc2
3
+ metadata.gz: 1d467de9d475a9a67d39dc4f7698be8b7a315d4a595e148c2a08f9ca3a5eff11
4
+ data.tar.gz: 9f82b594f99b6b7a2b27f4aa8f2abb9be2b3b46ad1f366d76a8f8a939b829828
5
5
  SHA512:
6
- metadata.gz: cb20154fbc1dba325e3a40415d7940b37f7e52aa1dfc877da24ba6cdb5691f0f99788b7a737688f083ff37ee8659393496344febaf0d62b97e08db5f61b378fb
7
- data.tar.gz: 3f925347dca40f57691af345af33e47fbd58d0b6b24deaabe0d89f3ebad3d24874d050783387d3dfc216fe500d3f31cf5d7682e99b5ac5935fc7760296ed7765
6
+ metadata.gz: 3756a70605f0d4e51a06442b92df8706b776115b614ed8771e85ac4ce861a2acff69d7fcbe5d2e92622d17506ae209bc5561ff46abb5418bc85d8bd0dcce7f12
7
+ data.tar.gz: cadcd1a2f92975616885f446eda4530c5883bf0eccea64a28c41f94ccc38fa009b8713e5ffd67d513872449be7491afcb514eb7accd5c7775e7f3bd42bba3a75
@@ -1,20 +1,82 @@
1
- 0.3.3
2
- -----
1
+ ## 1.1.0
2
+
3
+ - Allows to configure different Models / Tables for store actions. (#16)
4
+
5
+ ```rb
6
+ # app/models/like.rb
7
+ class Like < Action
8
+ self.table_name = "likes"
9
+ end
10
+ ```
11
+
12
+ ```rb
13
+ # app/models/user.rb
14
+ class User < ActiveRecord::Base
15
+ action_store :like, :post, counter_cache: true, action_class_name: "Like"
16
+ action_store :like, :comment, counter_cache: true, action_class_name: "Like"
17
+ end
18
+ ```
19
+
20
+ ## 1.0.0
21
+
22
+ - Require Rails >= 5.2.
23
+ - Fix primary key for use `bigint` column type.
24
+
25
+ 0.4.3
26
+
27
+ ---
28
+
29
+ - Auto reload `target`, when action/unaction target.
30
+
31
+ ```rb
32
+ irb> post.likes_count
33
+ => 0
34
+ irb> user.like_post(post)
35
+ irb> post.likes_count
36
+ => 1
37
+ irb> user.unlike_post(post)
38
+ irb> post.likes_count
39
+ => 0
40
+ ```
41
+
42
+ ## 0.4.2
43
+
44
+ - Add `UNIQUE INDEX` on `:action_type, :target_type, :target_id, :user_type, :user_id` for makesure action uniqueness.
45
+ > NOTE! If you already have actions in database, the new migration may have issue on `db:migrate`,
46
+ > so you need fix them by remove duplicate.
47
+ - Now `create_action` method use database to makesure unique.
48
+
49
+ **Upgrade from 0.3.x:**
50
+
51
+ You must use `rails g action_store:install` to generate the new migration file.
52
+
53
+ ```bash
54
+ $ rails g action_store:install
55
+ conflict config/initializers/action_store.rb
56
+ Overwrite config/initializers/action_store.rb? (enter "h" for help) [Ynaqdhm] n
57
+ skip config/initializers/action_store.rb
58
+ Copied migration 20181121061544_add_unique_index_to_actions.action_store.rb from action_store
59
+ ```
60
+
61
+ ## 0.3.3
3
62
 
4
63
  - Fix for supports Rails 5.2;
5
64
 
6
- 0.3.2
7
- -----
65
+ 0.3.2
66
+
67
+ ---
8
68
 
9
69
  - Gem dependency for Rails 5.x.
10
70
 
11
- 0.3.1
12
- -----
71
+ 0.3.1
72
+
73
+ ---
13
74
 
14
75
  - Fix that `:user_counter_cache` was incorrect, it not count with target_type.
15
76
 
16
- 0.3.0
17
- -----
77
+ 0.3.0
78
+
79
+ ---
18
80
 
19
81
  - Fix for action_store in Model that not named `User`.
20
82
  - Fix has_many name when `User` model in a namespace.
@@ -36,8 +98,7 @@ end
36
98
  @blog_user.like_post(@post), @post.like_by_blog_users, @post.like_by_blog_user_actions
37
99
  ```
38
100
 
39
- 0.2.2
40
- -----
101
+ ## 0.2.2
41
102
 
42
103
  - Fix #2 support Target that under a namespace.
43
104
 
@@ -45,18 +106,19 @@ end
45
106
  action_store :like, :blog_post, class_name: 'Blog::Post'
46
107
  ```
47
108
 
48
- 0.2.1
49
- -----
109
+ ## 0.2.1
50
110
 
51
111
  - Use `ActiveSupport.on_load` to hook into Active Record.
52
112
 
53
- 0.2.0
54
- -----
113
+ 0.2.0
114
+
115
+ ---
55
116
 
56
117
  - New API, define action in User model.
57
118
  - Builtin Many-to-Many relations and methods.
58
119
 
59
- 0.1.0
60
- -----
120
+ 0.1.0
121
+
122
+ ---
61
123
 
62
124
  - First release.
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
- ActionStore
2
- -----------
1
+ ## ActionStore
3
2
 
4
- [![Gem Version](https://badge.fury.io/rb/action-store.svg)](https://badge.fury.io/rb/action-store) [![Build Status](https://travis-ci.org/rails-engine/action-store.svg)](https://travis-ci.org/rails-engine/action-store) [![Code Climate](https://codeclimate.com/github/rails-engine/action-store/badges/gpa.svg)](https://codeclimate.com/github/rails-engine/action-store) [![codecov.io](https://codecov.io/github/rails-engine/action-store/coverage.svg?branch=master)](https://codecov.io/github/rails-engine/action-store?branch=master)
3
+ [![Gem Version](https://badge.fury.io/rb/action-store.svg)](https://badge.fury.io/rb/action-store) [![build](https://github.com/rails-engine/action-store/workflows/build/badge.svg)](https://github.com/rails-engine/action-store/actions?query=workflow%3Abuild) [![codecov.io](https://codecov.io/github/rails-engine/action-store/coverage.svg?branch=master)](https://codecov.io/github/rails-engine/action-store?branch=master)
5
4
 
6
5
  Store different kinds of actions (Like, Follow, Star, Block, etc.) in a single table via ActiveRecord Polymorphic Associations.
7
6
 
@@ -17,12 +16,18 @@ And more and more.
17
16
 
18
17
  ## Basic table struct
19
18
 
20
- | Column | Description |
21
- | ----- | ----- |
22
- | `action_type` | The type of action [like, watch, follow, star, favorite] |
23
- | `action_option` | Secondary option for storing your custom status, or null if unneeded. |
19
+ | Column | Description |
20
+ | -------------------------- | --------------------------------------------------------------------------- |
21
+ | `action_type` | The type of action [like, watch, follow, star, favorite] |
22
+ | `action_option` | Secondary option for storing your custom status, or null if unneeded. |
24
23
  | `target_type`, `target_id` | Polymorphic Association for different `Target` models [User, Post, Comment] |
25
24
 
25
+ ### Uniqueness
26
+
27
+ > version: ">= 0.4.0"
28
+
29
+ The have database unique index on fields: `[action_type, target_type, target_id, user_type, user_id]` for keep uniqueness for same action from user to target.
30
+
26
31
  ## Usage
27
32
 
28
33
  ```rb
@@ -33,7 +38,7 @@ and run `bundle install`
33
38
 
34
39
  Generate Migrations:
35
40
 
36
- ```
41
+ ```bash
37
42
  $ rails g action_store:install
38
43
  create config/initializers/action_store.rb
39
44
  migration 20170208024704_create_actions.rb from action_store
@@ -45,9 +50,8 @@ and run `rails db:migrate`.
45
50
 
46
51
  Use `action_store` to define actions:
47
52
 
48
- app/models/user.rb
49
-
50
- ```
53
+ ```rb
54
+ # app/models/user.rb
51
55
  class User < ActiveRecord::Base
52
56
  action_store <action_type>, <target>, opts
53
57
  end
@@ -55,18 +59,18 @@ end
55
59
 
56
60
  #### Convention Over Configuration:
57
61
 
58
- | action, target | Target Model | Target `counter_cache_field` | User `counter_cache_field` | Target has_many | User has_many |
59
- |----------------|--------------|------------------------------|----------------------------|-----------------|---------------|
60
- | `action_store :like, :post` | `Post` | | | `has_many :like_by_user_actions`, `has_many :like_by_users` | `has_many :like_post_actions`, `has_many :like_posts` |
61
- | `action_store :like, :post, counter_cache: true` | `Post` | `likes_count` | | `has_many :like_by_user_actions`, `has_many :like_by_users` | `has_many :like_post_actions`, `has_many :like_posts` |
62
- | `action_store :star, :project, class_name: 'Repository'` | `Repository ` | `stars_count` | `star_projects_count` | `has_many :star_by_user_actions`, `has_many :star_by_users` |
63
- | `action_store :follow, :user` | `User` | `follows_count` | `follow_users_count` | `has_many :follow_by_user_actions`, `has_many :follow_by_users` | `has_many :follow_user_actions`, `has_many :follow_users` |
64
- | `action_store :follow, :user, counter_cache: 'followers_count', user_counter_cache: 'following_count'` | `User` | `followers_count ` | `following_count ` | `has_many :follow_by_user_actions`, `has_many :follow_by_users` | `has_many :follow_user_actions`, `has_many :follow_users` |
62
+ | action, target | Target Model | Target `counter_cache_field` | User `counter_cache_field` | Target has_many | User has_many |
63
+ | ------------------------------------------------------------------------------------------------------ | ------------- | ---------------------------- | -------------------------- | --------------------------------------------------------------- | --------------------------------------------------------- |
64
+ | `action_store :like, :post` | `Post` | | | `has_many :like_by_user_actions`, `has_many :like_by_users` | `has_many :like_post_actions`, `has_many :like_posts` |
65
+ | `action_store :like, :post, counter_cache: true` | `Post` | `likes_count` | | `has_many :like_by_user_actions`, `has_many :like_by_users` | `has_many :like_post_actions`, `has_many :like_posts` |
66
+ | `action_store :star, :project, class_name: 'Repository'` | `Repository ` | `stars_count` | `star_projects_count` | `has_many :star_by_user_actions`, `has_many :star_by_users` |
67
+ | `action_store :follow, :user` | `User` | `follows_count` | `follow_users_count` | `has_many :follow_by_user_actions`, `has_many :follow_by_users` | `has_many :follow_user_actions`, `has_many :follow_users` |
68
+ | `action_store :follow, :user, counter_cache: 'followers_count', user_counter_cache: 'following_count'` | `User` | `followers_count ` | `following_count ` | `has_many :follow_by_user_actions`, `has_many :follow_by_users` | `has_many :follow_user_actions`, `has_many :follow_users` |
65
69
 
66
70
  for example:
67
71
 
68
72
  ```rb
69
- # app/models/action.rb
73
+ # app/models/user.rb
70
74
  class User < ActiveRecord::Base
71
75
  action_store :like, :post, counter_cache: true
72
76
  action_store :star, :post, counter_cache: true, user_counter_cache: true
@@ -124,23 +128,112 @@ irb> action.present?
124
128
  true
125
129
  ```
126
130
 
127
- Other following use cases:
131
+ **Other following use cases:**
128
132
 
129
133
  ```rb
130
134
  # @user1 -> follow @user2
131
- @user1.create_action(:follow, target: @user2)
132
- @user1.reload.following_count => 1
133
- @user2.reload.followers_count_ => 1
134
- @user1.follow_user?(@user2) => true
135
+ irb> @user1.create_action(:follow, target: @user2)
136
+ irb> @user1.reload.following_count
137
+ => 1
138
+ irb> @user2.reload.followers_count
139
+ => 1
140
+ irb> @user1.follow_user?(@user2)
141
+ => true
142
+
135
143
  # @user2 -> follow @user1
136
- @user2.create_action(:follow, target: @user1)
137
- @user2.follow_user?(@user1) => true
144
+ irb> @user2.create_action(:follow, target: @user1)
145
+ irb> @user2.follow_user?(@user1)
146
+ => true
147
+
138
148
  # @user1 -> follow @user3
139
- @user1.create_action(:follow, target: @user3)
149
+ irb> @user1.create_action(:follow, target: @user3)
150
+
140
151
  # @user1 -> unfollow @user3
141
- @user1.destroy_action(:follow, target: @user3)
152
+ irb> @user1.destroy_action(:follow, target: @user3)
153
+ ```
154
+
155
+ **Subscribe cases:**
156
+
157
+ Sometimes, you may need use `action_option` option.
158
+
159
+ For example, user to subscribe a issue (like GitHub Issue) on issue create, and they wants keep in subscribe list on unsubscribe for makesure next comment will not subscribe this issue again.
160
+
161
+ So, in this case, we should not use `@user.unsubscribe_issue` method to destroy action record, we need set a value on `action_option` to mark this subscribe is `ignore`.
162
+
163
+ ```rb
164
+ irb> User.create_action(:subscribe, target: @issue, user: @user)
165
+ irb> @user.subscribe_issue?(@issue)
166
+ => true
167
+
168
+ irb> User.create_action(:subscribe, target: @issue, user: @user, action_option: "ignore")
169
+ irb> @user.subscribe_issue?(@issue)
170
+ => true
171
+
172
+ irb> action = User.find_action(:subscribe, target: @issue, user: @user)
173
+ irb> action.action_option
174
+ => "ignore"
175
+
176
+ irb> @issue.subscribe_by_user_actions.count
177
+ => 1
178
+ irb> @issue.subscribe_by_user_actions.where(action_option: nil).count
179
+ => 0
180
+ ```
181
+
182
+ ## Use different tables for store actions.
183
+
184
+ > since 1.1.0
185
+
186
+ Sometimes, you may want to store actions into different table, for example, **Like** scenarios often have a lot of data, we wants store them into `likes` table.
187
+
188
+ Create a migration and model
189
+
190
+ ```bash
191
+ $ rails g migration create_likes
192
+ ```
193
+
194
+ And then modify this migration file to let this table have same struct like the `actions`
195
+
196
+ ```rb
197
+ class CreateLikes < ActiveRecord::Migration[6.1]
198
+ def change
199
+ create_table :likes do |t|
200
+ t.string :action_type, null: false
201
+ t.string :action_option
202
+ t.string :target_type
203
+ t.bigint :target_id
204
+ t.string :user_type
205
+ t.bigint :user_id
206
+
207
+ t.timestamps
208
+ end
209
+
210
+ add_index :likes, %i[user_type user_id action_type]
211
+ add_index :likes, %i[target_type target_id action_type]
212
+ add_index :likes, %i[action_type target_type target_id user_type user_id], unique: true, name: :uk_likes_target_user
213
+ end
214
+ end
215
+ ```
216
+
217
+ Create a `app/model/like.rb` model file:
218
+
219
+ ```rb
220
+ class Like < Action
221
+ self.table_name = "likes"
222
+ end
223
+ ```
224
+
225
+ And then change you `action_store` define to special some case to use Like model:
226
+
227
+ ```rb
228
+ # app/models/user.rb
229
+ class User < ActiveRecord::Base
230
+ action_store :like, :post, counter_cache: true, action_class_name: "Like"
231
+ action_store :like, :comment, counter_cache: true, action_class_name: "Like"
232
+ end
142
233
  ```
143
234
 
235
+ Now, `user.like_post`, `user.like_comment` will store the actions into `likes` table.
236
+
144
237
  ## Built-in relations and methods
145
238
 
146
239
  When you call `action_store`, ActionStore will define many-to-many relations for User and Target models.
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  begin
3
4
  require "bundler/setup"
4
5
  rescue LoadError
@@ -15,7 +16,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
15
16
  rdoc.rdoc_files.include("lib/**/*.rb")
16
17
  end
17
18
 
18
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
19
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
19
20
  load "rails/tasks/engine.rake"
20
21
  load "rails/tasks/statistics.rake"
21
22
 
@@ -29,5 +30,4 @@ Rake::TestTask.new(:test) do |t|
29
30
  t.verbose = false
30
31
  end
31
32
 
32
-
33
33
  task default: :test
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Auto generate with action-store gem.
3
4
  class Action < ActiveRecord::Base
4
5
  include ActionStore::Model
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # ActionStore Config
3
4
  ActionStore.configure do
4
5
  end
@@ -1,18 +1,19 @@
1
1
  # frozen_string_literal: true
2
- class CreateActions < ActiveRecord::Migration[5.0]
2
+
3
+ class CreateActions < ActiveRecord::Migration[5.2]
3
4
  def change
4
5
  create_table :actions do |t|
5
6
  t.string :action_type, null: false
6
7
  t.string :action_option
7
8
  t.string :target_type
8
- t.integer :target_id
9
+ t.bigint :target_id
9
10
  t.string :user_type
10
- t.integer :user_id
11
+ t.bigint :user_id
11
12
 
12
13
  t.timestamps
13
14
  end
14
15
 
15
- add_index :actions, [:user_type, :user_id, :action_type]
16
- add_index :actions, [:target_type, :target_id, :action_type]
16
+ add_index :actions, %i[user_type user_id action_type]
17
+ add_index :actions, %i[target_type target_id action_type]
17
18
  end
18
19
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddUniqueIndexToActions < ActiveRecord::Migration[5.2]
4
+ def change
5
+ add_index :actions, %i[action_type target_type target_id user_type user_id], unique: true,
6
+ name: :uk_action_target_user
7
+ end
8
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "action_store/version"
3
4
  require "action_store/configuration"
4
5
  require "action_store/engine"
@@ -9,6 +10,7 @@ module ActionStore
9
10
  class << self
10
11
  def config
11
12
  return @config if defined?(@config)
13
+
12
14
  @config = Configuration.new
13
15
  @config
14
16
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module ActionStore
3
4
  class Configuration
4
5
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module ActionStore
3
4
  class Engine < ::Rails::Engine
4
5
  isolate_namespace ActionStore
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module ActionStore
3
4
  module Mixin
4
5
  extend ActiveSupport::Concern
@@ -32,32 +33,36 @@ module ActionStore
32
33
  end
33
34
  end
34
35
 
35
- def action_store(action_type, name, opts = {})
36
- opts ||= {}
37
- klass_name = opts[:class_name] || name.to_s.classify
38
- target_klass = klass_name.constantize
36
+ def action_store(action_type, name, class_name: nil, action_class_name: "Action", counter_cache: nil, user_counter_cache: nil)
37
+ name = name.to_s
38
+
39
+ class_name ||= name.classify
40
+ target_klass = class_name.constantize
41
+ action_klass = action_class_name.constantize
39
42
  action_type = action_type.to_s
40
- if opts[:counter_cache] == true
43
+ if counter_cache == true
41
44
  # @post.stars_count
42
- opts[:counter_cache] = "#{action_type.pluralize}_count"
45
+ counter_cache = "#{action_type.pluralize}_count"
43
46
  end
44
- if opts[:user_counter_cache] == true
47
+ if user_counter_cache == true
45
48
  # @user.star_posts_count
46
- opts[:user_counter_cache] = "#{action_type}_#{name.to_s.pluralize}_count"
49
+ user_counter_cache = "#{action_type}_#{name.pluralize}_count"
47
50
  end
48
51
 
49
52
  @defined_actions ||= []
50
53
  action = {
51
- action_name: name.to_s,
54
+ action_name: name,
52
55
  action_type: action_type,
56
+ action_klass: action_klass,
53
57
  target_klass: target_klass,
54
58
  target_type: target_klass.name,
55
- counter_cache: opts[:counter_cache],
56
- user_counter_cache: opts[:user_counter_cache]
59
+ counter_cache: counter_cache,
60
+ user_counter_cache: user_counter_cache
57
61
  }
58
62
  @defined_actions << action
59
63
 
60
- define_relations(action)
64
+ define_relations(action_klass: action_klass, target_klass: target_klass,
65
+ action_type: action_type, action_name: name)
61
66
  end
62
67
 
63
68
  def find_action(action_type, opts)
@@ -69,7 +74,7 @@ module ActionStore
69
74
  defined_action = find_defined_action(opts[:action_type], opts[:target_type])
70
75
  return nil if defined_action.nil?
71
76
 
72
- Action.find_by(where_opts(opts))
77
+ defined_action[:action_klass].find_by(where_opts(opts))
73
78
  end
74
79
 
75
80
  def create_action(action_type, opts)
@@ -81,10 +86,16 @@ module ActionStore
81
86
  defined_action = find_defined_action(opts[:action_type], opts[:target_type])
82
87
  return false if defined_action.nil?
83
88
 
84
- action = Action.find_or_create_by(where_opts(opts))
85
- if opts[:action_option]
86
- action.update_attribute(:action_option, opts[:action_option])
89
+ # create! for raise RecordNotUnique
90
+ begin
91
+ action = defined_action[:action_klass].find_or_create_by!(where_opts(opts))
92
+ action.update(action_option: opts[:action_option]) if opts.key?(:action_option)
93
+ rescue ActiveRecord::RecordNotUnique
94
+ # update action_option on exist
95
+ action = defined_action[:action_klass].where(where_opts(opts)).take
96
+ action.update(action_option: opts[:action_option]) if opts.key?(:action_option)
87
97
  end
98
+
88
99
  reset_counter_cache(action, defined_action)
89
100
  true
90
101
  end
@@ -98,8 +109,9 @@ module ActionStore
98
109
  defined_action = find_defined_action(opts[:action_type], opts[:target_type])
99
110
  return false if defined_action.nil?
100
111
 
101
- action = Action.where(where_opts(opts)).first
102
- return true if !action
112
+ action = defined_action[:action_klass].where(where_opts(opts)).first
113
+ return true unless action
114
+
103
115
  action.destroy
104
116
  reset_counter_cache(action, defined_action)
105
117
  true
@@ -107,16 +119,18 @@ module ActionStore
107
119
 
108
120
  def reset_counter_cache(action, defined_action)
109
121
  return false if action.blank?
122
+
110
123
  if defined_action[:counter_cache] && action.target.present?
111
- target_count = Action.where(
124
+ target_count = defined_action[:action_klass].where(
112
125
  action_type: defined_action[:action_type],
113
126
  target_type: action.target_type,
114
127
  target_id: action.target_id
115
128
  ).count
116
129
  action.target.update_attribute(defined_action[:counter_cache], target_count)
117
130
  end
131
+
118
132
  if defined_action[:user_counter_cache] && action.user.present?
119
- user_count = Action.where(
133
+ user_count = defined_action[:action_klass].where(
120
134
  action_type: defined_action[:action_type],
121
135
  target_type: action.target_type,
122
136
  user_type: action.user_type,
@@ -128,103 +142,101 @@ module ActionStore
128
142
 
129
143
  private
130
144
 
131
- def define_relations(action)
132
- target_klass = action[:target_klass]
133
- action_type = action[:action_type]
134
- action_name = action[:action_name]
135
-
136
- user_klass = self
137
-
138
- # user, person
139
- user_name = user_klass.table_name.underscore.singularize
140
-
141
- # like_topic, follow_user
142
- full_action_name = [action_type, action_name].join("_")
143
- # like_user, follow_user
144
- full_action_name_for_target = [action_type, "by", user_name].join("_")
145
- # unlike_topic, unfollow_user
146
- unaction_name = "un#{full_action_name}"
147
-
148
- # @target.like_topic_actions, @target.follow_user_actions
149
- has_many_name = [full_action_name, "actions"].join("_").to_sym
150
- # @target.like_topics, @target.follow_users
151
- has_many_through_name = full_action_name.pluralize.to_sym
152
-
153
- # @user.like_by_user_actions, @user.follow_by_user_actions
154
- has_many_name_for_target = [full_action_name_for_target, "actions"].join("_").to_sym
155
- # @user.like_by_users, @user.follow_by_users
156
- has_many_through_name_for_target = full_action_name_for_target.pluralize.to_sym
157
-
158
- has_many_scope = -> {
159
- where(action_type: action_type, target_type: target_klass.name, user_type: user_klass.name)
160
- }
161
-
162
- # User has_many :like_topic_actions
163
- user_klass.send :has_many, has_many_name, has_many_scope,
164
- class_name: "Action",
165
- foreign_key: "user_id"
166
- # User has_many :like_topics
167
- user_klass.send :has_many, has_many_through_name,
168
- through: has_many_name,
169
- source: :target,
170
- source_type: target_klass.name
171
-
172
- # Topic has_many :like_user_actions
173
- target_klass.send :has_many, has_many_name_for_target, has_many_scope,
174
- foreign_key: :target_id,
175
- class_name: "Action"
176
- # Topic has_many :like_users
177
- target_klass.send :has_many, has_many_through_name_for_target,
178
- through: has_many_name_for_target,
179
- source_type: user_klass.name,
180
- source: :user
181
-
182
- # @user.like_topic
183
- user_klass.send(:define_method, full_action_name) do |target_or_id|
184
- target_id = target_or_id.is_a?(target_klass) ? target_or_id.id : target_or_id
185
- result = user_klass.create_action(action_type, target_type: target_klass.name,
186
- target_id: target_id,
187
- user: self)
188
- self.reload
189
- result
190
- end
191
-
192
- # @user.like_topic?
193
- user_klass.send(:define_method, "#{full_action_name}?") do |target_or_id|
194
- target_id = target_or_id.is_a?(target_klass) ? target_or_id.id : target_or_id
195
- result = user_klass.find_action(action_type, target_type: target_klass.name,
145
+ def define_relations(target_klass:, action_klass:, action_type:, action_name:)
146
+ user_klass = self
147
+
148
+ # user, person
149
+ user_name = user_klass.table_name.underscore.singularize
150
+
151
+ # like_topic, follow_user
152
+ full_action_name = [action_type, action_name].join("_")
153
+ # like_user, follow_user
154
+ full_action_name_for_target = [action_type, "by", user_name].join("_")
155
+ # unlike_topic, unfollow_user
156
+ unaction_name = "un#{full_action_name}"
157
+
158
+ # @target.like_topic_actions, @target.follow_user_actions
159
+ has_many_name = [full_action_name, "actions"].join("_").to_sym
160
+ # @target.like_topics, @target.follow_users
161
+ has_many_through_name = full_action_name.pluralize.to_sym
162
+
163
+ # @user.like_by_user_actions, @user.follow_by_user_actions
164
+ has_many_name_for_target = [full_action_name_for_target, "actions"].join("_").to_sym
165
+ # @user.like_by_users, @user.follow_by_users
166
+ has_many_through_name_for_target = full_action_name_for_target.pluralize.to_sym
167
+
168
+ has_many_scope = lambda {
169
+ where(action_type: action_type, target_type: target_klass.name, user_type: user_klass.name)
170
+ }
171
+
172
+ # User has_many :like_topic_actions
173
+ user_klass.send :has_many, has_many_name, has_many_scope,
174
+ class_name: action_klass.name,
175
+ foreign_key: "user_id"
176
+ # User has_many :like_topics
177
+ user_klass.send :has_many, has_many_through_name,
178
+ through: has_many_name,
179
+ source: :target,
180
+ source_type: target_klass.name
181
+
182
+ # Topic has_many :like_user_actions
183
+ target_klass.send :has_many, has_many_name_for_target, has_many_scope,
184
+ foreign_key: :target_id,
185
+ class_name: action_klass.name
186
+ # Topic has_many :like_users
187
+ target_klass.send :has_many, has_many_through_name_for_target,
188
+ through: has_many_name_for_target,
189
+ source_type: user_klass.name,
190
+ source: :user
191
+
192
+ # @user.like_topic
193
+ user_klass.send(:define_method, full_action_name) do |target_or_id|
194
+ target_id = target_or_id.is_a?(target_klass) ? target_or_id.id : target_or_id
195
+ result = user_klass.create_action(action_type, target_type: target_klass.name,
196
196
  target_id: target_id,
197
197
  user: self)
198
- result.present?
199
- end
200
-
201
- # @user.unlike_topic
202
- user_klass.send(:define_method, unaction_name) do |target_or_id|
203
- target_id = target_or_id.is_a?(target_klass) ? target_or_id.id : target_or_id
204
- result = user_klass.destroy_action(action_type, target_type: target_klass.name,
205
- target_id: target_id,
206
- user: self)
207
- self.reload
208
- result
209
- end
198
+ target_or_id.reload if target_or_id.is_a?(target_klass)
199
+ reload
200
+ result
210
201
  end
211
202
 
212
- def safe_action_opts(opts)
213
- opts ||= {}
214
- if opts[:user]
215
- opts[:user_id] = opts[:user].id
216
- opts[:user_type] = opts[:user].class.name
217
- end
218
- if opts[:target]
219
- opts[:target_type] = opts[:target].class.name
220
- opts[:target_id] = opts[:target].id
221
- end
222
- opts
203
+ # @user.like_topic?
204
+ user_klass.send(:define_method, "#{full_action_name}?") do |target_or_id|
205
+ target_id = target_or_id.is_a?(target_klass) ? target_or_id.id : target_or_id
206
+ result = user_klass.find_action(action_type, target_type: target_klass.name,
207
+ target_id: target_id,
208
+ user: self)
209
+ result.present?
223
210
  end
224
211
 
225
- def where_opts(opts)
226
- opts.extract!(:action_type, :target_type, :target_id, :user_id, :user_type)
212
+ # @user.unlike_topic
213
+ user_klass.send(:define_method, unaction_name) do |target_or_id|
214
+ target_id = target_or_id.is_a?(target_klass) ? target_or_id.id : target_or_id
215
+ result = user_klass.destroy_action(action_type, target_type: target_klass.name,
216
+ target_id: target_id,
217
+ user: self)
218
+ target_or_id.reload if target_or_id.is_a?(target_klass)
219
+ reload
220
+ result
227
221
  end
222
+ end
223
+
224
+ def safe_action_opts(opts)
225
+ opts ||= {}
226
+ if opts[:user]
227
+ opts[:user_id] = opts[:user].id
228
+ opts[:user_type] = opts[:user].class.name
229
+ end
230
+ if opts[:target]
231
+ opts[:target_type] = opts[:target].class.name
232
+ opts[:target_id] = opts[:target].id
233
+ end
234
+ opts
235
+ end
236
+
237
+ def where_opts(opts)
238
+ opts.extract!(:action_type, :target_type, :target_id, :user_id, :user_type)
239
+ end
228
240
  end
229
241
  end
230
242
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module ActionStore
3
4
  module Model
4
5
  extend ActiveSupport::Concern
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module ActionStore
3
- VERSION = "0.3.3"
4
+ VERSION = "1.1.0"
4
5
  end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "rails/generators"
3
4
  module ActionStore
4
5
  module Generators
5
6
  class InstallGenerator < Rails::Generators::Base
6
7
  desc "Create ActionStore's base files"
7
- source_root File.expand_path("../../../../", __FILE__)
8
+ source_root File.expand_path("../../..", __dir__)
8
9
 
9
10
  def add_initializer
10
11
  template "config/initializers/action_store.rb", "config/initializers/action_store.rb"
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action-store
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Lee
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2017-02-04 00:00:00.000000000 Z
@@ -14,18 +14,24 @@ dependencies:
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.2'
20
+ - - "<"
18
21
  - !ruby/object:Gem::Version
19
- version: '5'
22
+ version: '7'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '5.2'
30
+ - - "<"
25
31
  - !ruby/object:Gem::Version
26
- version: '5'
32
+ version: '7'
27
33
  - !ruby/object:Gem::Dependency
28
- name: mysql2
34
+ name: codecov
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - ">="
@@ -39,7 +45,7 @@ dependencies:
39
45
  - !ruby/object:Gem::Version
40
46
  version: '0'
41
47
  - !ruby/object:Gem::Dependency
42
- name: factory_girl
48
+ name: factory_bot
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
51
  - - ">="
@@ -53,7 +59,7 @@ dependencies:
53
59
  - !ruby/object:Gem::Version
54
60
  version: '0'
55
61
  - !ruby/object:Gem::Dependency
56
- name: simplecov
62
+ name: pg
57
63
  requirement: !ruby/object:Gem::Requirement
58
64
  requirements:
59
65
  - - ">="
@@ -67,7 +73,7 @@ dependencies:
67
73
  - !ruby/object:Gem::Version
68
74
  version: '0'
69
75
  - !ruby/object:Gem::Dependency
70
- name: codecov
76
+ name: simplecov
71
77
  requirement: !ruby/object:Gem::Requirement
72
78
  requirements:
73
79
  - - ">="
@@ -94,6 +100,7 @@ files:
94
100
  - app/models/action.rb
95
101
  - config/initializers/action_store.rb
96
102
  - db/migrate/20170204035500_create_actions.rb
103
+ - db/migrate/20181121052638_add_unique_index_to_actions.rb
97
104
  - lib/action-store.rb
98
105
  - lib/action_store/configuration.rb
99
106
  - lib/action_store/engine.rb
@@ -105,7 +112,7 @@ homepage: https://github.com/rails-engine/action-store
105
112
  licenses:
106
113
  - MIT
107
114
  metadata: {}
108
- post_install_message:
115
+ post_install_message:
109
116
  rdoc_options: []
110
117
  require_paths:
111
118
  - lib
@@ -120,9 +127,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
127
  - !ruby/object:Gem::Version
121
128
  version: '0'
122
129
  requirements: []
123
- rubyforge_project:
124
- rubygems_version: 2.7.6
125
- signing_key:
130
+ rubygems_version: 3.1.4
131
+ signing_key:
126
132
  specification_version: 4
127
133
  summary: Store difference kind of actions (Like, Follow, Star, Block ...) in one table.
128
134
  test_files: []