rostra 0.0.14 → 0.0.15

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.
data/README.rdoc CHANGED
@@ -41,7 +41,7 @@ Also, be sure to read through <tt>config/initializers/rostra.rb</tt> and overrid
41
41
 
42
42
  Finally, have a look at <tt>app/helpers/rostra/application_helper.rb</tt>, you may need to add/override helper methods.
43
43
 
44
- == Customizing the question and answer models
44
+ == Overriding models
45
45
  Rostra provides a DSL for adding application specific logic to <tt>Rostra::Question</tt> and <tt>Rostra:Answer</tt>:
46
46
 
47
47
  class User < ActiveRecord::Base
@@ -69,6 +69,9 @@ Rostra provides a DSL for adding application specific logic to <tt>Rostra::Quest
69
69
  end
70
70
  end
71
71
 
72
+ == Overriding Controllers
73
+ Added instructions for overriding controllers here (including generators!)
74
+
72
75
  == Setting permissions
73
76
  Under the hood, Rostra uses <tt>CanCan</tt> to set permissions. By default anyone can read rostra content - even if they are not logged in. A user can contribute content (i.e. ask questions, give answers, and leave comments) as long as they've logged in.
74
77
 
@@ -1,40 +1,5 @@
1
1
  module Rostra
2
- class AnswersController < ApplicationController
3
- load_and_authorize_resource
4
- before_filter :fetch_question
5
-
6
- def vote
7
- rostra_user.vote_on(@answer, params[:vote_direction])
8
-
9
- respond_to do |format|
10
- format.html { redirect_to question_path(@question, anchor: "rostra_answer_#{@answer.id}") }
11
- format.js
12
- end
13
- end
14
-
15
- def create
16
- if @answer.save
17
- redirect_to question_path(@question, anchor: "rostra_answer_#{@answer.id}")
18
- else
19
- redirect_to question_path(@question, anchor: 'new_rostra_answer')
20
- end
21
- end
22
-
23
- def edit
24
- end
25
-
26
- def update
27
- if @answer.update_attributes(params[:answer])
28
- redirect_to question_path(@question, anchor: "rostra_answer_#{@answer.id}")
29
- else
30
- render :edit
31
- end
32
- end
33
-
34
- private
35
-
36
- def fetch_question
37
- @question = Question.find(params[:question_id])
38
- end
2
+ class AnswersController < Rostra::Base::AnswersController
3
+ # Override existing actions here
39
4
  end
40
5
  end
@@ -3,7 +3,7 @@ module Rostra
3
3
 
4
4
  include Rostra::Config
5
5
 
6
- helper_method :user_logged_in?, :main_app_login_path, :main_app_signup_path, :rostra_user
6
+ helper_method :can_participate_in_rostra?, :main_app_login_path, :main_app_signup_path, :rostra_user
7
7
 
8
8
  rescue_from CanCan::AccessDenied do |exception|
9
9
  after_access_denied
@@ -25,8 +25,8 @@ module Rostra
25
25
 
26
26
  # Check if a user is logged in
27
27
  #
28
- def user_signed_in?
29
- rostra_user
28
+ def can_participate_in_rostra?
29
+ rostra_user && rostra_user.can_participate_in_rostra?
30
30
  end
31
31
 
32
32
  private
