acts_as_saveable 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.