neutral 0.0.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.
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
+