@@ -0,0 +1,42 @@
1
+ module Rostra
2
+ module Base
3
+ class AnswersController < ApplicationController
4
+ load_and_authorize_resource
5
+ before_filter :fetch_question
6
+
7
+ def vote
8
+ rostra_user.vote_on(@answer, params[:vote_direction])
9
+
10
+ respond_to do |format|
11
+ format.html { redirect_to question_path(@question, anchor: "rostra_answer_#{@answer.id}") }
12
+ format.js
13
+ end
14
+ end
15
+
16
+ def create
17
+ if @answer.save
18
+ redirect_to question_path(@question, anchor: "rostra_answer_#{@answer.id}")
19
+ else
20
+ redirect_to question_path(@question, anchor: 'new_rostra_answer')
21
+ end
22
+ end
23
+
24
+ def edit
25
+ end
26
+
27
+ def update
28
+ if @answer.update_attributes(params[:answer])
29
+ redirect_to question_path(@question, anchor: "rostra_answer_#{@answer.id}")
30
+ else
31
+ render :edit
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def fetch_question
38
+ @question = Question.find(params[:question_id])
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,31 @@
1
+ module Rostra
2
+ module Base
3
+ class CommentsController < ApplicationController
4
+ load_and_authorize_resource
5
+
6
+ before_filter :fetch_question
7
+
8
+ def create
9
+ if @comment.save
10
+ redirect_to @question
11
+ end
12
+ end
13
+
14
+ def update
15
+ @comment.update_attributes(:comment => params[:value])
16
+ render :text => @comment.comment
17
+ end
18
+
19
+ def destroy
20
+ @comment.destroy
21
+ redirect_to @question
22
+ end
23
+
24
+ private
25
+
26
+ def fetch_question
27
+ @question = Question.find(params[:question_id])
28
+ end
29
+ end
30
+ end
31
+ end
@@ -12,11 +12,24 @@ module Rostra
12
12
  end
13
13
  end
14
14
 
15
+ def toggle_following
16
+ if rostra_user.following?(@question)
17
+ rostra_user.followed_questions.delete(@question)
18
+ else
19
+ rostra_user.followed_questions << @question
20
+ end
21
+
22
+ respond_to do |format|
23
+ format.html { redirect_to @question }
24
+ format.js
25
+ end
26
+ end
27
+
15
28
  def index
16
29
  if params[:tag_search].present?
17
- @questions = Question.tagged_with(params[:tag_search]).order('created_at desc')
30
+ @questions = Question.tagged_with(params[:tag_search]).order('created_at desc').page(params[:page])
18
31
  else
19
- @questions = Question.order('created_at desc')
32
+ @questions = Question.order('created_at desc').page(params[:page])
20
33
  end
21
34
  end
22
35
 
@@ -47,11 +60,6 @@ module Rostra
47
60
  end
48
61
  end
49
62
 
50
- def destroy
51
- @question.destroy
52
- redirect_to questions_url
53
- end
54
-
55
63
  end
56
64
  end
57
65
  end
@@ -1,31 +1,5 @@
1
1
  module Rostra
2
- class CommentsController < ApplicationController
3
- load_and_authorize_resource
4
-
5
- before_filter :fetch_question
6
-
7
- def create
8
-
9
- if @comment.save
10
- redirect_to @question
11
- end
12
- end
13
-
14
- def update
15
- @comment.update_attributes(:comment => params[:value])
16
- render :text => @comment.comment
17
- end
18
-
19
- def destroy
20
- @comment.destroy
21
- redirect_to @question
22
- end
23
-
24
- private
25
-
26
- def fetch_question
27
- @question = Question.find(params[:question_id])
28
- end
29
-
2
+ class CommentsController < Rostra::Base::CommentsController
3
+ # Override existing actions here
30
4
  end
31
5
  end
@@ -1,5 +1,5 @@
1
1
  module Rostra
2
2
  module ApplicationHelper
3
- include Rostra::BaseHelper
3
+ include Rostra::Base::ApplicationHelper
4
4
  end
5
5
  end
