acts_as_saveable 0.10.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 81a949caf1bba42241830a88be68d00886de121d
4
+ data.tar.gz: ab7296ff429963a29162f78f2f80fc7e66cea096
5
+ SHA512:
6
+ metadata.gz: 5f257d6d0cb5cee42b9d2c336f1fb1a3c3b64074b14bcead7a71ac71fa6abdc7a4d4d6f3779bdc47de246e957a3ccce9c860d897d18f23c69ce740970d4292b4
7
+ data.tar.gz: 5c908749e2adbe8e55176ba9f2c435345b20a073adb699d959cf9b8581f825f34439760a444d39e5665aa1ed09d9d83ba307be705fd249300c15f64af9078af2
@@ -0,0 +1,6 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ nbproject/*
5
+ Gemfile.lock
6
+ bin
@@ -0,0 +1,25 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.0
8
+ env:
9
+ - "RAILS_VERSION=3.0.0"
10
+ - "RAILS_VERSION=3.1.0"
11
+ - "RAILS_VERSION=3.2.0"
12
+ - "RAILS_VERSION=4.0.0"
13
+ - "RAILS_VERSION=4.1.0"
14
+ matrix:
15
+ exclude:
16
+ - rvm: 1.8.7
17
+ env: "RAILS_VERSION=4.0.0"
18
+ - rvm: 1.9.2
19
+ env: "RAILS_VERSION=4.0.0"
20
+ - rvm: 1.8.7
21
+ env: "RAILS_VERSION=4.1.0"
22
+ - rvm: 1.9.2
23
+ env: "RAILS_VERSION=4.1.0"
24
+ - rvm: 1.9.3
25
+ env: "RAILS_VERSION=4.1.0"
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in acts_as_saveable.gemspec
4
+ gemspec
5
+
6
+ rails_version = ENV['RAILS_VERSION'] || 'default'
7
+
8
+ rails = case rails_version
9
+ when 'master'
10
+ { :github => 'rails/rails'}
11
+ when 'default'
12
+ '~> 3.2.0'
13
+ else
14
+ "~> #{rails_version}"
15
+ end
16
+
17
+ gem 'rails', rails
@@ -0,0 +1,399 @@
1
+ # Acts As Saveable (aka Acts As Read-Later)
2
+
3
+ Acts As Saveable is a Ruby Gem specifically written for Rails/ActiveRecord models.
4
+ The main goals of this gem are:
5
+
6
+ - Allow any model to be saved on, like/dislike, upsaved/downsaved, for later reading and viewing etc.
7
+ - Allow any model to be saved under arbitrary scopes.
8
+ - Allow any model to saved. In other words, saves do not have to come from a user,
9
+ they can come from any model (such as a Group or Team).
10
+ - Provide an easy to write/read syntax.
11
+
12
+ ## Installation
13
+
14
+ ### Supported Ruby and Rails versions
15
+
16
+ * Ruby 1.8.7, 1.9.2, 1.9.3
17
+ * Ruby 2.0.0, 2.1.0
18
+ * Rails 3.0, 3.1, 3.2
19
+ * Rails 4.0, 4.1+
20
+
21
+ ### Install
22
+
23
+ Just add the following to your Gemfile.
24
+
25
+ ```ruby
26
+ gem 'acts_as_saveable', '~> 0.10.0'
27
+ ```
28
+
29
+ And follow that up with a ``bundle install``.
30
+
31
+ ### Database Migrations
32
+
33
+ Acts As Saveable uses a saves table to store all saving information. To
34
+ generate and run the migration just use.
35
+
36
+ rails generate acts_as_saveable:migration
37
+ rake db:migrate
38
+
39
+ You will get a performance increase by adding in cached columns to your model's
40
+ tables. You will have to do this manually through your own migrations. See the
41
+ caching section of this document for more information.
42
+
43
+ ## Usage
44
+
45
+ ### Saveable Models
46
+
47
+ ```ruby
48
+ class Post < ActiveRecord::Base
49
+ acts_as_saveable
50
+ end
51
+
52
+ @post = Post.new(:name => 'my post!')
53
+ @post.save
54
+
55
+ @post.upsaved_by @user
56
+ @post.saves_for.size # => 1
57
+ ```
58
+
59
+ ### Like/Dislike Yes/No Up/Down
60
+
61
+ Here are some saving examples. All of these calls are valid and acceptable. The
62
+ more natural calls are the first few examples.
63
+
64
+ ```ruby
65
+ @post.upsaved_by @user1
66
+ @post.downsave_from @user2
67
+ @post.save_by :saver => @user3
68
+ @post.save_by :saver => @user4, :saved => 'bad'
69
+ @post.save_by :saver => @user5, :saved => 'like'
70
+ ```
71
+
72
+ By default all saves are positive, so `@user3` has cast a 'good' saved for `@post`.
73
+
74
+ `@user1`, `@user3`, and `@user5` all saved in favor of `@post`.
75
+
76
+ `@user2` and `@user4` on the other had has saved against `@post`.
77
+
78
+
79
+ Just about any word works for casting a saved in favor or against post. Up/Down,
80
+ Like/Dislike, Positive/Negative... the list goes on-and-on. Boolean flags `true` and
81
+ `false` are also applicable.
82
+
83
+ Revisiting the previous example of code.
84
+
85
+ ```ruby
86
+ # positive saves
87
+ @post.upsaved_by @user1
88
+ @post.save_by :saver => @user3
89
+ @post.save_by :saver => @user5, :saved => 'like'
90
+
91
+ # negative saves
92
+ @post.downsave_from @user2
93
+ @post.save_by :saver => @user2, :saved => 'bad'
94
+
95
+ # tally them up!
96
+ @post.saves_for.size # => 5
97
+ @post.get_likes.size # => 3
98
+ @post.get_upsaves.size # => 3
99
+ @post.get_dislikes.size # => 2
100
+ @post.get_downsaves.size # => 2
101
+ ```
102
+
103
+ Active Record scopes are provided to make life easier.
104
+
105
+ ```ruby
106
+ @post.saves_for.up.by_type(User)
107
+ @post.saves_for.down
108
+ @user1.saves.up
109
+ @user1.saves.down
110
+ @user1.saves.up.by_type(Post)
111
+ ```
112
+
113
+ Once scoping is complete, you can also trigger a get for the
114
+ saver/saveable
115
+
116
+ ```ruby
117
+ @post.saves_for.up.by_type(User).savers
118
+ @post.saves_for.down.by_type(User).savers
119
+
120
+ @user.saves.up.for_type(Post).saveables
121
+ @user.saves.up.saveables
122
+ ```
123
+
124
+ You can also 'unsaved' a model to remove a previous saved.
125
+
126
+ ```ruby
127
+ @post.upsaved_by @user1
128
+ @post.unsaved_by @user1
129
+ ```
130
+
131
+ Unsaving works for both positive and negative saves.
132
+
133
+ ### Examples with scopes
134
+
135
+ You can add a scope to your saved
136
+
137
+ ```ruby
138
+ # positive saves
139
+ @post.upsaved_by @user1, :save_scope => 'rank'
140
+ @post.save_by :saver => @user3, :save_scope => 'rank'
141
+ @post.save_by :saver => @user5, :saved => 'like', :save_scope => 'rank'
142
+
143
+ # negative saves
144
+ @post.downsave_from @user2, :save_scope => 'rank'
145
+ @post.save_by :saver => @user2, :saved => 'bad', :save_scope => 'rank'
146
+
147
+ # tally them up!
148
+ @post.find_saves_for(:save_scope => 'rank').size # => 5
149
+ @post.get_likes(:save_scope => 'rank').size # => 3
150
+ @post.get_upsaves(:save_scope => 'rank').size # => 3
151
+ @post.get_dislikes(:save_scope => 'rank').size # => 2
152
+ @post.get_downsaves(:save_scope => 'rank').size # => 2
153
+
154
+ # saveable model can be saved under different scopes
155
+ # by the same user
156
+ @post.save_by :saver => @user1, :save_scope => 'week'
157
+ @post.save_by :saver => @user1, :save_scope => 'month'
158
+
159
+ @post.saves_for.size # => 2
160
+ @post.find_saves_for(:save_scope => 'week').size # => 1
161
+ @post.find_saves_for(:save_scope => 'month').size # => 1
162
+ ```
163
+ ### Adding weights to your saves
164
+
165
+ You can add weight to your saved. The default value is 1.
166
+
167
+ ```ruby
168
+ # positive saves
169
+ @post.upsaved_by @user1, :save_weight => 1
170
+ @post.save_by :saver => @user3, :save_weight => 2
171
+ @post.save_by :saver => @user5, :saved => 'like', :save_scope => 'rank', :save_weight => 3
172
+
173
+ # negative saves
174
+ @post.downsave_from @user2, :save_scope => 'rank', :save_weight => 1
175
+ @post.save_by :saver => @user2, :saved => 'bad', :save_scope => 'rank', :save_weight => 3
176
+
177
+ # tally them up!
178
+ @post.find_saves_for(:save_scope => 'rank').sum(:save_weight) # => 6
179
+ @post.get_likes(:save_scope => 'rank').sum(:save_weight) # => 6
180
+ @post.get_upsaves(:save_scope => 'rank').sum(:save_weight) # => 6
181
+ @post.get_dislikes(:save_scope => 'rank').sum(:save_weight) # => 4
182
+ @post.get_downsaves(:save_scope => 'rank').sum(:save_weight) # => 4
183
+ ```
184
+
185
+ ### The Saver
186
+
187
+ You can have your savers `acts_as_saver` to provide some reserve functionality.
188
+
189
+ ```ruby
190
+ class User < ActiveRecord::Base
191
+ acts_as_saver
192
+ end
193
+
194
+ @user.likes @article
195
+
196
+ @article.saves.size # => 1
197
+ @article.likes.size # => 1
198
+ @article.dislikes.size # => 0
199
+ ```
200
+
201
+ To check if a saver has saved on a model, you can use ``saved_for?``. You can
202
+ check how the saver saved by using ``saved_as_when_saved_for``.
203
+
204
+ ```ruby
205
+ @user.likes @comment1
206
+ @user.up_saves @comment2
207
+ # user has not saved on @comment3
208
+
209
+ @user.saved_for? @comment1 # => true
210
+ @user.saved_for? @comment2 # => true
211
+ @user.saved_for? @comment3 # => false
212
+
213
+ @user.saved_as_when_saved_for @comment1 # => true, he liked it
214
+ @user.saved_as_when_saved_for @comment2 # => false, he didnt like it
215
+ @user.saved_as_when_saved_for @comment3 # => nil, he has yet to saved
216
+ ```
217
+
218
+ You can also check whether the saver has saved up or down.
219
+
220
+ ```ruby
221
+ @user.likes @comment1
222
+ @user.dislikes @comment2
223
+ # user has not saved on @comment3
224
+
225
+ @user.saved_up_on? @comment1 # => true
226
+ @user.saved_down_on? @comment1 # => false
227
+
228
+ @user.saved_down_on? @comment2 # => true
229
+ @user.saved_up_on? @comment2 # => false
230
+
231
+ @user.saved_up_on? @comment3 # => false
232
+ @user.saved_down_on? @comment3 # => false
233
+ ```
234
+
235
+ Aliases for methods `saved_up_on?` and `saved_down_on?` are: `saved_up_for?`, `saved_down_for?`, `liked?` and `disliked?`.
236
+
237
+ Also, you can obtain a list of all the objects a user has saved for.
238
+ This returns the actual objects instead of instances of the Vote model.
239
+ All objects are eager loaded
240
+
241
+ ```ruby
242
+ @user.find_saved_items
243
+
244
+ @user.find_up_saved_items
245
+ @user.find_liked_items
246
+
247
+ @user.find_down_saved_items
248
+ @user.find_disliked_items
249
+ ```
250
+
251
+ Members of an individual model that a user has saved for can also be
252
+ displayed. The result is an ActiveRecord Relation.
253
+
254
+ ```ruby
255
+ @user.get_saved Comment
256
+
257
+ @user.get_up_saved Comment
258
+
259
+ @user.get_down_saved Comment
260
+ ```
261
+
262
+ ### Registered Votes
263
+
264
+ Savers can only saved once per model. In this example the 2nd saved does not count
265
+ because `@user` has already saved for `@shoe`.
266
+
267
+ ```ruby
268
+ @user.likes @shoe
269
+ @user.likes @shoe
270
+
271
+ @shoe.saves # => 1
272
+ @shoe.likes # => 1
273
+ ```
274
+
275
+ To check if a saved counted, or registered, use `save_registered?` on your model
276
+ after saving. For example:
277
+
278
+ ```ruby
279
+ @hat.upsaved_by @user
280
+ @hat.save_registered? # => true
281
+
282
+ @hat.upsaved_by => @user
283
+ @hat.save_registered? # => false, because @user has already saved this way
284
+
285
+ @hat.dissaved_by @user
286
+ @hat.save_registered? # => true, because user changed their saved
287
+
288
+ @hat.saves.size # => 1
289
+ @hat.positives.size # => 0
290
+ @hat.negatives.size # => 1
291
+ ```
292
+
293
+ To permit duplicates entries of a same saver, use option duplicate. Also notice that this
294
+ will limit some other methods that didn't deal with multiples saves, in this case, the last saved will be considered.
295
+
296
+ ```ruby
297
+ @hat.save_by saver: @user, :duplicate => true
298
+ ```
299
+
300
+ ## Caching
301
+
302
+ To speed up perform you can add cache columns to your saveable model's table. These
303
+ columns will automatically be updated after each saved. For example, if we wanted
304
+ to speed up @post we would use the following migration:
305
+
306
+ ```ruby
307
+ class AddCachedVotesToPosts < ActiveRecord::Migration
308
+ def self.up
309
+ add_column :posts, :cached_saves_total, :integer, :default => 0
310
+ add_column :posts, :cached_saves_score, :integer, :default => 0
311
+ add_column :posts, :cached_saves_up, :integer, :default => 0
312
+ add_column :posts, :cached_saves_down, :integer, :default => 0
313
+ add_column :posts, :cached_weighted_score, :integer, :default => 0
314
+ add_column :posts, :cached_weighted_total, :integer, :default => 0
315
+ add_column :posts, :cached_weighted_average, :float, :default => 0.0
316
+ add_index :posts, :cached_saves_total
317
+ add_index :posts, :cached_saves_score
318
+ add_index :posts, :cached_saves_up
319
+ add_index :posts, :cached_saves_down
320
+ add_index :posts, :cached_weighted_score
321
+ add_index :posts, :cached_weighted_total
322
+ add_index :posts, :cached_weighted_average
323
+
324
+ # Uncomment this line to force caching of existing saves
325
+ # Post.find_each(&:update_cached_saves)
326
+ end
327
+
328
+ def self.down
329
+ remove_column :posts, :cached_saves_total
330
+ remove_column :posts, :cached_saves_score
331
+ remove_column :posts, :cached_saves_up
332
+ remove_column :posts, :cached_saves_down
333
+ remove_column :posts, :cached_weighted_score
334
+ remove_column :posts, :cached_weighted_total
335
+ remove_column :posts, :cached_weighted_average
336
+ end
337
+ end
338
+ ```
339
+
340
+ `cached_weighted_average` can be helpful for a rating system, e.g.:
341
+
342
+ Order by average rating:
343
+
344
+ ```ruby
345
+ Post.order(:cached_weighted_average => :desc)
346
+ ```
347
+
348
+ Display average rating:
349
+
350
+ ```erb
351
+ <%= post.weighted_average.round(2) %> / 5
352
+ <!-- 3.5 / 5 -->
353
+ ```
354
+
355
+ ## Testing
356
+
357
+ All tests follow the RSpec format and are located in the spec directory.
358
+ They can be run with:
359
+
360
+ ```
361
+ rake spec
362
+ ```
363
+
364
+ ## Changes
365
+
366
+ ### Fixes for saveable saver model
367
+
368
+ In version 0.8.0, there are bugs for a model that is both saveable and saver.
369
+ Some name-conflicting methods are renamed:
370
+ + Renamed Saveable.saves to saves_for
371
+ + Renamed Saveable.saved to save_by,
372
+ + Removed Saveable.save_by alias (was an alias for :save_up)
373
+ + Renamed Saveable.unsave_for to unsave_by
374
+ + Renamed Saveable.find_saves to find_saves_for
375
+ + Renamed Saveable.up_saves to get_upsaves
376
+ + and its aliases :get_true_saves, :get_ups, :get_upsaves, :get_likes, :get_positives, :get_for_saves
377
+ + Renamed Saveable.down_saves to get_downsaves
378
+ + and its aliases :get_false_saves, :get_downs, :get_downsaves, :get_dislikes, :get_negatives
379
+
380
+
381
+ ## License
382
+
383
+ Acts as saveable is released under the [MIT
384
+ License](http://www.opensource.org/licenses/MIT).
385
+
386
+ ## TODO
387
+
388
+ - Pass in a block of options when creating acts_as. Allow for things
389
+ like disabling the aliasing
390
+
391
+ - Smarter language syntax. Example: `@user.likes` will return all of the saveables
392
+ that the user likes, while `@user.likes @model` will cast a saved for @model by
393
+ @user.
394
+
395
+
396
+ - The aliased methods are referred to by using the terms 'up/down' and/or
397
+ 'true/false'. Need to come up with guidelines for naming these methods.
398
+
399
+ - Create more aliases. Specifically for counting saves and finding saves.