rostra 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
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