@@ -0,0 +1,89 @@
1
+ module Rostra
2
+ module Base
3
+ module ApplicationHelper
4
+
5
+ # Method used to render to user names (e.g. where it says: "John Does says:"). You can,
6
+ # for example, use this method to turn "John Doe" into a link to his profile page.
7
+ #
8
+ def link_to_profile(user)
9
+ link_to user.rostra_user_name, main_app.user_path(user)
10
+ end
11
+
12
+ # Used to populate both the <tt>title</tt> and <tt>h1</tt> elements for each page.
13
+ #
14
+ def page_title_helper
15
+ case "#{controller_name}##{action_name}"
16
+ when "questions#show" then @question.title
17
+ when "questions#index" then
18
+ if params[:tag_search].present?
19
+ "Recent Questions for tag #{params[:tag_search]}"
20
+ else
21
+ "Recent Questions"
22
+ end
23
+ when "questions#new" then "Post a new question"
24
+ when "questions#edit" then "Editing question"
25
+ when "answers#edit" then "Editing answer"
26
+ else "Recent Questions"
27
+ end
28
+ end
29
+
30
+ # Creates a list of tags linking to the index showing only questions with that tag
31
+ #
32
+ def tag_list(question)
33
+ tags = question.tags.map { |tag| link_to tag, questions_path(:tag_search => "#{tag}")}.join
34
+ content_tag :div, "Tags: #{tags}".html_safe, class: 'tags'
35
+ end
36
+
37
+ # Finds the url to the user's avatar following this logic:
38
+ #
39
+ # 1. Calls <tt>avatar</tt> on the user object
40
+ # 2. Uses the users email address to look for a gravatar
41
+ # 3. Renders <tt>app/assets/images/rostra/anonymous_avatar.png</tt>
42
+ #
43
+ def rostra_user_avatar(user)
44
+ if user.respond_to?(:avatar)
45
+ url = user.avatar
46
+ else
47
+ default_url = "#{main_app.root_url}assets/rostra/anonymous_avatar.png"
48
+ gravatar_id = Digest::MD5.hexdigest(user.rostra_user_email.downcase)
49
+ url = "http://gravatar.com/avatar/#{gravatar_id}.png?s=48&d=#{CGI.escape(default_url)}"
50
+ end
51
+ image_tag(url, class: 'avatar')
52
+ end
53
+
54
+ # Method to build links for ajax-y voting arrows.
55
+ #
56
+ def link_to_vote(direction, resource)
57
+ if can_participate_in_rostra? && ( (direction == :up && rostra_user.voted_for?(resource)) || (direction == :down && rostra_user.voted_against?(resource)) )
58
+ selected = 'selected'
59
+ else
60
+ selected = ''
61
+ end
62
+
63
+ link_to "Vote #{direction.capitalize}", vote_path(resource, direction), method: :put, remote: true, class: "vote #{direction} #{selected}"
64
+ end
65
+
66
+ # Returns a rostra object's base class name. For example, <tt>@question</tt> is an instance of
67
+ # Rostra::Question and so:
68
+ #
69
+ # class_name(@question) # => 'question'
70
+ #
71
+ def class_name(resource)
72
+ resource.class.name.split('::').last.downcase
73
+ end
74
+
75
+ private
76
+
77
+ def vote_path(resource, direction)
78
+ return '#' if !can_participate_in_rostra? || can?(:manage, resource)
79
+
80
+ if resource.is_a?(Rostra::Question)
81
+ vote_question_path(resource, vote_direction: direction)
82
+ else
83
+ vote_question_answer_path(resource.question, resource, vote_direction: direction)
84
+ end
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -2,8 +2,6 @@ module Rostra
2
2
  class Ability
3
3
  include CanCan::Ability
4
4
 
5
- attr_reader :user
6
-
7
5
  def initialize(user)
8
6
  @user = user || User.new
9
7
 
@@ -12,7 +10,7 @@ module Rostra
12
10
  can :manage, Answer, :user => user
13
11
  can :manage, Comment, :user => user
14
12
 
15
- can :vote, Question
13
+ can [:vote, :toggle_following], Question
16
14
  cannot :vote, Question, :user => user
17
15
 
18
16
  can :vote, Answer
@@ -1,6 +1,5 @@
1
1
  module Rostra
2
2
  class Question < ActiveRecord::Base
3
-
4
3
  belongs_to :user
5
4
  has_many :answers
6
5
  has_many :question_followings
@@ -17,6 +16,10 @@ module Rostra
17
16
  before_save :create_question_following
18
17
  attr_accessor :follow_by_email
19
18
 
19
+ # Set number of questions per page for will paginate
20
+ #
21
+ per_page = Rostra::Config.number_of_question_per_page
22
+
20
23
  # Finds questions asked within the last 15 days ordered by non-unique page views.
21
24
  #
22
25
  def self.trending(limit = 5)
@@ -8,9 +8,7 @@
8
8
  </head>
9
9
  <body id="<%= controller_name %>" class="<%= action_name %>">
10
10
  <div id="page_wrap">
11
- <nav>
12
- <%= link_to 'Recent questions', questions_path %>
13
- </nav>
11
+
14
12
  <% flash.each do |name, msg| %>
15
13
  <%= content_tag :div, msg, id: "flash_#{name}", class: 'flash' %>
