rostra 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +30 -0
- data/Rakefile +27 -0
- data/app/assets/images/rostra/vote_arrows.png +0 -0
- data/app/assets/javascripts/rostra/application.js +28 -0
- data/app/assets/javascripts/rostra/jquery.jeditable.js +543 -0
- data/app/assets/stylesheets/rostra/application.css +177 -0
- data/app/assets/stylesheets/rostra/buttons.css +43 -0
- data/app/assets/stylesheets/rostra/flash_messages.css +13 -0
- data/app/assets/stylesheets/rostra/forms.css +40 -0
- data/app/assets/stylesheets/rostra/questions.css +4 -0
- data/app/assets/stylesheets/rostra/reset.css +13 -0
- data/app/assets/stylesheets/rostra/typography.css +7 -0
- data/app/controllers/rostra/answers_controller.rb +47 -0
- data/app/controllers/rostra/application_controller.rb +31 -0
- data/app/controllers/rostra/questions_controller.rb +57 -0
- data/app/helpers/rostra/application_helper.rb +4 -0
- data/app/helpers/rostra/questions_helper.rb +4 -0
- data/app/models/rostra/ability.rb +27 -0
- data/app/models/rostra/answer.rb +10 -0
- data/app/models/rostra/question.rb +15 -0
- data/app/models/rostra/vote.rb +19 -0
- data/app/models/vote.rb +17 -0
- data/app/views/layouts/rostra/application.html.erb +23 -0
- data/app/views/rostra/answers/_form.html.erb +8 -0
- data/app/views/rostra/answers/edit.html.erb +7 -0
- data/app/views/rostra/answers/vote.js.erb +1 -0
- data/app/views/rostra/questions/_form.html.erb +7 -0
- data/app/views/rostra/questions/edit.html.erb +7 -0
- data/app/views/rostra/questions/index.html.erb +45 -0
- data/app/views/rostra/questions/new.html.erb +7 -0
- data/app/views/rostra/questions/show.html.erb +47 -0
- data/app/views/rostra/questions/vote.js.erb +1 -0
- data/app/views/rostra/shared/_answers_votes.html.erb +27 -0
- data/app/views/rostra/shared/_sidebar.html.erb +8 -0
- data/app/views/rostra/shared/_votes.html.erb +27 -0
- data/config/cucumber.yml +8 -0
- data/config/initializers/client_side_validations.rb +14 -0
- data/config/initializers/simple_form.rb +93 -0
- data/config/locales/simple_form.en.yml +24 -0
- data/config/routes.rb +10 -0
- data/db/migrate/20110918170142_create_rostra_questions.rb +10 -0
- data/db/migrate/20111003233228_acts_as_taggable_on_migration.rb +28 -0
- data/db/migrate/20111005012613_add_user_id_to_questions.rb +5 -0
- data/db/migrate/20111007205730_create_rostra_answers.rb +11 -0
- data/db/migrate/20111008224511_thumbs_up_migration.rb +25 -0
- data/lib/rostra/engine.rb +13 -0
- data/lib/rostra/version.rb +3 -0
- data/lib/rostra.rb +11 -0
- data/lib/tasks/cucumber.rake +65 -0
- data/lib/tasks/rake_routes.rake +40 -0
- data/lib/tasks/rostra_tasks.rake +4 -0
- data/lib/templates/erb/scaffold/_form.html.erb +13 -0
- metadata +273 -0
@@ -0,0 +1,177 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
3
|
+
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
4
|
+
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
5
|
+
*= require_self
|
6
|
+
*= require_tree .
|
7
|
+
*/
|
8
|
+
.hidden {
|
9
|
+
display: none;
|
10
|
+
}
|
11
|
+
|
12
|
+
#page_wrap {
|
13
|
+
width: 970px; margin: auto;
|
14
|
+
}
|
15
|
+
.text {
|
16
|
+
line-height: 18px;
|
17
|
+
}
|
18
|
+
nav {
|
19
|
+
float: right;
|
20
|
+
}
|
21
|
+
#page_content {
|
22
|
+
width: 550px;
|
23
|
+
border-right: 1px solid #ccc;
|
24
|
+
padding-right: 100px;
|
25
|
+
}
|
26
|
+
#sidebar {
|
27
|
+
float: right;
|
28
|
+
width: 300px;
|
29
|
+
text-align: center;
|
30
|
+
}
|
31
|
+
div#questions {
|
32
|
+
min-height: 250px;
|
33
|
+
}
|
34
|
+
.question {
|
35
|
+
margin-bottom: 10px;
|
36
|
+
border-bottom: dashed 1px #E0E0E0;
|
37
|
+
padding-bottom: 15px;
|
38
|
+
}
|
39
|
+
.question h3 {
|
40
|
+
margin-bottom: 5px;
|
41
|
+
width: 500px;
|
42
|
+
}
|
43
|
+
.question h3 a {
|
44
|
+
color: #333;
|
45
|
+
text-decoration: none;
|
46
|
+
}
|
47
|
+
.question h3 a:hover {
|
48
|
+
color: green;
|
49
|
+
background: transparent;
|
50
|
+
}
|
51
|
+
.question cite {
|
52
|
+
display: block;
|
53
|
+
margin-bottom: 20px;
|
54
|
+
color: #aaa;
|
55
|
+
}
|
56
|
+
.question cite a {
|
57
|
+
font-style: normal;
|
58
|
+
margin-left: 5px;
|
59
|
+
}
|
60
|
+
.question .text {
|
61
|
+
margin-bottom: 25px;
|
62
|
+
}
|
63
|
+
.question a.view_more {
|
64
|
+
margin-left: 10px;
|
65
|
+
}
|
66
|
+
.question .tags {
|
67
|
+
color: #aaa;
|
68
|
+
}
|
69
|
+
.question .tags a {
|
70
|
+
margin: 0 3px;
|
71
|
+
}
|
72
|
+
.timestamp {
|
73
|
+
color: #aaa;
|
74
|
+
float: right;
|
75
|
+
}
|
76
|
+
|
77
|
+
.vote h4 p.already_voted {
|
78
|
+
color: #e6e6e6;
|
79
|
+
}
|
80
|
+
|
81
|
+
/* styles for question on question show page */
|
82
|
+
body#questions.show .question {
|
83
|
+
border-bottom: none;
|
84
|
+
margin-bottom: 50px;
|
85
|
+
}
|
86
|
+
body#questions.show #page_content {
|
87
|
+
margin-left: 50px;
|
88
|
+
}
|
89
|
+
|
90
|
+
|
91
|
+
/* answers section */
|
92
|
+
#answer_count{
|
93
|
+
border: 1px dashed #ccc;
|
94
|
+
border-left: none;
|
95
|
+
border-right: none;
|
96
|
+
padding: 4px 0;
|
97
|
+
margin-bottom: 20px;
|
98
|
+
}
|
99
|
+
#answers .answer {
|
100
|
+
padding: 15px 0;
|
101
|
+
border-top: 1px dashed #ccc;
|
102
|
+
}
|
103
|
+
#answers .answer:first-child {
|
104
|
+
border-top: none;
|
105
|
+
}
|
106
|
+
#answers .answer cite {
|
107
|
+
color: #aaa;
|
108
|
+
}
|
109
|
+
#answers .answer cite a {
|
110
|
+
font-style: normal;
|
111
|
+
margin-left: 5px;
|
112
|
+
}
|
113
|
+
#answers .answer .text {
|
114
|
+
margin-top: 10px;
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
/* answer question form */
|
119
|
+
form#new_rostra_answer {
|
120
|
+
padding-top: 30px;
|
121
|
+
border-top: 2px solid #ccc;
|
122
|
+
margin-top: 50px;
|
123
|
+
}
|
124
|
+
form#new_rostra_answer .field label {
|
125
|
+
font-size: 16px;
|
126
|
+
}
|
127
|
+
form#new_rostra_answer .field label abbr {
|
128
|
+
display: none;
|
129
|
+
}
|
130
|
+
form#new_rostra_answer .field textarea {
|
131
|
+
height: 150px;
|
132
|
+
width: 100%;
|
133
|
+
margin: 10px 0;
|
134
|
+
}
|
135
|
+
|
136
|
+
/*voting styles*/
|
137
|
+
.vote_wrapper, .answers_vote_wrapper {
|
138
|
+
text-align: center;
|
139
|
+
width: 43px;
|
140
|
+
font-size: 22px;
|
141
|
+
font-weight: bold;
|
142
|
+
line-height: 12px;
|
143
|
+
float: left;
|
144
|
+
margin: -5px 0 0 -55px;
|
145
|
+
}
|
146
|
+
.vote {
|
147
|
+
background-image: url("vote_arrows.png");
|
148
|
+
background-repeat: no-repeat;
|
149
|
+
width: 43px;
|
150
|
+
height: 43px;
|
151
|
+
display: block;
|
152
|
+
text-indent: -999px;
|
153
|
+
background-color: transparent;
|
154
|
+
}
|
155
|
+
|
156
|
+
.vote:hover{
|
157
|
+
background-color: transparent;
|
158
|
+
}
|
159
|
+
|
160
|
+
.vote.up{
|
161
|
+
background-position: 0 0;
|
162
|
+
}
|
163
|
+
|
164
|
+
.vote.up:hover, .vote.up.selected{
|
165
|
+
background-position: 0 -43px;
|
166
|
+
}
|
167
|
+
|
168
|
+
.vote.down{
|
169
|
+
background-position: 0 -129px;
|
170
|
+
}
|
171
|
+
|
172
|
+
.vote.down:hover, .vote.down.selected{
|
173
|
+
background-position: 0 -86px;
|
174
|
+
}
|
175
|
+
|
176
|
+
|
177
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
.button,
|
2
|
+
input[type="submit"] {
|
3
|
+
margin: 10px 0;
|
4
|
+
display: inline-block;
|
5
|
+
background: #eee;
|
6
|
+
background: -moz-linear-gradient(top, #eee 0%, #ccc 100%);
|
7
|
+
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#eee), to(#ccc));
|
8
|
+
border: 1px solid #ccc;
|
9
|
+
border-bottom: 1px solid #bbb;
|
10
|
+
-moz-border-radius: 3px;
|
11
|
+
-webkit-border-radius: 3px;
|
12
|
+
border-radius: 3px;
|
13
|
+
color: #333 !important;
|
14
|
+
font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
|
15
|
+
font-size: 11px;
|
16
|
+
font-weight: bold;
|
17
|
+
line-height: 1;
|
18
|
+
padding: 8px;
|
19
|
+
text-align: center;
|
20
|
+
text-shadow: 0 1px 0 #eee;
|
21
|
+
text-decoration: none !important;
|
22
|
+
width: auto;
|
23
|
+
}
|
24
|
+
|
25
|
+
.button:hover,
|
26
|
+
input[type="submit"]:hover {
|
27
|
+
background: #ddd;
|
28
|
+
background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%);
|
29
|
+
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#ddd), to(#bbb));
|
30
|
+
border: 1px solid #bbb;
|
31
|
+
border-bottom: 1px solid #999;
|
32
|
+
cursor: pointer;
|
33
|
+
text-shadow: 0 1px 0 #ddd;
|
34
|
+
}
|
35
|
+
|
36
|
+
.button:active,
|
37
|
+
input[type="submit"]:active {
|
38
|
+
border: 1px solid #aaa;
|
39
|
+
border-bottom: 1px solid #888;
|
40
|
+
-moz-box-shadow: inset 0 0 5px 2px #aaa, 0 1px 0 0 #eee;
|
41
|
+
-webkit-box-shadow: inset 0 0 5px 2px #aaa, 0 1px 0 0 #eee;
|
42
|
+
box-shadow: inset 0 0 5px 2px #aaa, 0 1px 0 0 #eee;
|
43
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
form .hint {
|
2
|
+
display: block;
|
3
|
+
margin-top: -10px;
|
4
|
+
color: #aaa;
|
5
|
+
}
|
6
|
+
form label abbr {
|
7
|
+
color: green;
|
8
|
+
font-size: 18px;
|
9
|
+
font-weight: normal;
|
10
|
+
}
|
11
|
+
form .field {
|
12
|
+
position: relative;
|
13
|
+
width: 550px;
|
14
|
+
}
|
15
|
+
form label {
|
16
|
+
font-weight: bold;
|
17
|
+
display: block;
|
18
|
+
margin-bottom: 3px;
|
19
|
+
}
|
20
|
+
form input,
|
21
|
+
form textarea {
|
22
|
+
margin-bottom: 15px;
|
23
|
+
padding: 3px;
|
24
|
+
width: 100%;
|
25
|
+
}
|
26
|
+
textarea {
|
27
|
+
line-height: 18px;
|
28
|
+
height: 300px;
|
29
|
+
}
|
30
|
+
span.error {
|
31
|
+
color: red;
|
32
|
+
position: absolute;
|
33
|
+
top: 5px;
|
34
|
+
right: -5px;
|
35
|
+
}
|
36
|
+
.field_with_errors input,
|
37
|
+
.field_with_errors textarea {
|
38
|
+
background: #fde6e4;
|
39
|
+
border: 1px solid red;
|
40
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
* { margin: 0; padding: 0; }
|
2
|
+
body { font-size: 12px; font-family: Helvetica, Verdana, Arial, sans-serif; color: #333; }
|
3
|
+
ul { list-style: disc inside; padding-left: 10px; }
|
4
|
+
ol { list-style: decimal inside; padding-left: 10px; }
|
5
|
+
li { list-style-position: outside;}
|
6
|
+
a { outline: none; color: green;}
|
7
|
+
a:hover { background-color: green; color: white; text-decoration: none;}
|
8
|
+
a img { border: none; background: none; }
|
9
|
+
img { vertical-align: middle; }
|
10
|
+
table { border-collapse: collapse; }
|
11
|
+
p { margin-top: 10px; }
|
12
|
+
textarea { resize: none; }
|
13
|
+
input:focus, textarea:focus { outline: none; }
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Rostra
|
2
|
+
class AnswersController < ApplicationController
|
3
|
+
load_and_authorize_resource
|
4
|
+
before_filter :fetch_question
|
5
|
+
|
6
|
+
def vote
|
7
|
+
if current_user.voted_for?(@answer) && params[:vote_type] == 'up'
|
8
|
+
current_user.clear_votes(@answer)
|
9
|
+
elsif current_user.voted_against?(@answer) && params[:vote_type] == 'down'
|
10
|
+
current_user.clear_votes(@answer)
|
11
|
+
else
|
12
|
+
current_user.vote_exclusively_for(@answer) if params[:vote_type] == 'up'
|
13
|
+
current_user.vote_exclusively_against(@answer) if params[:vote_type] == 'down'
|
14
|
+
end
|
15
|
+
|
16
|
+
respond_to do |format|
|
17
|
+
format.html { redirect_to question_path(@question, anchor: "rostra_answer_#{@answer.id}") }
|
18
|
+
format.js
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def create
|
23
|
+
if @answer.save
|
24
|
+
redirect_to question_path(@question, anchor: "rostra_answer_#{@answer.id}")
|
25
|
+
else
|
26
|
+
redirect_to question_path(@question, anchor: 'new_rostra_answer')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def edit
|
31
|
+
end
|
32
|
+
|
33
|
+
def update
|
34
|
+
if @answer.update_attributes(params[:answer])
|
35
|
+
redirect_to question_path(@question, anchor: "rostra_answer_#{@answer.id}")
|
36
|
+
else
|
37
|
+
render :edit
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def fetch_question
|
44
|
+
@question = Question.find(params[:question_id])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rostra
|
2
|
+
class ApplicationController < ActionController::Base
|
3
|
+
|
4
|
+
helper_method :user_logged_in?
|
5
|
+
|
6
|
+
rescue_from CanCan::AccessDenied do |exception|
|
7
|
+
after_access_denied
|
8
|
+
end
|
9
|
+
|
10
|
+
# Check if a user is logged in
|
11
|
+
#
|
12
|
+
def user_signed_in?
|
13
|
+
current_user
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Override <tt>cancan</tt>'s default class of <tt>Ability</tt> to user <tt>Rostra::Ability</tt>.
|
19
|
+
#
|
20
|
+
def current_ability
|
21
|
+
@current_ability ||= Rostra::Ability.new(current_user)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Override this method to if finer control over what happens when <tt>cancan</tt> denies access.
|
25
|
+
#
|
26
|
+
def after_access_denied
|
27
|
+
redirect_to root_url, alert: "You don't have access to view this page"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Rostra
|
2
|
+
class QuestionsController < ApplicationController
|
3
|
+
load_and_authorize_resource
|
4
|
+
|
5
|
+
def vote
|
6
|
+
if current_user.voted_for?(@question) && params[:vote_type] == 'up'
|
7
|
+
current_user.clear_votes(@question)
|
8
|
+
elsif current_user.voted_against?(@question) && params[:vote_type] == 'down'
|
9
|
+
current_user.clear_votes(@question)
|
10
|
+
else
|
11
|
+
current_user.vote_exclusively_for(@question) if params[:vote_type] == 'up'
|
12
|
+
current_user.vote_exclusively_against(@question) if params[:vote_type] == 'down'
|
13
|
+
end
|
14
|
+
|
15
|
+
respond_to do |format|
|
16
|
+
format.html { redirect_to @question }
|
17
|
+
format.js
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def index
|
22
|
+
@questions = Question.order('created_at desc')
|
23
|
+
@user = current_user
|
24
|
+
end
|
25
|
+
|
26
|
+
def show
|
27
|
+
@answers = @question.answers
|
28
|
+
end
|
29
|
+
|
30
|
+
def new
|
31
|
+
end
|
32
|
+
|
33
|
+
def edit
|
34
|
+
end
|
35
|
+
|
36
|
+
def create
|
37
|
+
if @question.save
|
38
|
+
redirect_to questions_path, notice: 'Your question has been posted.'
|
39
|
+
else
|
40
|
+
render :new
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def update
|
45
|
+
if @question.update_attributes(params[:question])
|
46
|
+
redirect_to @question, notice: 'Question was successfully updated.'
|
47
|
+
else
|
48
|
+
render :edit
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def destroy
|
53
|
+
@question.destroy
|
54
|
+
redirect_to questions_url
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rostra
|
2
|
+
class Ability
|
3
|
+
include CanCan::Ability
|
4
|
+
|
5
|
+
attr_reader :user
|
6
|
+
|
7
|
+
def initialize(user)
|
8
|
+
@user = user || User.new
|
9
|
+
|
10
|
+
if logged_in?
|
11
|
+
can :manage, Question, :user => user
|
12
|
+
can :manage, Answer, :user => user
|
13
|
+
can [:vote_up, :vote_down], Question
|
14
|
+
can [:vote_up, :vote_down], Answer
|
15
|
+
end
|
16
|
+
|
17
|
+
can :read, :all
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def logged_in?
|
23
|
+
! user.new_record?
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Rostra
|
2
|
+
class Question < ActiveRecord::Base
|
3
|
+
|
4
|
+
belongs_to :user
|
5
|
+
has_many :answers
|
6
|
+
|
7
|
+
acts_as_taggable
|
8
|
+
acts_as_voteable
|
9
|
+
|
10
|
+
validates :title, :presence => true, :uniqueness => true, :length => { :minimum => 15 }
|
11
|
+
validates :user, :presence => true
|
12
|
+
validates :tag_list, :presence => true
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rostra
|
2
|
+
class Vote < ActiveRecord::Base
|
3
|
+
|
4
|
+
scope :for_voter, lambda { |*args| where(["voter_id = ? AND voter_type = ?", args.first.id, args.first.class.name]) }
|
5
|
+
scope :for_voteable, lambda { |*args| where(["voteable_id = ? AND voteable_type = ?", args.first.id, args.first.class.name]) }
|
6
|
+
scope :recent, lambda { |*args| where(["created_at > ?", (args.first || 2.weeks.ago)]) }
|
7
|
+
scope :descending, order("created_at DESC")
|
8
|
+
|
9
|
+
belongs_to :voteable, :polymorphic => true
|
10
|
+
belongs_to :voter, :polymorphic => true
|
11
|
+
|
12
|
+
attr_accessible :vote, :voter, :voteable
|
13
|
+
|
14
|
+
|
15
|
+
# Comment out the line below to allow multiple votes per user.
|
16
|
+
validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id]
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/app/models/vote.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Vote < ActiveRecord::Base
|
2
|
+
|
3
|
+
scope :for_voter, lambda { |*args| where(["voter_id = ? AND voter_type = ?", args.first.id, args.first.class.name]) }
|
4
|
+
scope :for_voteable, lambda { |*args| where(["voteable_id = ? AND voteable_type = ?", args.first.id, args.first.class.name]) }
|
5
|
+
scope :recent, lambda { |*args| where(["created_at > ?", (args.first || 2.weeks.ago)]) }
|
6
|
+
scope :descending, order("created_at DESC")
|
7
|
+
|
8
|
+
belongs_to :voteable, :polymorphic => true
|
9
|
+
belongs_to :voter, :polymorphic => true
|
10
|
+
|
11
|
+
attr_accessible :vote, :voter, :voteable
|
12
|
+
|
13
|
+
|
14
|
+
# Comment out the line below to allow multiple votes per user.
|
15
|
+
validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id]
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Rostra</title>
|
5
|
+
<%= stylesheet_link_tag "rostra/application" %>
|
6
|
+
<%= javascript_include_tag "rostra/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body id="<%= controller_name %>" class="<%= action_name %>">
|
10
|
+
<div id="page_wrap">
|
11
|
+
<nav>
|
12
|
+
<%= link_to 'Recent questions', questions_path %>
|
13
|
+
<%= link_to 'Logout', main_app.destroy_user_session_path, :method => :post %>
|
14
|
+
|
15
|
+
</nav>
|
16
|
+
<% flash.each do |name, msg| %>
|
17
|
+
<%= content_tag :div, msg, id: "flash_#{name}", class: 'flash' %>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<%= yield %>
|
21
|
+
</div>
|
22
|
+
</body>
|
23
|
+
</html>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<% @answer ||= @question.answers.build %>
|
2
|
+
|
3
|
+
<%= simple_form_for [@question, @answer], validate: true do |f| %>
|
4
|
+
<%= f.hidden_field :user_id, value: current_user.id %>
|
5
|
+
<%= f.hidden_field :question_id, value: @question.id %>
|
6
|
+
<%= f.input :text, label: 'Answer this question' %>
|
7
|
+
<%= f.submit @answer.new_record? ? 'Answer' : 'Update' %>
|
8
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
$('.answers_vote_wrapper').replaceWith('<%= escape_javascript(render(:partial => 'rostra/shared/answers_votes', locals: {answer: @answer})) %>');
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<%= simple_form_for @question, validate: true do |f| %>
|
2
|
+
<%= f.hidden_field :user_id, value: current_user.id %>
|
3
|
+
<%= f.input :title %>
|
4
|
+
<%= f.input :details %>
|
5
|
+
<%= f.input :tag_list, label: 'Tags', hint: 'Separate tags with commas' %>
|
6
|
+
<%= f.submit "Post your question" %>
|
7
|
+
<% end %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<h1>Recent Questions</h1>
|
2
|
+
|
3
|
+
<%= render 'rostra/shared/sidebar' %>
|
4
|
+
|
5
|
+
<div id="page_content">
|
6
|
+
<div id="questions">
|
7
|
+
<% if @questions.empty? %>
|
8
|
+
<h3>No questions have been asked.</h3>
|
9
|
+
|
10
|
+
<% else %>
|
11
|
+
|
12
|
+
<% @questions.each do |question| %>
|
13
|
+
<div class="question">
|
14
|
+
<h3 class="title"><%= link_to question.title, question %></h3>
|
15
|
+
<cite>
|
16
|
+
Asked by <%= question.user.name %>
|
17
|
+
<%= link_to 'edit', edit_question_path(question) if can? :manage, question %>
|
18
|
+
</cite>
|
19
|
+
<div class="text">
|
20
|
+
<% if question.details.length > 250 %>
|
21
|
+
<%= simple_format(
|
22
|
+
truncate(question.details, length: 250) +
|
23
|
+
link_to("view more", question, class: "view_more")
|
24
|
+
) %>
|
25
|
+
|
26
|
+
<% else %>
|
27
|
+
<%= simple_format(question.details) %>
|
28
|
+
<% end %>
|
29
|
+
</div>
|
30
|
+
<div class="timestamp"><%= time_ago_in_words(question.updated_at) %> ago</div>
|
31
|
+
<div class="tags">
|
32
|
+
Tags:
|
33
|
+
<% question.tags.each do |tag| %>
|
34
|
+
<%= link_to tag, "" %>
|
35
|
+
<% end %>
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
<% end %>
|
39
|
+
|
40
|
+
<% end %>
|
41
|
+
</div><!-- questions -->
|
42
|
+
|
43
|
+
|
44
|
+
</div><!--page_content-->
|
45
|
+
|