neutral 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +194 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +143 -0
  7. data/Rakefile +21 -0
  8. data/app/assets/stylesheets/neutral/index.css +43 -0
  9. data/app/controllers/neutral/application_controller.rb +22 -0
  10. data/app/controllers/neutral/votes_controller.rb +48 -0
  11. data/app/helpers/neutral/votes_helper.rb +16 -0
  12. data/app/models/neutral/vote.rb +26 -0
  13. data/app/models/neutral/voting.rb +39 -0
  14. data/app/views/neutral/votes/create.js.erb +27 -0
  15. data/app/views/neutral/votes/destroy.js.erb +18 -0
  16. data/app/views/neutral/votes/errors/cannot_change.js.erb +9 -0
  17. data/app/views/neutral/votes/errors/duplicate.js.erb +9 -0
  18. data/app/views/neutral/votes/errors/require_login.js.erb +10 -0
  19. data/app/views/neutral/votes/update.js.erb +11 -0
  20. data/bin/rails +8 -0
  21. data/config/locales/impartial.yml +6 -0
  22. data/config/routes.rb +3 -0
  23. data/lib/generators/neutral/formats.rb +16 -0
  24. data/lib/generators/neutral/install/install_generator.rb +47 -0
  25. data/lib/generators/neutral/install/templates/initializer.rb +41 -0
  26. data/lib/generators/neutral/install/templates/locale.yml +5 -0
  27. data/lib/generators/neutral/install/templates/votes.rb +12 -0
  28. data/lib/generators/neutral/install/templates/votings.rb +12 -0
  29. data/lib/generators/neutral/uninstall/templates/drop_neutral_votes_table.rb +9 -0
  30. data/lib/generators/neutral/uninstall/templates/drop_neutral_votings_table.rb +9 -0
  31. data/lib/generators/neutral/uninstall/uninstall_generator.rb +55 -0
  32. data/lib/neutral/configuration.rb +27 -0
  33. data/lib/neutral/engine.rb +28 -0
  34. data/lib/neutral/errors.rb +11 -0
  35. data/lib/neutral/helpers/action_view_extension.rb +19 -0
  36. data/lib/neutral/helpers/routes.rb +9 -0
  37. data/lib/neutral/icons/collection.rb +55 -0
  38. data/lib/neutral/icons/set.rb +22 -0
  39. data/lib/neutral/model/active_record_extension.rb +31 -0
  40. data/lib/neutral/model/vote_cached.rb +32 -0
  41. data/lib/neutral/version.rb +3 -0
  42. data/lib/neutral/voting_builder/builder.rb +42 -0
  43. data/lib/neutral/voting_builder/elements/link.rb +46 -0
  44. data/lib/neutral/voting_builder/elements/span.rb +41 -0
  45. data/lib/neutral/voting_builder/elements.rb +23 -0
  46. data/lib/neutral/voting_builder/router.rb +45 -0
  47. data/lib/neutral/voting_builder/structure.rb +21 -0
  48. data/lib/neutral.rb +46 -0
  49. data/neutral.gemspec +34 -0
  50. data/spec/controllers/votes_controller_spec.rb +138 -0
  51. data/spec/dummy/Rakefile +6 -0
  52. data/spec/dummy/app/assets/images/.keep +0 -0
  53. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  54. data/spec/dummy/app/assets/stylesheets/application.css +29 -0
  55. data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
  56. data/spec/dummy/app/controllers/application_controller.rb +11 -0
  57. data/spec/dummy/app/controllers/posts_controller.rb +33 -0
  58. data/spec/dummy/app/controllers/sessions_controller.rb +21 -0
  59. data/spec/dummy/app/controllers/users_controller.rb +24 -0
  60. data/spec/dummy/app/models/.keep +0 -0
  61. data/spec/dummy/app/models/post.rb +3 -0
  62. data/spec/dummy/app/models/user.rb +7 -0
  63. data/spec/dummy/app/views/layouts/application.html.erb +25 -0
  64. data/spec/dummy/app/views/posts/_form.html.erb +21 -0
  65. data/spec/dummy/app/views/posts/index.html.erb +26 -0
  66. data/spec/dummy/app/views/posts/new.html.erb +5 -0
  67. data/spec/dummy/app/views/sessions/new.html.erb +18 -0
  68. data/spec/dummy/app/views/users/_form.html.erb +25 -0
  69. data/spec/dummy/app/views/users/new.html.erb +3 -0
  70. data/spec/dummy/bin/bundle +3 -0
  71. data/spec/dummy/bin/rails +4 -0
  72. data/spec/dummy/bin/rake +4 -0
  73. data/spec/dummy/config/application.rb +29 -0
  74. data/spec/dummy/config/boot.rb +5 -0
  75. data/spec/dummy/config/database.yml +25 -0
  76. data/spec/dummy/config/environment.rb +5 -0
  77. data/spec/dummy/config/environments/development.rb +29 -0
  78. data/spec/dummy/config/environments/production.rb +80 -0
  79. data/spec/dummy/config/environments/test.rb +36 -0
  80. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  81. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  82. data/spec/dummy/config/initializers/neutral.rb +41 -0
  83. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  84. data/spec/dummy/config/initializers/session_store.rb +3 -0
  85. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  86. data/spec/dummy/config/locales/en.yml +23 -0
  87. data/spec/dummy/config/locales/neutral.yml +5 -0
  88. data/spec/dummy/config/routes.rb +13 -0
  89. data/spec/dummy/config.ru +4 -0
  90. data/spec/dummy/db/migrate/20140110214145_create_posts.rb +9 -0
  91. data/spec/dummy/db/migrate/20140111225442_create_users.rb +10 -0
  92. data/spec/dummy/db/migrate/20140118172808881589_create_neutral_votes.rb +12 -0
  93. data/spec/dummy/db/migrate/20140118172808882161_create_neutral_votings.rb +12 -0
  94. data/spec/dummy/db/schema.rb +47 -0
  95. data/spec/dummy/lib/assets/.keep +0 -0
  96. data/spec/dummy/log/.keep +0 -0
  97. data/spec/dummy/public/404.html +58 -0
  98. data/spec/dummy/public/422.html +58 -0
  99. data/spec/dummy/public/500.html +57 -0
  100. data/spec/dummy/public/favicon.ico +0 -0
  101. data/spec/factories.rb +18 -0
  102. data/spec/helpers/action_view_extension_spec.rb +45 -0
  103. data/spec/icons/collection_spec.rb +38 -0
  104. data/spec/icons/set_spec.rb +25 -0
  105. data/spec/models/active_record_extension_spec.rb +49 -0
  106. data/spec/models/vote_spec.rb +51 -0
  107. data/spec/models/voting_spec.rb +60 -0
  108. data/spec/spec_helper.rb +47 -0
  109. data/spec/support/shared_examples/controller_examples.rb +45 -0
  110. data/spec/support/votes_controller_base_class.rb +28 -0
  111. data/spec/support/votes_controller_helpers.rb +24 -0
  112. data/spec/voting_builder/builder_spec.rb +66 -0
  113. data/spec/voting_builder/elements/link_spec.rb +31 -0
  114. data/spec/voting_builder/elements/span_spec.rb +44 -0
  115. data/spec/voting_builder/router_spec.rb +57 -0
  116. data/spec/voting_builder/structure_spec.rb +59 -0
  117. metadata +449 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 27678637183996203a37b3887be25f347be8a784