16
14
  <% end %>
@@ -4,5 +4,5 @@
4
4
  <%= f.input :details, input_html: {class: 'wysiwyg'} %>
5
5
  <%= f.input :tag_list, label: 'Tags', hint: 'Separate tags with commas' %>
6
6
  <%= f.input :follow_by_email, as: :boolean, input_html: { checked: true }, label: "I want to follow answers and comments on this question" %>
7
- <%= f.submit "Post your question" %>
7
+ <%= f.submit @question.new_record? ? 'Post your question' : 'Update' %>
8
8
  <% end %>
@@ -44,6 +44,8 @@
44
44
  </div>
45
45
  <% end %>
46
46
 
47
+ <%= will_paginate @posts %>
48
+
47
49
  <% end %>
48
50
  </div><!-- questions -->
49
51
 
@@ -9,7 +9,7 @@
9
9
  Asked by <%= link_to_profile(@question.user) %>
10
10
  <%= link_to 'edit', edit_question_path(@question) if can? :manage, @question %>
11
11
  </cite>
12
- <div class="text"><%= simple_format(@question.details) %></div>
12
+ <div class="text"><%= @question.details.html_safe %></div>
13
13
  <div class="details">
14
14
  <div class="timestamp"><%= time_ago_in_words(@question.updated_at) %> ago</div>
15
15
  <%= tag_list(@question) %>
@@ -27,7 +27,7 @@
27
27
  <%= link_to_profile(answer.user) %> says:
28
28
  <%= link_to('edit', edit_question_answer_path(@question, answer)) if can? :manage, answer %>
29
29
  </cite>
30
- <div class="text"><%= simple_format(answer.text) %></div>
30
+ <div class="text"><%= answer.text.html_safe %></div>
31
31
  <div class="timestamp"><%= time_ago_in_words(answer.updated_at) %> ago</div>
32
32
 
33
33
  <% if answer.comments.any? %>
@@ -71,7 +71,7 @@
71
71
  </div>
72
72
  <% end %>
73
73
 
74
- <% if user_signed_in? %>
74
+ <% if can_participate_in_rostra? %>
75
75
  <%= render 'rostra/answers/form' %>
76
76
  <% else %>
77
77
  <%= link_to "Login to answer this question", main_app_login_path, class: 'button' %>
@@ -0,0 +1,7 @@
1
+ <% if rostra_user.following?(@question) %>
2
+ var button_text = "Stop following this question"
3
+ <% else %>
4
+ var button_text = "Follow this question"
5
+ <% end %>
6
+
7
+ $('a.toggle_following_question').text(button_text);
@@ -1,10 +1,14 @@
1
1
  <div id="sidebar">
2
- <% if user_signed_in? %>
2
+ <% if can_participate_in_rostra? %>
3
3
  <%= link_to 'Ask a question', new_question_path, class: "button" %>
4
4
  <% else %>
5
5
  <%= link_to 'Login to ask a question', main_app_login_path, class: "button" %>
6
6
  <% end %>
7
7
 
8
+ <% if can_participate_in_rostra? && controller_name == 'questions' && action_name == 'show' %>
9
+ <%= render partial: 'rostra/shared/toggle_following_question_button', locals: { question: @question } %>
10
+ <% end %>
11
+
8
12
  <h4>Trending questions</h4>
9
13
  <ul id="trending_questions">
10
14
  <% Rostra::Question.trending.each do |question| %>
@@ -0,0 +1,3 @@
1
+ <% button_text = rostra_user.following?(question) ? 'Stop following this question' : 'Follow this question' %>
2
+ <%= link_to button_text, toggle_following_question_path(question), method: :put, remote: true, class: "toggle_following_question button" %>
3
+
@@ -4,7 +4,7 @@
4
4
  <%= link_to_vote(:down, resource) %>
5
5
  </div>
6
6
 
7
- <% unless user_signed_in? %>
7
+ <% unless can_participate_in_rostra? %>
8
8
  <div class="hidden flash" id="flash_notice">
9
9
  You must <%= link_to 'login', main_app_login_path %> or <%= link_to 'signup', main_app_signup_path %> in order to vote
10
10
  <%= link_to 'X', '#', class: 'closeable' %>
