acts_as_starrable 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +46 -0
  4. data/app/assets/javascripts/application.js +15 -0
  5. data/app/assets/javascripts/jquery.rateit.min.js +2 -0
  6. data/app/assets/javascripts/starrable.js +35 -0
  7. data/app/assets/stylesheets/application.css +13 -0
  8. data/app/assets/stylesheets/rateit.css +98 -0
  9. data/app/controllers/application_controller.rb +5 -0
  10. data/app/controllers/ratings_controller.rb +15 -0
  11. data/app/helpers/application_helper.rb +5 -0
  12. data/app/views/layouts/application.html.erb +14 -0
  13. data/app/views/starrable/_stars.html.erb +6 -0
  14. data/config/routes.rb +4 -0
  15. data/lib/acts_as_starrable/engine.rb +13 -0
  16. data/lib/acts_as_starrable/rating.rb +10 -0
  17. data/lib/acts_as_starrable/starrable.rb +39 -0
  18. data/lib/acts_as_starrable/starrable_helper.rb +10 -0
  19. data/lib/acts_as_starrable/version.rb +4 -0
  20. data/lib/acts_as_starrable.rb +10 -0
  21. data/lib/generators/acts_as_starrable/migration/migration_generator.rb +40 -0
  22. data/lib/generators/acts_as_starrable/migration/templates/active_record/migration.rb +17 -0
  23. data/lib/tasks/acts_as_starrable_tasks.rake +4 -0
  24. data/spec/controllers/ratings_controller_spec.rb +35 -0
  25. data/spec/dummy/Gemfile +38 -0
  26. data/spec/dummy/Gemfile.lock +114 -0
  27. data/spec/dummy/README.rdoc +261 -0
  28. data/spec/dummy/Rakefile +7 -0
  29. data/spec/dummy/app/assets/images/rails.png +0 -0
  30. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  31. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  32. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  33. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  34. data/spec/dummy/app/models/flick.rb +4 -0
  35. data/spec/dummy/app/models/user.rb +3 -0
  36. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  37. data/spec/dummy/config/application.rb +62 -0
  38. data/spec/dummy/config/boot.rb +6 -0
  39. data/spec/dummy/config/database.yml +25 -0
  40. data/spec/dummy/config/environment.rb +5 -0
  41. data/spec/dummy/config/environments/development.rb +37 -0
  42. data/spec/dummy/config/environments/production.rb +67 -0
  43. data/spec/dummy/config/environments/test.rb +37 -0
  44. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  45. data/spec/dummy/config/initializers/inflections.rb +15 -0
  46. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  47. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  48. data/spec/dummy/config/initializers/session_store.rb +8 -0
  49. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  50. data/spec/dummy/config/locales/en.yml +5 -0
  51. data/spec/dummy/config/routes.rb +58 -0
  52. data/spec/dummy/config.ru +4 -0
  53. data/spec/dummy/db/development.sqlite3 +0 -0
  54. data/spec/dummy/db/migrate/20140409035450_create_flicks.rb +9 -0
  55. data/spec/dummy/db/migrate/20140409041520_create_users.rb +9 -0
  56. data/spec/dummy/db/migrate/20140412132501_acts_as_starrable_migration.rb +16 -0
  57. data/spec/dummy/db/schema.rb +39 -0
  58. data/spec/dummy/db/seeds.rb +8 -0
  59. data/spec/dummy/db/test.sqlite3 +0 -0
  60. data/spec/dummy/doc/README_FOR_APP +2 -0
  61. data/spec/dummy/log/development.log +158 -0
  62. data/spec/dummy/log/test.log +627 -0
  63. data/spec/dummy/public/404.html +26 -0
  64. data/spec/dummy/public/422.html +26 -0
  65. data/spec/dummy/public/500.html +25 -0
  66. data/spec/dummy/public/favicon.ico +0 -0
  67. data/spec/dummy/public/index.html +241 -0
  68. data/spec/dummy/public/robots.txt +5 -0
  69. data/spec/dummy/script/rails +6 -0
  70. data/spec/dummy/tmp/cache/assets/CF0/DA0/sprockets%2Fd7d5b37686831d37c4dd75e645f5e016 +0 -0
  71. data/spec/dummy/tmp/cache/assets/E25/4C0/sprockets%2Fde2fd9fd11c04a582cdbbe3d84a35ae6 +0 -0
  72. data/spec/factories.rb +11 -0
  73. data/spec/models/flick_spec.rb +10 -0
  74. data/spec/models/user_spec.rb +10 -0
  75. data/spec/spec_helper.rb +30 -0
  76. metadata +301 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Alexander Clark
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.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = ActsAsStarrable
2
+
3
+ Acts as Starrable allows you to easily add star ratings to Rails models.
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ begin
9
+ require 'rdoc/task'
10
+ rescue LoadError
11
+ require 'rdoc/rdoc'
12
+ require 'rake/rdoctask'
13
+ RDoc::Task = Rake::RDocTask
14
+ end
15
+
16
+ RDoc::Task.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'ActsAsStarrable'
19
+ rdoc.options << '--line-numbers'
20
+ rdoc.rdoc_files.include('README.rdoc')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ task :console do
25
+ require 'irb'
26
+ require 'irb/completion'
27
+ require 'acts_as_starrable'
28
+ ARGV.clear
29
+ IRB.start
30
+ end
31
+
32
+
33
+ APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
34
+ load 'rails/tasks/engine.rake'
35
+
36
+ Bundler::GemHelper.install_tasks
37
+
38
+ Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
39
+
40
+ require 'rspec/core'
41
+ require 'rspec/core/rake_task'
42
+
43
+ desc "Run all specs in spec directory (excluding plugin specs)"
44
+ RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
45
+
46
+ task default: :spec
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,2 @@
1
+ (function(n){function t(n){var u=n.originalEvent.changedTouches,t=u[0],i="",r;switch(n.type){case"touchmove":i="mousemove";break;case"touchend":i="mouseup";break;default:return}r=document.createEvent("MouseEvent"),r.initMouseEvent(i,!0,!0,window,1,t.screenX,t.screenY,t.clientX,t.clientY,!1,!1,!1,!1,0,null),t.target.dispatchEvent(r),n.preventDefault()}n.rateit={aria:{resetLabel:"reset rating",ratingLabel:"rating"}},n.fn.rateit=function(i,r){var e=1,u={},o="init",s=function(n){return n.charAt(0).toUpperCase()+n.substr(1)},f;if(this.length==0)return this;if(f=n.type(i),f=="object"||i===undefined||i==null)u=n.extend({},n.fn.rateit.defaults,i);else{if(f=="string"&&r===undefined)return this.data("rateit"+s(i));f=="string"&&(o="setvalue")}return this.each(function(){var c=n(this),f=function(n,t){if(t!=null){var i="aria-value"+(n=="value"?"now":n),r=c.find(".rateit-range");r.attr(i)!=undefined&&r.attr(i,t)}return arguments[0]="rateit"+s(n),c.data.apply(c,arguments)},v,h,b,k,l,y,p,a;if(c.hasClass("rateit")||c.addClass("rateit"),v=c.css("direction")!="rtl",o=="setvalue"){if(!f("init"))throw"Can't set value before init";i!="readonly"||r!=!0||f("readonly")||(c.find(".rateit-range").unbind(),f("wired",!1)),i=="value"&&(r=r==null?f("min"):Math.max(f("min"),Math.min(f("max"),r))),f("backingfld")&&(h=n(f("backingfld")),i=="value"&&h.val(r),i=="min"&&h[0].min&&(h[0].min=r),i=="max"&&h[0].max&&(h[0].max=r),i=="step"&&h[0].step&&(h[0].step=r)),f(i,r)}f("init")||(f("min",f("min")||u.min),f("max",f("max")||u.max),f("step",f("step")||u.step),f("readonly",f("readonly")!==undefined?f("readonly"):u.readonly),f("resetable",f("resetable")!==undefined?f("resetable"):u.resetable),f("backingfld",f("backingfld")||u.backingfld),f("starwidth",f("starwidth")||u.starwidth),f("starheight",f("starheight")||u.starheight),f("value",Math.max(f("min"),Math.min(f("max"),f("value")||u.value||u.min))),f("ispreset",f("ispreset")!==undefined?f("ispreset"):u.ispreset),f("backingfld")&&(h=n(f("backingfld")),f("value",h.hide().val()),(h.attr("disabled")||h.attr("readonly"))&&f("readonly",!0),h[0].nodeName=="INPUT"&&(h[0].type=="range"||h[0].type=="text")&&(f("min",parseInt(h.attr("min"))||f("min")),f("max",parseInt(h.attr("max"))||f("max")),f("step",parseInt(h.attr("step"))||f("step"))),h[0].nodeName=="SELECT"&&h[0].options.length>1&&(f("min",Number(h[0].options[0].value)),f("max",Number(h[0].options[h[0].length-1].value)),f("step",Number(h[0].options[1].value)-Number(h[0].options[0].value)))),b=c[0].nodeName=="DIV"?"div":"span",e++,k='<button id="rateit-reset-{{index}}" class="rateit-reset" aria-label="'+n.rateit.aria.resetLabel+'" aria-controls="rateit-range-{{index}}"><\/button><{{element}} id="rateit-range-{{index}}" class="rateit-range" tabindex="0" role="slider" aria-label="'+n.rateit.aria.ratingLabel+'" aria-owns="rateit-reset-{{index}}" aria-valuemin="'+f("min")+'" aria-valuemax="'+f("max")+'" aria-valuenow="'+f("value")+'"><{{element}} class="rateit-selected" style="height:'+f("starheight")+'px"><\/{{element}}><{{element}} class="rateit-hover" style="height:'+f("starheight")+'px"><\/{{element}}><\/{{element}}>',c.append(k.replace(/{{index}}/gi,e).replace(/{{element}}/gi,b)),v||(c.find(".rateit-reset").css("float","right"),c.find(".rateit-selected").addClass("rateit-selected-rtl"),c.find(".rateit-hover").addClass("rateit-hover-rtl")),f("init",!0)),l=c.find(".rateit-range"),l.width(f("starwidth")*(f("max")-f("min"))).height(f("starheight")),y="rateit-preset"+(v?"":"-rtl"),f("ispreset")?c.find(".rateit-selected").addClass(y):c.find(".rateit-selected").removeClass(y),f("value")!=null&&(p=(f("value")-f("min"))*f("starwidth"),c.find(".rateit-selected").width(p)),a=c.find(".rateit-reset"),a.data("wired")!==!0&&a.bind("click",function(t){t.preventDefault(),a.blur(),f("value",f("min")),l.find(".rateit-hover").hide().width(0),l.find(".rateit-selected").width(0).show(),f("backingfld")&&n(f("backingfld")).val(f("min")),c.trigger("reset")}).data("wired",!0);var d=function(t,i){var u=i.changedTouches?i.changedTouches[0].pageX:i.pageX,r=u-n(t).offset().left;return v||(r=l.width()-r),r>l.width()&&(r=l.width()),r<0&&(r=0),p=Math.ceil(r/f("starwidth")*(1/f("step")))},g=function(n){var t=n*f("starwidth")*f("step"),r=l.find(".rateit-hover"),i;r.data("width")!=t&&(l.find(".rateit-selected").hide(),r.width(t).show().data("width",t),i=[n*f("step")+f("min")],c.trigger("hover",i).trigger("over",i))},w=function(t){f("value",t),f("backingfld")&&n(f("backingfld")).val(t),f("ispreset")&&(l.find(".rateit-selected").removeClass(y),f("ispreset",!1)),l.find(".rateit-hover").hide(),l.find(".rateit-selected").width(t*f("starwidth")-f("min")*f("starwidth")).show(),c.trigger("hover",[null]).trigger("over",[null]).trigger("rated",[t])};f("readonly")?a.hide():(f("resetable")||a.hide(),f("wired")||(l.bind("touchmove touchend",t),l.mousemove(function(n){var t=d(this,n);g(t)}),l.mouseleave(function(){l.find(".rateit-hover").hide().width(0).data("width",""),c.trigger("hover",[null]).trigger("over",[null]),l.find(".rateit-selected").show()}),l.mouseup(function(n){var t=d(this,n),i=t*f("step")+f("min");w(i)}),l.keyup(function(n){(n.which==38||n.which==(v?39:37))&&w(Math.min(f("value")+f("step"),f("max"))),(n.which==40||n.which==(v?37:39))&&w(Math.max(f("value")-f("step"),f("min")))}),f("wired",!0)),f("resetable")&&a.show()),l.attr("aria-readonly",f("readonly"))})},n.fn.rateit.defaults={min:0,max:5,step:.5,starwidth:16,starheight:16,readonly:!1,resetable:!0,ispreset:!1},n(function(){n("div.rateit, span.rateit").rateit()})})(jQuery);
2
+ //@ sourceMappingURL=jquery.rateit.min.js.map
@@ -0,0 +1,35 @@
1
+ $(document).ready(function() {
2
+ // $.getJSON('products/124.json', function(data) {
3
+ // $("div[data-productid=423]").attr('data-rateit-value', data.average_rating / 2);
4
+ // $("div[data-productid=423]").attr('data-rateit-ispreset', true);
5
+ // /*var items = [];
6
+ // $.each(data, function(key, val) {
7
+ // items.push('<li id=""' + key + '">' + val + '</li>');
8
+ // });*/
9
+ // });
10
+
11
+ $('.rateit').bind('rated reset', function (e) {
12
+ console.log("hello");
13
+ var ri = $(this);
14
+
15
+ //if the use pressed reset, it will get value: 0 (to be compatible with the HTML range control), we could check if e.type == 'reset', and then set the value to null .
16
+ var value = ri.rateit('value');
17
+ var rateableID = ri.data('rateableid'); // if the product id was in some hidden field: ri.closest('li').find('input[name="productid"]').val()
18
+ var stype = 'Gallery';
19
+
20
+ //maybe we want to disable voting?
21
+ //ri.rateit('readonly', true);
22
+
23
+ $.ajax({
24
+ url: '/starrable/ratings.json', //your server side script
25
+ data: { id: rateableID, value: value, stype: stype }, //our data
26
+ type: 'POST',
27
+ success: function (data) {
28
+ //$('#response').append('<li>' + data + '</li>');
29
+ },
30
+ error: function (jxhr, msg, err) {
31
+ //$('#response').append('<li style="color:red">' + msg + '</li>');
32
+ }
33
+ });
34
+ });
35
+ });
@@ -0,0 +1,13 @@
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 vendor/assets/stylesheets of plugins, if any, 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 top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,98 @@
1
+ .rateit {
2
+ display: -moz-inline-box;
3
+ display: inline-block;
4
+ position: relative;
5
+ -webkit-user-select: none;
6
+ -khtml-user-select: none;
7
+ -moz-user-select: none;
8
+ -o-user-select: none;
9
+ -ms-user-select: none;
10
+ user-select: none;
11
+ -webkit-touch-callout: none;
12
+ }
13
+
14
+ .rateit .rateit-range
15
+ {
16
+ position: relative;
17
+ display: -moz-inline-box;
18
+ display: inline-block;
19
+ background: url(star.gif);
20
+ height: 16px;
21
+ outline: none;
22
+ }
23
+
24
+ .rateit .rateit-range * {
25
+ display:block;
26
+ }
27
+
28
+ /* for IE 6 */
29
+ * html .rateit, * html .rateit .rateit-range
30
+ {
31
+ display: inline;
32
+ }
33
+
34
+ /* for IE 7 */
35
+ * + html .rateit, * + html .rateit .rateit-range
36
+ {
37
+ display: inline;
38
+ }
39
+
40
+ .rateit .rateit-hover, .rateit .rateit-selected
41
+ {
42
+ position: absolute;
43
+ left: 0px;
44
+ }
45
+
46
+ .rateit .rateit-hover-rtl, .rateit .rateit-selected-rtl
47
+ {
48
+ left: auto;
49
+ right: 0px;
50
+ }
51
+
52
+ .rateit .rateit-hover
53
+ {
54
+ background: url(star.gif) left -32px;
55
+ }
56
+
57
+ .rateit .rateit-hover-rtl
58
+ {
59
+ background-position: right -32px;
60
+ }
61
+
62
+ .rateit .rateit-selected
63
+ {
64
+ background: url(star.gif) left -16px;
65
+ }
66
+
67
+ .rateit .rateit-selected-rtl
68
+ {
69
+ background-position: right -16px;
70
+ }
71
+
72
+ .rateit .rateit-preset
73
+ {
74
+ background: url(star.gif) left -48px;
75
+ }
76
+
77
+ .rateit .rateit-preset-rtl
78
+ {
79
+ background: url(star.gif) left -48px;
80
+ }
81
+
82
+ .rateit button.rateit-reset
83
+ {
84
+ background: url(delete.gif) 0 0;
85
+ width: 16px;
86
+ height: 16px;
87
+ display: -moz-inline-box;
88
+ display: inline-block;
89
+ float: left;
90
+ outline: none;
91
+ border:none;
92
+ padding: 0;
93
+ }
94
+
95
+ .rateit button.rateit-reset:hover, .rateit button.rateit-reset:focus
96
+ {
97
+ background-position: 0 -16px;
98
+ }
@@ -0,0 +1,5 @@
1
+ # Encoding: utf-8
2
+ module ActsAsStarrable
3
+ class ApplicationController < ActionController::Base
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ # Encoding: utf-8
2
+ class RatingsController < ApplicationController
3
+ respond_to :json
4
+
5
+ def create
6
+ @rating = ::ActsAsStarrable::Rating.new(:starrable_type => params[:stype],
7
+ :starrable_id => params[:id],
8
+ :rating => params[:value])
9
+ if @rating.save
10
+ render :json => @rating, :status => :created
11
+ else
12
+ render :json => @rating.errors, :status => :unprocessable_entity
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ # Encoding: utf-8
2
+ module ActsAsStarrable
3
+ module ApplicationHelper
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>ActsAsStarrable</title>
5
+ <%= stylesheet_link_tag "acts_as_starrable/application", :media => "all" %>
6
+ <%= javascript_include_tag "acts_as_starrable/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,6 @@
1
+ <div class="rateit" data-rateableid="<%= @gallery.id %>" data-rateit-value="<%= @gallery.average_rating %>" data-rateit-ispreset="true"></div>
2
+ <span itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">
3
+ <span itemprop="ratingValue"><%= starrable.average_rating %></span> stars out of
4
+ <span itemprop="bestRating"><%= starrable.max_rating %></span>
5
+ (<span itemprop="ratingCount"><%= pluralize(starrable.ratings.count, 'rating') %></span> total).
6
+ </span>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ # Encoding: utf-8
2
+ Rails.application.routes.draw do
3
+ resources :ratings, :only => [:create]
4
+ end
@@ -0,0 +1,13 @@
1
+ # Encoding: utf-8
2
+ module ActsAsStarrable
3
+ class Engine < ::Rails::Engine
4
+ # isolate_namespace ActsAsStarrable
5
+
6
+ config.generators do |g|
7
+ g.test_framework :rspec, :fixture => false
8
+ g.fixture_replacement :factory_girl, :dir => 'spec/factories'
9
+ g.assets false
10
+ g.helper false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # Encoding: utf-8
2
+ module ActsAsStarrable
3
+ class Rating < ::ActiveRecord::Base
4
+ attr_accessible :starrable_id, :starrable_type, :rater_id, :rater_type,
5
+ :rating
6
+
7
+ belongs_to :starrable, :polymorphic => true
8
+ belongs_to :rater, :polymorphic => true
9
+ end
10
+ end
@@ -0,0 +1,39 @@
1
+ # Encoding: utf-8
2
+ module ActsAsStarrable
3
+ module Starrable
4
+ def starrable?
5
+ false
6
+ end
7
+
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ end
12
+
13
+ module ClassMethods
14
+ def acts_as_starrable
15
+ has_many :ratings, :as => :starrable, :dependent => :destroy,
16
+ :class_name => 'ActsAsStarrable::Rating'
17
+ include ActsAsStarrable::Starrable::LocalInstanceMethods
18
+ end
19
+ end
20
+
21
+ module LocalInstanceMethods
22
+ def starrable?
23
+ true
24
+ end
25
+
26
+ def average_rating
27
+ if avg = ratings.average('rating')
28
+ (avg * 2).round / 2.0 # round to nearest .5 or .0
29
+ end
30
+ end
31
+
32
+ def max_rating
33
+ 5
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ ActiveRecord::Base.send :include, ActsAsStarrable::Starrable
@@ -0,0 +1,10 @@
1
+ # Encoding: utf-8
2
+ module ActsAsStarrable
3
+ module StarrableHelper
4
+ def stars(starrable)
5
+ render :partial => 'starrable/stars', :locals => {
6
+ :starrable => starrable
7
+ }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ # Encoding: utf-8
2
+ module ActsAsStarrable
3
+ VERSION = '0.0.1'
4
+ end
@@ -0,0 +1,10 @@
1
+ # Encoding: utf-8
2
+ require 'acts_as_starrable/engine'
3
+ require 'acts_as_starrable/starrable'
4
+ require 'acts_as_starrable/starrable_helper'
5
+ require 'acts_as_starrable/rating'
6
+
7
+ module ActsAsStarrable
8
+ end
9
+
10
+ ActionView::Base.send :include, ActsAsStarrable::StarrableHelper
@@ -0,0 +1,40 @@
1
+ # Encoding: utf-8
2
+ require 'rails/generators'
3
+ require 'rails/generators/migration'
4
+
5
+ module ActsAsStarrable
6
+ class MigrationGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+
9
+ desc 'Generates migration for Rating model'
10
+
11
+ def self.orm
12
+ Rails::Generators.options[:rails][:orm]
13
+ end
14
+
15
+ def self.source_root
16
+ File.join(File.dirname(__FILE__), 'templates',
17
+ (orm.to_s unless orm.class.eql?(String)))
18
+ end
19
+
20
+ def self.orm_has_migration?
21
+ [:active_record].include? orm
22
+ end
23
+
24
+ def self.next_migration_number(dirname)
25
+ if ActiveRecord::Base.timestamped_migrations
26
+ migration_number = Time.now.utc.strftime('%Y%m%d%H%M%S').to_i
27
+ migration_number += 1
28
+ migration_number.to_s
29
+ else
30
+ '%.3d' % (current_migration_number(dirname) + 1)
31
+ end
32
+ end
33
+
34
+ def create_migration_file
35
+ if self.class.orm_has_migration?
36
+ migration_template 'migration.rb', 'db/migrate/acts_as_starrable_migration'
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ # Encoding: utf-8
2
+ class ActsAsStarrableMigration < ActiveRecord::Migration
3
+ def self.up
4
+ create_table :ratings do |t|
5
+ t.belongs_to :starrable, :polymorphic => true
6
+ t.belongs_to :rater, :polymorphic => true
7
+ t.integer :rating
8
+ end
9
+
10
+ add_index :ratings, [:starrable_id, :starrable_type]
11
+ add_index :ratings, [:rater_id, :rater_type]
12
+ end
13
+
14
+ def self.down
15
+ drop_table :ratings
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :acts_as_starrable do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe RatingsController do
4
+
5
+ let(:instance) { mock_model(ActsAsStarrable::Rating) }
6
+
7
+ describe '#create' do
8
+
9
+ context 'success' do
10
+
11
+ before do
12
+ expect(ActsAsStarrable::Rating).to receive(:new).and_return(instance)
13
+ expect(instance).to receive(:save).and_return(true)
14
+ post :create, :format => 'json', :rating => { :id => '1',
15
+ :stype => 'Flick',
16
+ :value => '2.5'}
17
+ end
18
+
19
+ it { should respond_with 201 }
20
+ end
21
+
22
+ context 'failure' do
23
+
24
+ before do
25
+ expect(ActsAsStarrable::Rating).to receive(:new).and_return(instance)
26
+ expect(instance).to receive(:save).and_return(false)
27
+ post :create, :format => 'json', :rating => { :id => '1',
28
+ :stype => 'Flick',
29
+ :value => '2.5'}
30
+ end
31
+
32
+ it { should respond_with 422 }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,38 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '3.2.12'
4
+
5
+ # Bundle edge Rails instead:
6
+ # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
+
8
+ gem 'sqlite3'
9
+ gem 'acts_as_starrable'
10
+
11
+ # Gems used only for assets and not required
12
+ # in production environments by default.
13
+ group :assets do
14
+ gem 'sass-rails', '~> 3.2.3'
15
+ gem 'coffee-rails', '~> 3.2.1'
16
+
17
+ # See https://github.com/sstephenson/execjs#readme for more supported runtimes
18
+ # gem 'therubyracer', :platforms => :ruby
19
+
20
+ gem 'uglifier', '>= 1.0.3'
21
+ end
22
+
23
+ gem 'jquery-rails'
24
+
25
+ # To use ActiveModel has_secure_password
26
+ # gem 'bcrypt-ruby', '~> 3.0.0'
27
+
28
+ # To use Jbuilder templates for JSON
29
+ # gem 'jbuilder'
30
+
31
+ # Use unicorn as the app server
32
+ # gem 'unicorn'
33
+
34
+ # Deploy with Capistrano
35
+ # gem 'capistrano'
36
+
37
+ # To use debugger
38
+ # gem 'debugger'
@@ -0,0 +1,114 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ actionmailer (3.2.12)
5
+ actionpack (= 3.2.12)
6
+ mail (~> 2.4.4)
7
+ actionpack (3.2.12)
8
+ activemodel (= 3.2.12)
9
+ activesupport (= 3.2.12)
10
+ builder (~> 3.0.0)
11
+ erubis (~> 2.7.0)
12
+ journey (~> 1.0.4)
13
+ rack (~> 1.4.5)
14
+ rack-cache (~> 1.2)
15
+ rack-test (~> 0.6.1)
16
+ sprockets (~> 2.2.1)
17
+ activemodel (3.2.12)
18
+ activesupport (= 3.2.12)
19
+ builder (~> 3.0.0)
20
+ activerecord (3.2.12)
21
+ activemodel (= 3.2.12)
22
+ activesupport (= 3.2.12)
23
+ arel (~> 3.0.2)
24
+ tzinfo (~> 0.3.29)
25
+ activeresource (3.2.12)
26
+ activemodel (= 3.2.12)
27
+ activesupport (= 3.2.12)
28
+ activesupport (3.2.12)
29
+ i18n (~> 0.6)
30
+ multi_json (~> 1.0)
31
+ acts_as_starrable (0.0.1)
32
+ rails (~> 3.2.12)
33
+ arel (3.0.3)
34
+ builder (3.0.4)
35
+ coffee-rails (3.2.2)
36
+ coffee-script (>= 2.2.0)
37
+ railties (~> 3.2.0)
38
+ coffee-script (2.2.0)
39
+ coffee-script-source
40
+ execjs
41
+ coffee-script-source (1.7.0)
42
+ erubis (2.7.0)
43
+ execjs (2.0.2)
44
+ hike (1.2.3)
45
+ i18n (0.6.9)
46
+ journey (1.0.4)
47
+ jquery-rails (3.1.0)
48
+ railties (>= 3.0, < 5.0)
49
+ thor (>= 0.14, < 2.0)
50
+ json (1.8.1)
51
+ mail (2.4.4)
52
+ i18n (>= 0.4.0)
53
+ mime-types (~> 1.16)
54
+ treetop (~> 1.4.8)
55
+ mime-types (1.25.1)
56
+ multi_json (1.8.4)
57
+ polyglot (0.3.3)
58
+ rack (1.4.5)
59
+ rack-cache (1.2)
60
+ rack (>= 0.4)
61
+ rack-ssl (1.3.3)
62
+ rack
63
+ rack-test (0.6.2)
64
+ rack (>= 1.0)
65
+ rails (3.2.12)
66
+ actionmailer (= 3.2.12)
67
+ actionpack (= 3.2.12)
68
+ activerecord (= 3.2.12)
69
+ activeresource (= 3.2.12)
70
+ activesupport (= 3.2.12)
71
+ bundler (~> 1.0)
72
+ railties (= 3.2.12)
73
+ railties (3.2.12)
74
+ actionpack (= 3.2.12)
75
+ activesupport (= 3.2.12)
76
+ rack-ssl (~> 1.3.2)
77
+ rake (>= 0.8.7)
78
+ rdoc (~> 3.4)
79
+ thor (>= 0.14.6, < 2.0)
80
+ rake (10.1.1)
81
+ rdoc (3.12.2)
82
+ json (~> 1.4)
83
+ sass (3.2.14)
84
+ sass-rails (3.2.6)
85
+ railties (~> 3.2.0)
86
+ sass (>= 3.1.10)
87
+ tilt (~> 1.3)
88
+ sprockets (2.2.2)
89
+ hike (~> 1.2)
90
+ multi_json (~> 1.0)
91
+ rack (~> 1.0)
92
+ tilt (~> 1.1, != 1.3.0)
93
+ sqlite3 (1.3.8)
94
+ thor (0.18.1)
95
+ tilt (1.4.1)
96
+ treetop (1.4.15)
97
+ polyglot
98
+ polyglot (>= 0.3.1)
99
+ tzinfo (0.3.38)
100
+ uglifier (2.4.0)
101
+ execjs (>= 0.3.0)
102
+ json (>= 1.8.0)
103
+
104
+ PLATFORMS
105
+ ruby
106
+
107
+ DEPENDENCIES
108
+ acts_as_starrable
109
+ coffee-rails (~> 3.2.1)
110
+ jquery-rails
111
+ rails (= 3.2.12)
112
+ sass-rails (~> 3.2.3)
113
+ sqlite3
114
+ uglifier (>= 1.0.3)