4
+ data.tar.gz: a76fd757d8c8e389a38fb89f94c912baf592deb3
5
+ SHA512:
6
+ metadata.gz: 6dfdec73927a16494db5b9dc5ecf8097d301c5aa995b7282e7035d0851cc0c0882a521ab4ae56bda9e8fae9c3f08427546669edcf5db73a895db84d086091652
7
+ data.tar.gz: aabe39f28693e565acaace9c7c897c32f7a698c878f0a1063ca69225037e1354da49804005763f7b9bbb416a9a83be9296709461188a5f0c9bfd95ce1432197e
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ coverage/**/*
5
+ spec/dummy/db/*.sqlite3
6
+ spec/dummy/db/*.sqlite3-journal
7
+ spec/dummy/log/*.log
8
+ spec/dummy/tmp/
9
+ spec/dummy/.sass-cache
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,194 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ neutral (0.0.1)
5
+ font-awesome-rails (~> 4.0.3.1)
6
+ jquery-rails
7
+ rails (~> 4.0.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionmailer (4.0.2)
13
+ actionpack (= 4.0.2)
14
+ mail (~> 2.5.4)
15
+ actionpack (4.0.2)
16
+ activesupport (= 4.0.2)
17
+ builder (~> 3.1.0)
18
+ erubis (~> 2.7.0)
19
+ rack (~> 1.5.2)
20
+ rack-test (~> 0.6.2)
21
+ activemodel (4.0.2)
22
+ activesupport (= 4.0.2)
23
+ builder (~> 3.1.0)
24
+ activerecord (4.0.2)
25
+ activemodel (= 4.0.2)
26
+ activerecord-deprecated_finders (~> 1.0.2)
27
+ activesupport (= 4.0.2)
28
+ arel (~> 4.0.0)
29
+ activerecord-deprecated_finders (1.0.3)
30
+ activesupport (4.0.2)
31
+ i18n (~> 0.6, >= 0.6.4)
32
+ minitest (~> 4.2)
33
+ multi_json (~> 1.3)
34
+ thread_safe (~> 0.1)
35
+ tzinfo (~> 0.3.37)
36
+ arel (4.0.1)
37
+ atomic (1.1.14)
38
+ bcrypt-ruby (3.0.1)
39
+ builder (3.1.4)
40
+ capybara (2.2.1)
41
+ mime-types (>= 1.16)
42
+ nokogiri (>= 1.3.3)
43
+ rack (>= 1.0.0)
44
+ rack-test (>= 0.5.4)
45
+ xpath (~> 2.0)
46
+ coderay (1.1.0)
47
+ columnize (0.3.6)
48
+ database_cleaner (1.2.0)
49
+ debugger (1.6.5)
50
+ columnize (>= 0.3.1)
51
+ debugger-linecache (~> 1.2.0)
52
+ debugger-ruby_core_source (~> 1.3.1)
53
+ debugger-linecache (1.2.0)
54
+ debugger-ruby_core_source (1.3.1)
55
+ diff-lcs (1.2.5)
56
+ docile (1.1.1)
57
+ erubis (2.7.0)
58
+ factory_girl (4.2.0)
59
+ activesupport (>= 3.0.0)
60
+ factory_girl_rails (4.2.1)
61
+ factory_girl (~> 4.2.0)
62
+ railties (>= 3.0.0)
63
+ faraday (0.8.7)
64
+ multipart-post (~> 1.1)
65
+ ffaker (1.22.1)
66
+ font-awesome-rails (4.0.3.1)
67
+ railties (>= 3.2, < 5.0)
68
+ hike (1.2.3)
69
+ httpauth (0.2.0)
70
+ i18n (0.6.9)
71
+ jquery-rails (3.0.4)
72
+ railties (>= 3.0, < 5.0)
73
+ thor (>= 0.14, < 2.0)
74
+ jwt (0.1.8)
75
+ multi_json (>= 1.5)
76
+ libv8 (3.16.14.3)
77
+ mail (2.5.4)
78
+ mime-types (~> 1.16)
79
+ treetop (~> 1.4.8)
80
+ method_source (0.8.2)
81
+ mime-types (1.25.1)
82
+ mini_portile (0.5.2)
83
+ minitest (4.7.5)
84
+ multi_json (1.8.2)
85
+ multipart-post (1.2.0)
86
+ nokogiri (1.6.1)
87
+ mini_portile (~> 0.5.0)
88
+ oauth (0.4.7)
89
+ oauth2 (0.8.1)
90
+ faraday (~> 0.8)
91
+ httpauth (~> 0.1)
92
+ jwt (~> 0.1.4)
93
+ multi_json (~> 1.0)
94
+ rack (~> 1.2)
95
+ polyglot (0.3.3)
96
+ pry (0.9.12.4)
97
+ coderay (~> 1.0)
98
+ method_source (~> 0.8)
99
+ slop (~> 3.4)
100
+ pry-rails (0.3.2)
101
+ pry (>= 0.9.10)
102
+ rack (1.5.2)
103
+ rack-test (0.6.2)
104
+ rack (>= 1.0)
105
+ rails (4.0.2)
106
+ actionmailer (= 4.0.2)
107
+ actionpack (= 4.0.2)
108
+ activerecord (= 4.0.2)
109
+ activesupport (= 4.0.2)
110
+ bundler (>= 1.3.0, < 2.0)
111
+ railties (= 4.0.2)
112
+ sprockets-rails (~> 2.0.0)
113
+ railties (4.0.2)
114
+ actionpack (= 4.0.2)
115
+ activesupport (= 4.0.2)
116
+ rake (>= 0.8.7)
117
+ thor (>= 0.18.1, < 2.0)
118
+ rake (10.1.1)
119
+ ref (1.0.5)
120
+ remarkable (3.1.13)
121
+ rspec (>= 1.2.0)
122
+ remarkable_activerecord (3.1.13)
123
+ remarkable (~> 3.1.13)
124
+ rspec (>= 1.2.0)
125
+ rspec (2.14.1)
126
+ rspec-core (~> 2.14.0)
127
+ rspec-expectations (~> 2.14.0)
128
+ rspec-mocks (~> 2.14.0)
129
+ rspec-core (2.14.7)
130
+ rspec-expectations (2.14.4)
131
+ diff-lcs (>= 1.1.3, < 2.0)
132
+ rspec-mocks (2.14.4)
133
+ rspec-rails (2.14.1)
134
+ actionpack (>= 3.0)
135
+ activemodel (>= 3.0)
136
+ activesupport (>= 3.0)
137
+ railties (>= 3.0)
138
+ rspec-core (~> 2.14.0)
139
+ rspec-expectations (~> 2.14.0)
140
+ rspec-mocks (~> 2.14.0)
141
+ shoulda-matchers (2.4.0)
142
+ activesupport (>= 3.0.0)
143
+ simplecov (0.8.2)
144
+ docile (~> 1.1.0)
145
+ multi_json
146
+ simplecov-html (~> 0.8.0)
147
+ simplecov-html (0.8.0)
148
+ slop (3.4.7)
149
+ sorcery (0.8.2)
150
+ bcrypt-ruby (~> 3.0.0)
151
+ oauth (~> 0.4.4)
152
+ oauth2 (~> 0.8.0)
153
+ sprockets (2.10.1)
154
+ hike (~> 1.2)
155
+ multi_json (~> 1.0)
156
+ rack (~> 1.0)
157
+ tilt (~> 1.1, != 1.3.0)
158
+ sprockets-rails (2.0.1)
159
+ actionpack (>= 3.0)
160
+ activesupport (>= 3.0)
161
+ sprockets (~> 2.8)
162
+ sqlite3 (1.3.8)
163
+ therubyracer (0.12.0)
164
+ libv8 (~> 3.16.14.0)
165
+ ref
166
+ thor (0.18.1)
167
+ thread_safe (0.1.3)
168
+ atomic
169
+ tilt (1.4.1)
170
+ treetop (1.4.15)
171
+ polyglot
172
+ polyglot (>= 0.3.1)
173
+ tzinfo (0.3.38)
174
+ xpath (2.0.0)
175
+ nokogiri (~> 1.3)
176
+
177
+ PLATFORMS
178
+ ruby
179
+
180
+ DEPENDENCIES
181
+ capybara
182
+ database_cleaner
183
+ debugger
184
+ factory_girl_rails (~> 4.2.1)
185
+ ffaker
186
+ neutral!
187
+ pry-rails
188
+ remarkable_activerecord
189
+ rspec-rails
190
+ shoulda-matchers
191
+ simplecov
192
+ sorcery
193
+ sqlite3
194
+ therubyracer
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
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,143 @@
1
+ # Neutral
2
+
3
+ Neutral is a rails engine providing ajaxful positive/negative voting solution for your ActiveRecord objects along with couple of additional features.
4
+
5
+ ![Preview](images/neutral.png)
6
+
7
+ ## Installation
8
+
9
+ Add following into your Gemfile
10
+
11
+ gem 'neutral'
12
+
13
+ Run
14
+
15
+ $ bundle
16
+  
17
+ Or install it yourself as
18
+
19
+ $ gem install neutral
20
+
21
+ ### Generation
22
+
23
+ Generate required files using
24
+
25
+ $ rails g neutral:install
26
+
27
+ And proceed to migrate newly created migration files
28
+
29
+ $ rake db:migrate
30
+
31
+ ## Usage
32
+
33
+ Make your ActiveRecord model voteable
34
+
35
+ class Post < ActiveRecord::Base
36
+ neutral
37
+ end
38
+
39
+ And select your voter model
40
+
41
+ class User < ActiveRecord::Base
42
+ neutral_voter
43
+ end
44
+
45
+ *Note: If your voter model is not User configure this setting inside neutral.rb [intializer](https://github.com/petertoth/neutral#configuring-neutral)*
46
+
47
+ To display voting use `voting_for` helper in your view : 
48
+
49
+ <%= voting_for post %>
50
+
51
+ ## Customization
52
+
53
+ ### View
54
+
55
+ You can also pass two additional options to `voting_for` helper
56
+
57
+ * **[icons](https://github.com/petertoth/neutral#font-awesome)** : Icons used for positive/negative/remove
58
+ * **difference** : Display difference count instead of positive/negative counts
59
+ <br>*If the difference is positive i.e positive votes - negative votes > 0 then the color of the span is green, red otherwise*
60
+
61
+ Example : 
62
+
63
+ <%= voting_for article, icons: :myfabulousicons, difference: true %>
64
+
65
+ ### Configuring Neutral
66
+
67
+ In *config/initializers/neutral.rb* you can configure these options :
68
+
69
+ * **can_change** : Determine wheter a voter can change(update,delete) his vote
70
+ * **current_voter_method** : This is most typically `current_user` but if not, change this to your own representation of a voter instance e.g `current_client` or `current_customer`. Also make sure it accessible from your ApplicationController.
71
+ * **require_login** : Voter is/is not required to be authenticated in order to vote. Setting to false is not recommended
72
+ * **vote_owner_class** : Configure an owner of a vote. Pass string of class name of the model you added `neutral_voter` into. For example `'User'`, `'Client'` or `'Customer'`
73
+ * **default_icon_set** : This icon set is used when no explicit icon set is passed to `voting_for` helper
74
+
75
+ ### Font Awesome
76
+
77
+ This engine enables you to define your own icon sets using FontAwesome icons that provide representation of voting related actions such as like, dislike, remove, plus, minus, whatever ...
78
+
79
+ You can use any [FontAwesome icon class](http://fontawesome.io/icons/) available
80
+
81
+ Define an icon set in your *neutral.rb* initializer
82
+
83
+ ```
84
+ #config/initializers/neutral.rb
85
+
86
+ Neutral.define do
87
+ set :myicons do
88
+ positive "fa-thumbs-up"
89
+ negative "fa-thumbs-down"
90
+ remove "fa-times"
91
+   end
92
+
93
+ set :fabulous do
94
+ positive "fa-plus"
95
+ # If any of action is omitted, definition from your default icon set is used.
96
+ # In this case "fa-thumbs-down-o" would be used for negative and "fa-times" 
97
+ # for remove action because because :thumbs(default set) contains these definitions.
98
+ end
99
+ end
100
+ ```
101
+
102
+ Finally use it as follows :
103
+
104
+ <%= voting_for voteable, icons: :myicons %>
105
+
106
+ If you ever need to access a definition of a given icon set proceed analogically as follows : `Neutral.icons.thumbs.positive`
107
+
108
+ ## i18n
109
+
110
+ Define your custom error messages for each of your locale in *config/locales/neutral.yml*
111
+
112
+ en:
113
+ errors:
114
+ duplication: "You have already selected this option!"
115
+ cannot_change: "You are not permitted to change the vote!"
116
+ require_login : "You must be logged in to vote!"
117
+
118
+ ## Uninstallation
119
+
120
+ Run : 
121
+
122
+ $ rails g neutral:uninstall
123
+
124
+ It :
125
+
126
+ * comments `neutral` in your *routes.rb*
127
+
128
+ * removes `require neutral` from your stylesheet manifest
129
+
130
+ * removes *neutral.rb* initializer
131
+ * removes *neutral.yml* locale file
132
+ * removes database entities(engine's tables) and migration files - **optional**
133
+
134
+ ## Contributing
135
+
136
+ 1. Fork it
137
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
138
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
139
+ 4. Push to the branch (`git push origin my-new-feature`)
140
+ 5. Create new Pull Request
141
+
142
+ ## License
143
+ MIT License. Copyright (c) 2014
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Neutral'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
@@ -0,0 +1,43 @@
1
+ /*
2
+ *= require font-awesome
3
+ *= require_self
4
+ *= require_tree .
5
+ */
6
+
7
+ div.neutral a {
8
+ display: inline;
9
+ margin: 0 4px;
10
+ color: inherit;
11
+ outline: none;
12
+ }
13
+
14
+ div.neutral a:hover {
15
+ border: none;
16
+ opacity: .8;
17
+ text-decoration: none;
18
+ }
19
+
20
+ div.neutral a.remove {
21
+ opacity: .4;
22
+ }
23
+
24
+ div.neutral i {
25
+ font-size: 1.2em;
26
+ }
27
+
28
+ div.neutral span {
29
+ display: inline;
30
+ }
31
+
32
+ div.neutral span#positive, div.neutral span.positive {
33
+ color: green;
34
+ }
35
+
36
+ div.neutral span#negative, div.neutral span.negative {
37
+ color: red;
38
+ }
39
+
40
+ div.neutral span.error {
41
+ margin-left: 5px;
42
+ color: red;
43
+ }
@@ -0,0 +1,22 @@
1
+ module Neutral
2
+ class ApplicationController < ::ApplicationController
3
+ protect_from_forgery
4
+
5
+ rescue_from Errors::RequireLogin, with: :require_login
6
+ rescue_from Errors::CannotChange, with: :cannot_change
7
+ rescue_from Errors::DuplicateVote, with: :duplicate
8
+
9
+ private
10
+ def require_login
11
+ render 'neutral/votes/errors/require_login'
12
+ end
13
+
14
+ def cannot_change
15
+ render 'neutral/votes/errors/cannot_change'
16
+ end
17
+
18
+ def duplicate
19
+ render 'neutral/votes/errors/duplicate'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,48 @@
1
+ require_dependency 'application_controller'
2
+
3
+ module Neutral
4
+ class VotesController < ApplicationController
5
+ layout false
6
+
7
+ before_filter :require_login?, only: :create
8
+ before_filter :can_change?, except: :create
9
+
10
+ def create
11
+ @vote = Vote.create(vote_params)
12
+ end
13
+
14
+ def update
15
+ vote.update_attributes(value: params[:value])
16
+ end
17
+
18
+ def destroy
19
+ vote.destroy
20
+ end
21
+
22
+ helper_method :vote, :voting
23
+ def vote
24
+ @vote ||= Vote.find_by(id: params[:id]) || Vote.new(vote_params)
25
+ end
26
+
27
+ def voting
28
+ @voting ||= vote.voting || Voting.new
29
+ end
30
+
31
+ private
32
+ def require_login?
33
+ raise Errors::RequireLogin if Neutral.config.require_login && !current_voter
34
+ end
35
+
36
+ def can_change?
37
+ raise Errors::CannotChange unless Neutral.config.can_change && authorized?
38
+ end
39
+
40
+ def vote_params
41
+ params.require(:vote).permit(:voteable_type, :voteable_id, :value).merge voter_id: current_voter.try(:id)
42
+ end
43
+
44
+ def authorized?
45
+ current_voter == vote.voter
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ module Neutral
2
+ module VotesHelper
3
+ def by_url
4
+ return raw "a[href*='#{request.post? ? votes_path : vote_path}']"
5
+ end
6
+
7
+ def vote_path(value=[1,0].sample)
8
+ raw neutral.vote_path(vote, value: value)
9
+ end
10
+
11
+ def votes_path(value=[1,0].sample)
12
+ raw neutral.votes_path(vote: vote.main_attributes.update(value: value))
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,26 @@
1
+ module Neutral
2
+ class Vote < ActiveRecord::Base
3
+ before_update :avoid_duplication
4
+
5
+ validates_inclusion_of :value, in: [0,1]
6
+ validates_presence_of :voteable_type, :voteable_id, :value
7
+
8
+ belongs_to :voteable, polymorphic: true
9
+ belongs_to :voter, class_name: Neutral.config.vote_owner_class.classify
10
+
11
+ include Neutral::Model::VoteCached
12
+
13
+ def nature
14
+ value == 1 ? :positive : :negative
15
+ end
16
+
17
+ def main_attributes
18
+ attributes.symbolize_keys.except(:id, :voter_id, :created_at, :updated_at)
19
+ end
20
+
21
+ private
22
+ def avoid_duplication
23
+ raise Errors::DuplicateVote unless self.changed?
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ module Neutral
2
+ class Voting < ActiveRecord::Base
3
+ before_destroy :delete_votes
4
+
5
+ belongs_to :votingable, polymorphic: true
6
+
7
+ delegate :votes, to: :votingable
8
+
9
+ def difference
10
+ positive - negative
11
+ end
12
+
13
+ def self.init(vote)
14
+ create(votingable_type: vote.voteable_type, votingable_id: vote.voteable_id) do |voting|
15
+ voting.increment(vote.nature)
16
+ end
17
+ end
18
+
19
+ def add_to_existing(nature)
20
+ increment!(nature)
21
+ end
22
+
23
+ def edit(nature)
24
+ increment(nature)
25
+ decrement(nature==:positive ? :negative : :positive)
26
+ save
27
+ end
28
+
29
+ def remove(nature)
30
+ decrement!(nature)
31
+ end
32
+
33
+ private
34
+
35
+ def delete_votes
36
+ votes.delete_all
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ $(document).ready(function() {
2
+
3
+ neutral = $("div.neutral").find("<%= by_url %>").parent();
4
+
5
+ neutral.find("span#positive").html("<%= voting.positive.nonzero? %>");
6
+ neutral.find("span#negative").html("<%= voting.negative.nonzero? %>");
7
+ neutral.find("span#difference").html("<%= voting.difference.nonzero?.try(:abs) %>");
8
+
9
+ neutral.find("span#difference").attr("class", "<%= voting.difference > 0 ? 'positive' : 'negative' %>");
10
+
11
+ <% if vote.voter_id && Neutral.config.can_change %>
12
+
13
+ neutral.find("a[class!='remove']").data('method', 'patch');
14
+ neutral.find("a[class!='remove']").attr('data-method', 'patch');
15
+ neutral.find("a.positive").attr('href', '<%= vote_path(1) %>');
16
+ neutral.find("a.negative").attr('href', '<%= vote_path(0) %>');
17
+
18
+ neutral.append('<%= escape_javascript(
19
+ Neutral::VotingBuilder::Elements::Link::Remove.new(
20
+ Neutral::VotingBuilder::Router.new(vote)[:remove],
21
+ Neutral.icons.send(Neutral.config.default_icon_set).send(:remove)).to_s
22
+ )
23
+ %>');
24
+
25
+ <% end %>
26
+
27
+ });
@@ -0,0 +1,18 @@
1
+ $(document).ready(function() {
2
+
3
+ neutral = $("div.neutral").find("<%= by_url %>").parent();
4
+
5
+ neutral.find("a[class!='remove']").data('method', 'post');
6
+ neutral.find("a[class!='remove']").attr('data-method', 'post');
7
+ neutral.find("a.positive").attr('href', '<%= votes_path(1) %>');
8
+ neutral.find("a.negative").attr('href', '<%= votes_path(0) %>');
9
+
10
+ neutral.find("span#positive").html("<%= voting.positive.nonzero? %>");
11
+ neutral.find("span#negative").html("<%= voting.negative.nonzero? %>");
12
+ neutral.find("span#difference").html("<%= voting.difference.nonzero?.try(:abs) %>");
13
+
14
+ neutral.find("span#difference").attr("class", "<%= voting.difference > 0 ? 'positive' : 'negative' %>");
15
+
16
+ neutral.find("a.remove").remove();
17
+
18
+ });
@@ -0,0 +1,9 @@
1
+ $(document).ready(function() {
2
+
3
+ neutral = $("div.neutral").find("<%= by_url %>").parent();
4
+
5
+ neutral.find("span.error").remove();
6
+
7
+ $("<span class='error'><%= t('errors.cannot_change') %></span>").appendTo(neutral).delay(4000).hide(0);
8
+
9
+ });
@@ -0,0 +1,9 @@
1
+ $(document).ready(function() {
2
+
3
+ neutral = $("div.neutral").find("<%= by_url %>").parent();
4
+
5
+ neutral.find("span.error").remove();
6
+
7
+ $("<span class='error'><%= t('errors.duplication') %></span>").appendTo(neutral).delay(4000).hide(0);
8
+
9
+ });
@@ -0,0 +1,10 @@
1
+ $(document).ready(function() {
2
+
3
+ neutral = $("div.neutral").find("<%= by_url %>").parent();
4
+
5
+ neutral.find("span.error").remove();
6
+
7
+ $("<span class='error'><%= t('errors.require_login') %></span>").appendTo(neutral).delay(4000).hide(0);
8
+
9
+ });
10
+