data/config/routes.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  Rostra::Engine.routes.draw do
2
- resources :questions do
3
- put :vote, :on => :member
4
- resources :answers do
5
- put :vote, :on => :member
2
+ resources :questions, except: [:destroy] do
3
+ put :vote, on: :member
4
+ put :toggle_following, on: :member
5
+ resources :answers, only: [:create, :edit, :update] do
6
+ put :vote, on: :member
6
7
  end
7
- resources :comments, :only => [:create, :update, :destroy]
8
+ resources :comments, only: [:create, :update, :destroy]
8
9
  end
9
10
 
10
11
  root :to => "questions#index"
@@ -6,7 +6,7 @@ module Rostra
6
6
  # this line but you can add/override rostra methods in this file. The helpers which you may
7
7
  # need to override are listed below. Just un-comment them and make changes.
8
8
  #
9
- include Rostra::BaseHelper
9
+ include Rostra::Base::ApplicationHelper
10
10
 
11
11
  # If you want to user helper methods defined elsewhere in your app, you can include them here
12
12
  # as well. For example:
@@ -3,6 +3,10 @@ Rostra::Config.setup do |config|
3
3
  # Helper method used to access current user in the view
4
4
  # config.deliver_emails_from = 'change_me@example.com'
5
5
 
6
+ # Set the number of questions that will appear on each page. Applies to both the
7
+ # questions index page (i.e. "recent questions" and "questions tagged with")
8
+ # config.number_of_question_per_page = 10
9
+
6
10
  # Helper method used to access current user in the view
7
11
  # config.rostra_user = :current_user
8
12
 
data/lib/rostra.rb CHANGED
@@ -63,6 +63,12 @@ module Rostra
63
63
  end
64
64
  end
65
65
 
66
+ # Check if the user is following a given question
67
+ #
68
+ def following?(question)
69
+ followed_questions.include?(question)
70
+ end
71
+
66
72
  # By default anyone can read rostra content - even if they are not logged in. This method
67
73
  # determines if users can contribute content (i.e. ask questions, give answers, and leave
68
74
  # comments). If <tt>can_participate_in_rostra?</tt> returns true, the user can contribute
data/lib/rostra/config.rb CHANGED
@@ -6,6 +6,12 @@ module Rostra
6
6
  mattr_accessor :deliver_emails_from
7
7
  @@deliver_emails_from = 'change_me@example.com'
8
8
 
9
+ # Set the number of questions that will appear on each page. Applies to both the
10
+ # questions index page (i.e. "recent questions" and "questions tagged with")
11
+ #
12
+ mattr_accessor :number_of_question_per_page
13
+ @@number_of_question_per_page = 10
14
+
9
15
  # Helper method used to access current user in the view
10
16
  #
11
17
  mattr_accessor :rostra_user
data/lib/rostra/engine.rb CHANGED
@@ -8,6 +8,7 @@ module Rostra
8
8
  require 'thumbs_up'
9
9
  require 'acts_as_commentable'
10
10
  require 'impressionist'
11
+ require 'will_paginate'
11
12
  require_relative 'email_notifier'
12
13
 
13
14
  isolate_namespace Rostra
@@ -1,3 +1,3 @@
1
1
  module Rostra
2
- VERSION = "0.0.14"
2
+ VERSION = "0.0.15"
3
3
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rostra
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.14
5
+ version: 0.0.15
6
6
  platform: ruby
7
7
  authors:
8
8
  - Cory Schires
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-10-22 00:00:00 -05:00
13
+ date: 2011-10-24 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -113,7 +113,7 @@ dependencies:
113
113
  type: :runtime
114
114
  version_requirements: *id009
115
115
  - !ruby/object:Gem::Dependency
116
- name: sqlite3
116
+ name: will_paginate
117
117
  prerelease: false
118
118
  requirement: &id010 !ruby/object:Gem::Requirement
119
119
  none: false
@@ -121,10 +121,10 @@ dependencies:
121
121
  - - ">="
122
122
  - !ruby/object:Gem::Version
123
123
  version: "0"
124
- type: :development
124
+ type: :runtime
125
125
  version_requirements: *id010
126
126
  - !ruby/object:Gem::Dependency
