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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +194 -0
- data/MIT-LICENSE +20 -0
- data/README.md +143 -0
- data/Rakefile +21 -0
- data/app/assets/stylesheets/neutral/index.css +43 -0
- data/app/controllers/neutral/application_controller.rb +22 -0
- data/app/controllers/neutral/votes_controller.rb +48 -0
- data/app/helpers/neutral/votes_helper.rb +16 -0
- data/app/models/neutral/vote.rb +26 -0
- data/app/models/neutral/voting.rb +39 -0
- data/app/views/neutral/votes/create.js.erb +27 -0
- data/app/views/neutral/votes/destroy.js.erb +18 -0
- data/app/views/neutral/votes/errors/cannot_change.js.erb +9 -0
- data/app/views/neutral/votes/errors/duplicate.js.erb +9 -0
- data/app/views/neutral/votes/errors/require_login.js.erb +10 -0
- data/app/views/neutral/votes/update.js.erb +11 -0
- data/bin/rails +8 -0
- data/config/locales/impartial.yml +6 -0
- data/config/routes.rb +3 -0
- data/lib/generators/neutral/formats.rb +16 -0
- data/lib/generators/neutral/install/install_generator.rb +47 -0
- data/lib/generators/neutral/install/templates/initializer.rb +41 -0
- data/lib/generators/neutral/install/templates/locale.yml +5 -0
- data/lib/generators/neutral/install/templates/votes.rb +12 -0
- data/lib/generators/neutral/install/templates/votings.rb +12 -0
- data/lib/generators/neutral/uninstall/templates/drop_neutral_votes_table.rb +9 -0
- data/lib/generators/neutral/uninstall/templates/drop_neutral_votings_table.rb +9 -0
- data/lib/generators/neutral/uninstall/uninstall_generator.rb +55 -0
- data/lib/neutral/configuration.rb +27 -0
- data/lib/neutral/engine.rb +28 -0
- data/lib/neutral/errors.rb +11 -0
- data/lib/neutral/helpers/action_view_extension.rb +19 -0
- data/lib/neutral/helpers/routes.rb +9 -0
- data/lib/neutral/icons/collection.rb +55 -0
- data/lib/neutral/icons/set.rb +22 -0
- data/lib/neutral/model/active_record_extension.rb +31 -0
- data/lib/neutral/model/vote_cached.rb +32 -0
- data/lib/neutral/version.rb +3 -0
- data/lib/neutral/voting_builder/builder.rb +42 -0
- data/lib/neutral/voting_builder/elements/link.rb +46 -0
- data/lib/neutral/voting_builder/elements/span.rb +41 -0
- data/lib/neutral/voting_builder/elements.rb +23 -0
- data/lib/neutral/voting_builder/router.rb +45 -0
- data/lib/neutral/voting_builder/structure.rb +21 -0
- data/lib/neutral.rb +46 -0
- data/neutral.gemspec +34 -0
- data/spec/controllers/votes_controller_spec.rb +138 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +29 -0
- data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/dummy/app/controllers/application_controller.rb +11 -0
- data/spec/dummy/app/controllers/posts_controller.rb +33 -0
- data/spec/dummy/app/controllers/sessions_controller.rb +21 -0
- data/spec/dummy/app/controllers/users_controller.rb +24 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/models/user.rb +7 -0
- data/spec/dummy/app/views/layouts/application.html.erb +25 -0
- data/spec/dummy/app/views/posts/_form.html.erb +21 -0
- data/spec/dummy/app/views/posts/index.html.erb +26 -0
- data/spec/dummy/app/views/posts/new.html.erb +5 -0
- data/spec/dummy/app/views/sessions/new.html.erb +18 -0
- data/spec/dummy/app/views/users/_form.html.erb +25 -0
- data/spec/dummy/app/views/users/new.html.erb +3 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +29 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/neutral.rb +41 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/locales/neutral.yml +5 -0
- data/spec/dummy/config/routes.rb +13 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20140110214145_create_posts.rb +9 -0
- data/spec/dummy/db/migrate/20140111225442_create_users.rb +10 -0
- data/spec/dummy/db/migrate/20140118172808881589_create_neutral_votes.rb +12 -0
- data/spec/dummy/db/migrate/20140118172808882161_create_neutral_votings.rb +12 -0
- data/spec/dummy/db/schema.rb +47 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories.rb +18 -0
- data/spec/helpers/action_view_extension_spec.rb +45 -0
- data/spec/icons/collection_spec.rb +38 -0
- data/spec/icons/set_spec.rb +25 -0
- data/spec/models/active_record_extension_spec.rb +49 -0
- data/spec/models/vote_spec.rb +51 -0
- data/spec/models/voting_spec.rb +60 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/support/shared_examples/controller_examples.rb +45 -0
- data/spec/support/votes_controller_base_class.rb +28 -0
- data/spec/support/votes_controller_helpers.rb +24 -0
- data/spec/voting_builder/builder_spec.rb +66 -0
- data/spec/voting_builder/elements/link_spec.rb +31 -0
- data/spec/voting_builder/elements/span_spec.rb +44 -0
- data/spec/voting_builder/router_spec.rb +57 -0
- data/spec/voting_builder/structure_spec.rb +59 -0
- metadata +449 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Neutral
|
|
2
|
+
module VotingBuilder
|
|
3
|
+
class Router
|
|
4
|
+
include Neutral::Engine.routes.url_helpers
|
|
5
|
+
|
|
6
|
+
def initialize(vote)
|
|
7
|
+
@vote = vote
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def [](element)
|
|
11
|
+
send element
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def positive
|
|
15
|
+
if persisted?
|
|
16
|
+
{ path: vote_path(vote, value: 1), method: 'patch' }
|
|
17
|
+
else
|
|
18
|
+
{ path: votes_path(vote: vote.main_attributes.merge(value: 1)), method: 'post' }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def negative
|
|
23
|
+
if persisted?
|
|
24
|
+
{ path: vote_path(vote, value: 0), method: 'patch' }
|
|
25
|
+
else
|
|
26
|
+
{ path: votes_path(vote: vote.main_attributes.merge(value: 0)), method: 'post' }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def remove
|
|
31
|
+
raise "Remove path for non-existent vote cannot be obtained" unless persisted?
|
|
32
|
+
{ path: vote_path(vote), method: 'delete' }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
def vote
|
|
37
|
+
@vote
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def persisted?
|
|
41
|
+
vote.persisted?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Neutral
|
|
2
|
+
module VotingBuilder
|
|
3
|
+
class Structure
|
|
4
|
+
def initialize(persisted, difference)
|
|
5
|
+
@persisted = persisted
|
|
6
|
+
@difference = difference
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def to_a
|
|
10
|
+
structure = %w[positive_span positive_link difference_span negative_link negative_span remove_link]
|
|
11
|
+
structure -= %w[remove_link] unless can_change?
|
|
12
|
+
structure -= @difference ? %w[positive_span negative_span] : %w[difference_span]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
def can_change?
|
|
17
|
+
@persisted && Neutral.config.can_change
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/neutral.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require "neutral/engine"
|
|
2
|
+
|
|
3
|
+
require "jquery-rails"
|
|
4
|
+
require "font-awesome-rails"
|
|
5
|
+
|
|
6
|
+
require "neutral/engine"
|
|
7
|
+
require "neutral/configuration"
|
|
8
|
+
|
|
9
|
+
module Neutral
|
|
10
|
+
autoload :Engine, 'neutral/engine'
|
|
11
|
+
autoload :Errors, 'neutral/errors'
|
|
12
|
+
|
|
13
|
+
module Model
|
|
14
|
+
autoload :ActiveRecordExtension, 'neutral/model/active_record_extension'
|
|
15
|
+
autoload :VoteCached, 'neutral/model/vote_cached'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module VotingBuilder
|
|
19
|
+
autoload :Builder, 'neutral/voting_builder/builder'
|
|
20
|
+
autoload :Elements, 'neutral/voting_builder/elements'
|
|
21
|
+
autoload :Router, 'neutral/voting_builder/router'
|
|
22
|
+
autoload :Structure, 'neutral/voting_builder/structure'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module Helpers
|
|
26
|
+
autoload :Routes, 'neutral/helpers/routes'
|
|
27
|
+
autoload :ActionViewExtension, 'neutral/helpers/action_view_extension'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module Icons
|
|
31
|
+
autoload :Collection, 'neutral/icons/collection'
|
|
32
|
+
autoload :Set, 'neutral/icons/set'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.define(&block)
|
|
36
|
+
module_eval(&block)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.set(name, &block)
|
|
40
|
+
icons.add Icons::Set.new(name, &block)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.icons
|
|
44
|
+
@icons ||= Icons::Collection.new
|
|
45
|
+
end
|
|
46
|
+
end
|
data/neutral.gemspec
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
2
|
+
|
|
3
|
+
require "neutral/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "neutral"
|
|
7
|
+
s.version = Neutral::VERSION
|
|
8
|
+
s.authors = ["Peter Tóth"]
|
|
9
|
+
s.email = ["proximin@gmail.com"]
|
|
10
|
+
s.homepage = "https://github.com/petertoth/neutral"
|
|
11
|
+
s.summary = "Rails engine providing positive/negative ajaxful voting solution with FontAwesome integration and handful of additional features."
|
|
12
|
+
s.description = "Rails engine providing positive/negative ajaxful voting solution with FontAwesome integration and handful of additional features."
|
|
13
|
+
|
|
14
|
+
s.files = `git ls-files`.split("\n") - Dir["images/*"]
|
|
15
|
+
s.test_files = `git ls-files -- spec/**/*`.split("\n")
|
|
16
|
+
|
|
17
|
+
s.add_dependency "rails", "~> 4.0.0"
|
|
18
|
+
s.add_dependency "font-awesome-rails", "~> 4.0.3.1"
|
|
19
|
+
s.add_dependency "jquery-rails"
|
|
20
|
+
|
|
21
|
+
s.add_development_dependency "sqlite3"
|
|
22
|
+
s.add_development_dependency "simplecov"
|
|
23
|
+
s.add_development_dependency "pry-rails"
|
|
24
|
+
s.add_development_dependency "ffaker"
|
|
25
|
+
s.add_development_dependency "therubyracer"
|
|
26
|
+
s.add_development_dependency "sorcery"
|
|
27
|
+
s.add_development_dependency "rspec-rails"
|
|
28
|
+
s.add_development_dependency "capybara"
|
|
29
|
+
s.add_development_dependency "factory_girl_rails", "~> 4.2.1"
|
|
30
|
+
s.add_development_dependency "database_cleaner"
|
|
31
|
+
s.add_development_dependency "remarkable_activerecord"
|
|
32
|
+
s.add_development_dependency "shoulda-matchers"
|
|
33
|
+
s.add_development_dependency "debugger"
|
|
34
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Neutral::VotesController do
|
|
4
|
+
routes { Neutral::Engine.routes }
|
|
5
|
+
|
|
6
|
+
include VotesControllerHelpers
|
|
7
|
+
include VotesControllerBaseClass
|
|
8
|
+
|
|
9
|
+
let(:voteable) { FactoryGirl.create(:post) }
|
|
10
|
+
let(:voter) { FactoryGirl.create(:user) }
|
|
11
|
+
let(:vote) { FactoryGirl.create(:vote) }
|
|
12
|
+
|
|
13
|
+
describe "POST #create" do
|
|
14
|
+
context "when valid" do
|
|
15
|
+
context "when login required" do
|
|
16
|
+
before do
|
|
17
|
+
controller.stub(:current_user).and_return(voter)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "creates a new vote" do
|
|
21
|
+
expect { create(voteable) }.to change(Neutral::Vote, :count).by(1)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "assigns a newly created vote as @vote" do
|
|
25
|
+
create(voteable)
|
|
26
|
+
assigns(:vote).should be_a(Neutral::Vote)
|
|
27
|
+
assigns(:vote).should be_persisted
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "renders create template" do
|
|
31
|
+
expect(create(voteable)).to render_template(:create)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "when login not required " do
|
|
36
|
+
before do
|
|
37
|
+
Neutral.configure { |config| config.require_login = false }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
after do
|
|
41
|
+
Neutral.configure { |config| config.require_login = true }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "creates a new vote" do
|
|
45
|
+
expect { create(voteable) }.to change(Neutral::Vote, :count).by(1)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "assigns a newly created vote as @vote without a voter" do
|
|
49
|
+
create(voteable)
|
|
50
|
+
assigns(:vote).should be_a(Neutral::Vote)
|
|
51
|
+
assigns(:vote).voter.should be_nil
|
|
52
|
+
assigns(:vote).should be_persisted
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "renders create template" do
|
|
56
|
+
expect(create(voteable)).to render_template(:create)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context "when invalid" do
|
|
62
|
+
context "when login required" do
|
|
63
|
+
subject { -> { create(voteable) } }
|
|
64
|
+
|
|
65
|
+
it { should_not change(Neutral::Vote, :count).by(1) }
|
|
66
|
+
its(:call) { should render_template('errors/require_login') }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe "PATCH #update" do
|
|
72
|
+
context "when valid" do
|
|
73
|
+
before do
|
|
74
|
+
controller.stub(:current_user).and_return(vote.voter)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "updates given vote" do
|
|
78
|
+
update(vote)
|
|
79
|
+
vote.value.should_not == vote.reload.value
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "assigns the vote as @vote and persists" do
|
|
83
|
+
update(vote)
|
|
84
|
+
assigns(:vote).should eq(vote.reload)
|
|
85
|
+
assigns(:vote).should be_persisted
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "renders update template" do
|
|
89
|
+
expect(update(vote)).to render_template(:update)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context "when invalid" do
|
|
94
|
+
it_should_behave_like "unable to change", :update
|
|
95
|
+
|
|
96
|
+
context "when duplicated" do
|
|
97
|
+
before do
|
|
98
|
+
controller.stub(:current_user).and_return(vote.voter)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "assigns the vote as @vote" do
|
|
102
|
+
update vote, duplicate=true
|
|
103
|
+
assigns(:vote).should eq(vote)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "renders duplicate template" do
|
|
107
|
+
expect(update(vote, duplicate=true)).to render_template('errors/duplicate')
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe "DELETE #destroy" do
|
|
114
|
+
context "when valid" do
|
|
115
|
+
before do
|
|
116
|
+
controller.stub(:current_user).and_return(vote.voter)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "destroys the vote" do
|
|
120
|
+
expect { destroy(vote) }.to change(Neutral::Vote, :count).by(-1)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "assigns the vote as @vote and does not persist" do
|
|
124
|
+
destroy(vote)
|
|
125
|
+
assigns(:vote).should eq(vote)
|
|
126
|
+
assigns(:vote).should_not be_persisted
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "renders destroy template" do
|
|
130
|
+
expect(destroy(vote)).to render_template(:destroy)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context "when invalid" do
|
|
135
|
+
it_should_behave_like "unable to change", :destroy
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
data/spec/dummy/Rakefile
ADDED
|
File without changes
|
|
@@ -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
|
+
// compiled file.
|
|
9
|
+
//
|
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
|
11
|
+
// about supported directives.
|
|
12
|
+
//
|
|
13
|
+
//= require_tree
|
|
14
|
+
//= require jquery
|
|
15
|
+
//= require jquery_ujs
|
|
@@ -0,0 +1,29 @@
|
|
|
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 neutral
|
|
13
|
+
|
|
14
|
+
*= require_tree .
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
a:hover {
|
|
18
|
+
background-color: none;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#container {
|
|
22
|
+
width: 1000px;
|
|
23
|
+
margin: 0 auto;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
div.neutral a:hover {
|
|
27
|
+
background-color: none!important;
|
|
28
|
+
color: inherit;
|
|
29
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
body { background-color: #fff; color: #333; }
|
|
2
|
+
|
|
3
|
+
body, p, ol, ul, td {
|
|
4
|
+
font-family: Arial, sans-serif;
|
|
5
|
+
font-size: 13px;
|
|
6
|
+
line-height: 18px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
pre {
|
|
10
|
+
background-color: #eee;
|
|
11
|
+
padding: 10px;
|
|
12
|
+
font-size: 11px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
a { color: #000; }
|
|
16
|
+
a:visited { color: #666; }
|
|
17
|
+
a:hover { color: #fff; background-color:#000; }
|
|
18
|
+
|
|
19
|
+
div.field, div.actions {
|
|
20
|
+
margin-bottom: 10px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#notice {
|
|
24
|
+
color: green;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.field_with_errors {
|
|
28
|
+
padding: 2px;
|
|
29
|
+
background-color: red;
|
|
30
|
+
display: table;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#error_explanation {
|
|
34
|
+
width: 450px;
|
|
35
|
+
border: 2px solid red;
|
|
36
|
+
padding: 7px;
|
|
37
|
+
padding-bottom: 0;
|
|
38
|
+
margin-bottom: 20px;
|
|
39
|
+
background-color: #f0f0f0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#error_explanation h2 {
|
|
43
|
+
text-align: left;
|
|
44
|
+
font-weight: bold;
|
|
45
|
+
padding: 5px 5px 5px 15px;
|
|
46
|
+
font-size: 12px;
|
|
47
|
+
margin: -7px;
|
|
48
|
+
margin-bottom: 0px;
|
|
49
|
+
background-color: #c00;
|
|
50
|
+
color: #fff;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#error_explanation ul li {
|
|
54
|
+
font-size: 12px;
|
|
55
|
+
list-style: square;
|
|
56
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class ApplicationController < ActionController::Base
|
|
2
|
+
# Prevent CSRF attacks by raising an exception.
|
|
3
|
+
# For APIs, you may want to use :null_session instead.
|
|
4
|
+
protect_from_forgery with: :exception
|
|
5
|
+
|
|
6
|
+
helper_method :current_user
|
|
7
|
+
|
|
8
|
+
def current_user
|
|
9
|
+
@current_user ||= User.find(session[:user_id]) if session[:user_id]
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
class PostsController < ApplicationController
|
|
2
|
+
# GET /posts
|
|
3
|
+
def index
|
|
4
|
+
@posts = Post.all
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# GET /posts/new
|
|
8
|
+
def new
|
|
9
|
+
@post = Post.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# POST /posts
|
|
13
|
+
def create
|
|
14
|
+
@post = Post.new(post_params)
|
|
15
|
+
|
|
16
|
+
if @post.save
|
|
17
|
+
redirect_to @post, notice: 'Post was successfully created.'
|
|
18
|
+
else
|
|
19
|
+
render action: 'new'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
25
|
+
def set_post
|
|
26
|
+
@post = Post.find(params[:id])
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Only allow a trusted parameter "white list" through.
|
|
30
|
+
def post_params
|
|
31
|
+
params.require(:post).permit(:title)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class SessionsController < ApplicationController
|
|
2
|
+
def new
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
def create
|
|
6
|
+
user = User.authenticate(params[:username], params[:password])
|
|
7
|
+
|
|
8
|
+
if user
|
|
9
|
+
session[:user_id] = user.id
|
|
10
|
+
redirect_to root_url, notice: "Logged in!"
|
|
11
|
+
else
|
|
12
|
+
flash.now[:error] = "Invalid username or password."
|
|
13
|
+
render "new"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def destroy
|
|
18
|
+
session[:user_id] = nil
|
|
19
|
+
redirect_to root_url, notice: "Logged out!"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class UsersController < ApplicationController
|
|
2
|
+
|
|
3
|
+
# GET /users/new
|
|
4
|
+
def new
|
|
5
|
+
@user = User.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# POST /users
|
|
9
|
+
def create
|
|
10
|
+
@user = User.new(user_params)
|
|
11
|
+
|
|
12
|
+
if @user.save
|
|
13
|
+
redirect_to @user, notice: 'User was successfully created.'
|
|
14
|
+
else
|
|
15
|
+
render action: 'new'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
# Only allow a trusted parameter "white list" through.
|
|
21
|
+
def user_params
|
|
22
|
+
params.require(:user).permit(:username, :password)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Dummy</title>
|
|
5
|
+
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
|
|
6
|
+
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
|
|
7
|
+
<%= csrf_meta_tags %>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
|
|
11
|
+
<div id="container">
|
|
12
|
+
<div id="userpanel">
|
|
13
|
+
<% if current_user %>
|
|
14
|
+
<span><b><%= current_user.username %></b></span>
|
|
15
|
+
<%= link_to "Logout", logout_path %>
|
|
16
|
+
<% else %>
|
|
17
|
+
<%= link_to "Login", login_path %>
|
|
18
|
+
<%= link_to "Register", new_user_path %>
|
|
19
|
+
<% end %>
|
|
20
|
+
</div>
|
|
21
|
+
<%= yield %>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<%= form_for(@post) do |f| %>
|
|
2
|
+
<% if @post.errors.any? %>
|
|
3
|
+
<div id="error_explanation">
|
|
4
|
+
<h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
|
|
5
|
+
|
|
6
|
+
<ul>
|
|
7
|
+
<% @post.errors.full_messages.each do |msg| %>
|
|
8
|
+
<li><%= msg %></li>
|
|
9
|
+
<% end %>
|
|
10
|
+
</ul>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<div class="field">
|
|
15
|
+
<%= f.label :title %><br>
|
|
16
|
+
<%= f.text_field :title %>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="actions">
|
|
19
|
+
<%= f.submit %>
|
|
20
|
+
</div>
|
|
21
|
+
<% end %>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<h1>Listing posts</h1>
|
|
2
|
+
|
|
3
|
+
<table>
|
|
4
|
+
<thead>
|
|
5
|
+
<tr>
|
|
6
|
+
<th>Title</th>
|
|
7
|
+
<th></th>
|
|
8
|
+
<th></th>
|
|
9
|
+
<th></th>
|
|
10
|
+
</tr>
|
|
11
|
+
</thead>
|
|
12
|
+
|
|
13
|
+
<tbody>
|
|
14
|
+
<% @posts.each do |post| %>
|
|
15
|
+
<tr>
|
|
16
|
+
<td><%= post.title %></td>
|
|
17
|
+
|
|
18
|
+
<%= voting_for post %>
|
|
19
|
+
</tr>
|
|
20
|
+
<% end %>
|
|
21
|
+
</tbody>
|
|
22
|
+
</table>
|
|
23
|
+
|
|
24
|
+
<br>
|
|
25
|
+
|
|
26
|
+
<%= link_to 'New Post', new_post_path %>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<p id="error"><%= flash[:error] %></p>
|
|
2
|
+
|
|
3
|
+
<h1>Login</h1>
|
|
4
|
+
|
|
5
|
+
<%= form_tag sessions_path do %>
|
|
6
|
+
|
|
7
|
+
<%= label_tag :username %>
|
|
8
|
+
<%= text_field_tag :username %>
|
|
9
|
+
|
|
10
|
+
<br>
|
|
11
|
+
|
|
12
|
+
<%= label_tag :password %>
|
|
13
|
+
<%= password_field_tag :password %>
|
|
14
|
+
|
|
15
|
+
<br>
|
|
16
|
+
|
|
17
|
+
<%= submit_tag "Login!" %>
|
|
18
|
+
<% end %>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<%= form_for(@user) do |f| %>
|
|
2
|
+
<% if @user.errors.any? %>
|
|
3
|
+
<div id="error_explanation">
|
|
4
|
+
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
|
|
5
|
+
|
|
6
|
+
<ul>
|
|
7
|
+
<% @user.errors.full_messages.each do |msg| %>
|
|
8
|
+
<li><%= msg %></li>
|
|
9
|
+
<% end %>
|
|
10
|
+
</ul>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<div class="field">
|
|
15
|
+
<%= f.label :username %><br>
|
|
16
|
+
<%= f.text_field :username %>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="field">
|
|
19
|
+
<%= f.label :password %><br>
|
|
20
|
+
<%= f.password_field :password %>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="actions">
|
|
23
|
+
<%= f.submit %>
|
|
24
|
+
</div>
|
|
25
|
+
<% end %>
|
data/spec/dummy/bin/rake
ADDED