127
- name: cucumber-rails
127
+ name: sqlite3
128
128
  prerelease: false
129
129
  requirement: &id011 !ruby/object:Gem::Requirement
130
130
  none: false
@@ -135,7 +135,7 @@ dependencies:
135
135
  type: :development
136
136
  version_requirements: *id011
137
137
  - !ruby/object:Gem::Dependency
138
- name: factory_girl_rails
138
+ name: cucumber-rails
139
139
  prerelease: false
140
140
  requirement: &id012 !ruby/object:Gem::Requirement
141
141
  none: false
@@ -146,7 +146,7 @@ dependencies:
146
146
  type: :development
147
147
  version_requirements: *id012
148
148
  - !ruby/object:Gem::Dependency
149
- name: launchy
149
+ name: factory_girl_rails
150
150
  prerelease: false
151
151
  requirement: &id013 !ruby/object:Gem::Requirement
152
152
  none: false
@@ -157,7 +157,7 @@ dependencies:
157
157
  type: :development
158
158
  version_requirements: *id013
159
159
  - !ruby/object:Gem::Dependency
160
- name: database_cleaner
160
+ name: launchy
161
161
  prerelease: false
162
162
  requirement: &id014 !ruby/object:Gem::Requirement
163
163
  none: false
@@ -168,29 +168,29 @@ dependencies:
168
168
  type: :development
169
169
  version_requirements: *id014
170
170
  - !ruby/object:Gem::Dependency
171
- name: rspec-rails
171
+ name: database_cleaner
172
172
  prerelease: false
173
173
  requirement: &id015 !ruby/object:Gem::Requirement
174
174
  none: false
175
175
  requirements:
176
- - - ~>
176
+ - - ">="
177
177
  - !ruby/object:Gem::Version
178
- version: "2.5"
178
+ version: "0"
179
179
  type: :development
180
180
  version_requirements: *id015
181
181
  - !ruby/object:Gem::Dependency
182
- name: devise
182
+ name: rspec-rails
183
183
  prerelease: false
184
184
  requirement: &id016 !ruby/object:Gem::Requirement
185
185
  none: false
186
186
  requirements:
187
- - - ">="
187
+ - - ~>
188
188
  - !ruby/object:Gem::Version
189
- version: "0"
189
+ version: "2.5"
190
190
  type: :development
191
191
  version_requirements: *id016
192
192
  - !ruby/object:Gem::Dependency
193
- name: grb
193
+ name: devise
194
194
  prerelease: false
195
195
  requirement: &id017 !ruby/object:Gem::Requirement
196
196
  none: false
@@ -201,7 +201,7 @@ dependencies:
201
201
  type: :development
202
202
  version_requirements: *id017
203
203
  - !ruby/object:Gem::Dependency
204
- name: email_spec
204
+ name: grb
205
205
  prerelease: false
206
206
  requirement: &id018 !ruby/object:Gem::Requirement
207
207
  none: false
@@ -211,6 +211,17 @@ dependencies:
211
211
  version: "0"
212
212
  type: :development
213
213
  version_requirements: *id018
214
+ - !ruby/object:Gem::Dependency
215
+ name: email_spec
216
+ prerelease: false
217
+ requirement: &id019 !ruby/object:Gem::Requirement
218
+ none: false
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: "0"
223
+ type: :development
224
+ version_requirements: *id019
214
225
  description: Don't use. Not production ready
215
226
  email:
216
227
  - coryschires@gmail.com
@@ -487,11 +498,13 @@ files:
487
498
  - app/assets/stylesheets/rostra/typography.css
488
499
  - app/controllers/rostra/answers_controller.rb
489
500
  - app/controllers/rostra/application_controller.rb
501
+ - app/controllers/rostra/base/answers_controller.rb
502
+ - app/controllers/rostra/base/comments_controller.rb
490
503
  - app/controllers/rostra/base/questions_controller.rb
491
504
  - app/controllers/rostra/comments_controller.rb
492
505
  - app/controllers/rostra/questions_controller.rb
493
506
  - app/helpers/rostra/application_helper.rb
494
- - app/helpers/rostra/base_helper.rb
507
+ - app/helpers/rostra/base/application_helper.rb
495
508
  - app/mailers/rostra/application_mailer.rb
496
509
  - app/models/comment.rb
497
510
  - app/models/rostra/ability.rb
@@ -510,8 +523,10 @@ files:
510
523
  - app/views/rostra/questions/index.html.erb
511
524
  - app/views/rostra/questions/new.html.erb
512
525
  - app/views/rostra/questions/show.html.erb
526
+ - app/views/rostra/questions/toggle_following.js.erb
513
527
  - app/views/rostra/questions/vote.js.erb
514
528
  - app/views/rostra/shared/_sidebar.html.erb
529
+ - app/views/rostra/shared/_toggle_following_question_button.html.erb
515
530
  - app/views/rostra/shared/_votes.html.erb
516
531
  - config/cucumber.yml
517
532
  - config/initializers/client_side_validations.rb
@@ -1,87 +0,0 @@
1
- module Rostra
2
- module BaseHelper
3
-
4
- # Method used to render to user names (e.g. where it says: "John Does says:"). You can,
5
- # for example, use this method to turn "John Doe" into a link to his profile page.
6
- #
7
- def link_to_profile(user)
8
- link_to user.rostra_user_name, main_app.user_path(user)
9
- end
10
-
11
- # Used to populate both the <tt>title</tt> and <tt>h1</tt> elements for each page.
12
- #
13
- def page_title_helper
14
- case "#{controller_name}##{action_name}"
15
- when "questions#show" then @question.title
16
- when "questions#index" then
17
- if params[:tag_search].present?
18
- "Recent Questions for tag #{params[:tag_search]}"
19
- else
20
- "Recent Questions"
21
- end
22
- when "questions#new" then "Post a new question"
23
- when "questions#edit" then "Editing question"
24
- when "answers#edit" then "Editing answer"
25
- else "Recent Questions"
26
- end
27
- end
28
-
29
- # Creates a list of tags linking to the index showing only questions with that tag
30
- #
31
- def tag_list(question)
32
- tags = question.tags.map { |tag| link_to tag, questions_path(:tag_search => "#{tag}")}.join
33
- content_tag :div, "Tags: #{tags}".html_safe, class: 'tags'
34
- end
35
-
36
- # Finds the url to the user's avatar following this logic:
37
- #
38
- # 1. Calls <tt>avatar</tt> on the user object
39
- # 2. Uses the users email address to look for a gravatar
40
- # 3. Renders <tt>app/assets/images/rostra/anonymous_avatar.png</tt>
41
- #
42
- def rostra_user_avatar(user)
43
- if user.respond_to?(:avatar)
44
- url = user.avatar
45
- else
46
- default_url = "#{main_app.root_url}assets/rostra/anonymous_avatar.png"
47
- gravatar_id = Digest::MD5.hexdigest(user.rostra_user_email.downcase)
48
- url = "http://gravatar.com/avatar/#{gravatar_id}.png?s=48&d=#{CGI.escape(default_url)}"
49
- end
50
- image_tag(url, class: 'avatar')
51
- end
52
-
53
- # Method to build links for ajax-y voting arrows.
54
- #
55
- def link_to_vote(direction, resource)
56
- if user_signed_in? && ( (direction == :up && rostra_user.voted_for?(resource)) || (direction == :down && rostra_user.voted_against?(resource)) )
57
- selected = 'selected'
58
- else
59
- selected = ''
60
- end
61
-
62
- link_to "Vote #{direction.capitalize}", vote_path(resource, direction), method: :put, remote: true, class: "vote #{direction} #{selected}"
63
- end
64
-
65
- # Returns a rostra object's base class name. For example, <tt>@question</tt> is an instance of
66
- # Rostra::Question and so:
67
- #
68
- # class_name(@question) # => 'question'
69
- #
70
- def class_name(resource)
71
- resource.class.name.split('::').last.downcase
72
- end
73
-
74
- private
75
-
76
- def vote_path(resource, direction)
77
- return '#' if !user_signed_in? || can?(:manage, resource)
78
-
79
- if resource.is_a?(Rostra::Question)
80
- vote_question_path(resource, vote_direction: direction)
81
- else
82
- vote_question_answer_path(resource.question, resource, vote_direction: direction)
83
- end
84
- end
85
-
86
- end
87
- end