rostra 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -18,9 +18,9 @@ Install and run the necessary migrations:
18
18
  rake rostra:install:migrations
19
19
  rake db:migrate
20
20
 
21
- Run the generator to create the configuration file:
21
+ Run the generator to create <tt>config/initializers/rostra.rb</tt> and <tt>app/helpers/application_helper.rb</tt>:
22
22
 
23
- rails generate rostra:install # see `config/initializers/rostra.rb` for details
23
+ rails generate rostra:install
24
24
 
25
25
  Call <tt>rostra</tt> in your user model:
26
26
 
@@ -38,7 +38,9 @@ There's some stuff you'll almost definitely want to do in order to get Rostra wo
38
38
  Also, be sure to read through <tt>config/initializers/rostra.rb</tt> and override configuration options to suit your app. At the very least, you'll want to change:
39
39
 
40
40
  config.deliver_emails_from = 'change_me@example.com'
41
- `
41
+
42
+ Finally, have a look at <tt>app/helpers/rostra/application_helper.rb</tt>, you may need to add/override helper methods.
43
+
42
44
  == Customizing the question and answer models
43
45
  Rostra provides a DSL for adding application specific logic to <tt>Rostra::Question</tt> and <tt>Rostra:Answer</tt>:
44
46
 
@@ -67,6 +69,11 @@ Rostra provides a DSL for adding application specific logic to <tt>Rostra::Quest
67
69
  end
68
70
  end
69
71
 
72
+ == Setting permissions
73
+ 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
+
75
+ If you need to change these defaults, override <tt>can_participate_in_rostra?</tt> in your user model. <tt>CanCan</tt> will use this method to determine who can participate. If you need to specify even more complicated permissions, override <tt>app/models/rostra/ability.rb</tt> and go wild.
76
+
70
77
 
71
78
  == Contributing to Rostra
72
79
  Fork the project, make your changes, and submit a pull request. Please ensure the tests pass:
@@ -47,7 +47,7 @@ $(document).ready(function() {
47
47
  theme_advanced_buttons3 : "",
48
48
  theme_advanced_toolbar_location : "top",
49
49
  theme_advanced_toolbar_align : "left",
50
- plugins: 'paste, autoresize',
50
+ plugins: 'paste',
51
51
  paste_remove_styles: true,
52
52
  paste_remove_spans: true,
53
53
  setup: function (ed) {
@@ -1,68 +1,5 @@
1
1
  module Rostra
2
2
  module ApplicationHelper
3
-
4
- # Loop thru included helper files and include them in the project.
5
- #
6
- Rostra::Config.included_helpers.each do |helper_file|
7
- include helper_file
8
- end
9
-
10
- # Creates a list of tags linking to the index showing only questions with that tag
11
- #
12
- def tag_list(question)
13
- content_tag :div, "Tags: #{question.tags.map { |tag| link_to tag, questions_path(:tag_search => "#{tag}")}.join}".html_safe, class: 'tags'
14
- end
15
-
16
- # Finds the url to the user's avatar following this logic:
17
- #
18
- # 1. Calls the method defined in the <tt>Rostra::Config</tt>
19
- # 2. Uses the users email address to looks for a gravatar
20
- # 3. Renders <tt>app/assets/images/rostra/anonymous_avatar.png</tt>
21
- #
22
- def avatar_url(user)
23
- avatar_method = Rostra::Config.rostra_user_avatar
24
-
25
- if user.respond_to?(avatar_method)
26
- user.send(avatar_method)
27
- else
28
- default_url = "#{main_app.root_url}assets/rostra/anonymous_avatar.png"
29
- gravatar_id = Digest::MD5.hexdigest(user.rostra_user_email.downcase)
30
- "http://gravatar.com/avatar/#{gravatar_id}.png?s=48&d=#{CGI.escape(default_url)}"
31
- end
32
- end
33
-
34
- # Method to build links for ajax-y voting arrows.
35
- #
36
- def link_to_vote(direction, resource)
37
- if user_signed_in? && ( (direction == :up && rostra_user.voted_for?(resource)) || (direction == :down && rostra_user.voted_against?(resource)) )
38
- selected = 'selected'
39
- else
40
- selected = ''
41
- end
42
-
43
- link_to "Vote #{direction.capitalize}", vote_path(resource, direction), method: :put, remote: true, class: "vote #{direction} #{selected}"
44
- end
45
-
46
- # Returns a rostra object's base class name. For example, <tt>@question</tt> is an instance of
47
- # Rostra::Question and so:
48
- #
49
- # class_name(@question) # => 'question'
50
- #
51
- def class_name(resource)
52
- resource.class.name.split('::').last.downcase
53
- end
54
-
55
- private
56
-
57
- def vote_path(resource, direction)
58
- return '#' if !user_signed_in? || can?(:manage, resource)
59
-
60
- if resource.is_a?(Rostra::Question)
61
- vote_question_path(resource, vote_direction: direction)
62
- else
63
- vote_question_answer_path(resource.question, resource, vote_direction: direction)
64
- end
65
- end
66
-
3
+ include Rostra::BaseHelper
67
4
  end
68
5
  end
@@ -0,0 +1,86 @@
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 avatar_url(user)
43
+ if user.respond_to?(:avatar)
44
+ 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
+ "http://gravatar.com/avatar/#{gravatar_id}.png?s=48&d=#{CGI.escape(default_url)}"
49
+ end
50
+ end
51
+
52
+ # Method to build links for ajax-y voting arrows.
53
+ #
54
+ def link_to_vote(direction, resource)
55
+ if user_signed_in? && ( (direction == :up && rostra_user.voted_for?(resource)) || (direction == :down && rostra_user.voted_against?(resource)) )
56
+ selected = 'selected'
57
+ else
58
+ selected = ''
59
+ end
60
+
61
+ link_to "Vote #{direction.capitalize}", vote_path(resource, direction), method: :put, remote: true, class: "vote #{direction} #{selected}"
62
+ end
63
+
64
+ # Returns a rostra object's base class name. For example, <tt>@question</tt> is an instance of
65
+ # Rostra::Question and so:
66
+ #
67
+ # class_name(@question) # => 'question'
68
+ #
69
+ def class_name(resource)
70
+ resource.class.name.split('::').last.downcase
71
+ end
72
+
73
+ private
74
+
75
+ def vote_path(resource, direction)
76
+ return '#' if !user_signed_in? || can?(:manage, resource)
77
+
78
+ if resource.is_a?(Rostra::Question)
79
+ vote_question_path(resource, vote_direction: direction)
80
+ else
81
+ vote_question_answer_path(resource.question, resource, vote_direction: direction)
82
+ end
83
+ end
84
+
85
+ end
86
+ end
@@ -7,7 +7,7 @@ module Rostra
7
7
  def initialize(user)
8
8
  @user = user || User.new
9
9
 
10
- if logged_in?
10
+ if @user.can_participate_in_rostra?
11
11
  can :manage, Question, :user => user
12
12
  can :manage, Answer, :user => user
13
13
  can :manage, Comment, :user => user
@@ -22,11 +22,5 @@ module Rostra
22
22
  can :read, :all
23
23
  end
24
24
 
25
- private
26
-
27
- def logged_in?
28
- ! user.new_record?
29
- end
30
-
31
25
  end
32
26
  end
@@ -1,9 +1,9 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <title>Rostra</title>
5
- <%= stylesheet_link_tag "rostra/application" %>
6
- <%= javascript_include_tag "rostra/application" %>
4
+ <title><%=page_title_helper || 'Rostra' %></title>
5
+ <%= stylesheet_link_tag 'rostra/application' %>
6
+ <%= javascript_include_tag 'rostra/application' %>
7
7
  <%= csrf_meta_tags %>
8
8
  </head>
9
9
  <body id="<%= controller_name %>" class="<%= action_name %>">
@@ -15,21 +15,7 @@
15
15
  <%= content_tag :div, msg, id: "flash_#{name}", class: 'flash' %>
16
16
  <% end %>
17
17
 
18
- <h1><%=
19
- case "#{controller_name}##{action_name}"
20
- when "questions#show" then @question.title
21
- when "questions#index" then
22
- if params[:tag_search].present?
23
- "Recent Questions for tag #{params[:tag_search]}"
24
- else
25
- "Recent Questions"
26
- end
27
- when "questions#new" then "Post a new question"
28
- when "questions#edit" then "Editing question"
29
- when "answers#edit" then "Editing answer"
30
- else "Recent Questions"
31
- end
32
- %></h1>
18
+ <h1><%=page_title_helper %></h1>
33
19
 
34
20
  <%= yield %>
35
21
  </div>
@@ -22,7 +22,6 @@
22
22
  <div class="views_count">
23
23
  <span class="count"><%= question.unique_page_views %></span>
24
24
  <span class="type"><%= question.unique_page_views.abs == 1 ? 'view' : 'views' %></span>
25
-
26
25
  </div>
27
26
  </div>
28
27
 
@@ -30,7 +29,7 @@
30
29
 
31
30
  <h3 class="title"><%= link_to question.title, question %></h3>
32
31
  <cite>
33
- Asked by <%= question.user.rostra_user_name %>
32
+ Asked by <%= link_to_profile(question.user) %>
34
33
  <%= link_to 'edit', edit_question_path(question) if can? :manage, question %>
35
34
  </cite>
36
35
  <div class="text">
@@ -6,7 +6,7 @@
6
6
  <%= render partial: 'rostra/shared/votes', locals: { resource: @question } %>
7
7
  <%= image_tag avatar_url(@question.user), class: 'avatar' %>
8
8
  <cite>
9
- Asked by <%= @question.user.rostra_user_name %>
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
12
  <div class="text"><%= simple_format(@question.details) %></div>
@@ -22,7 +22,7 @@
22
22
  <%= render partial: 'rostra/shared/votes', locals: { resource: answer } %>
23
23
  <%= image_tag avatar_url(answer.user), class: 'avatar' %>
24
24
  <cite>
25
- <%= answer.user.rostra_user_name %> says:
25
+ <%= link_to_profile(answer.user) %> says:
26
26
  <%= link_to('edit', edit_question_answer_path(@question, answer)) if can? :manage, answer %>
27
27
  </cite>
28
28
  <div class="text"><%= simple_format(answer.text) %></div>
@@ -34,10 +34,10 @@
34
34
  <div class="comment text">
35
35
  <div class="editable" data-ajax_url="<%= question_comment_path(@question, comment) %>"><%= comment.comment %></div>
36
36
  <div class="timestamp">
37
- <%= comment.user.rostra_user_name %> – <%= time_ago_in_words(comment.updated_at) %> ago
37
+ <%= link_to_profile(comment.user) %> – <%= time_ago_in_words(comment.updated_at) %> ago
38
38
  <% if can? :manage, comment %>
39
39
  <%= link_to('edit', question_comment_path(@question, comment), class: 'edit_comment') %>
40
- <%= link_to('delete', question_comment_path(@question, comment), method: :delete, confirm: 'Are you sure?') if can? :manage, comment %>
40
+ <%= link_to('delete', question_comment_path(@question, comment), method: :delete, confirm: 'Are you sure?') %>
41
41
  <% end %>
42
42
  </div>
43
43
  </div>
@@ -47,9 +47,9 @@
47
47
 
48
48
 
49
49
  <% if can? :manage, Comment %>
50
- <%= link_to("leave comment", '#', class: 'leave_comment') %>
50
+ <%= link_to("comment on this answer", '#', class: 'leave_comment') %>
51
51
  <% else %>
52
- <%= link_to("login leave comment", main_app_login_path) %>
52
+ <%= link_to("login to leave comment", main_app_login_path) %>
53
53
  <% end %>
54
54
 
55
55
 
@@ -5,10 +5,16 @@ module Rostra
5
5
  source_root File.expand_path('../templates', __FILE__)
6
6
  class_option :template_engine
7
7
 
8
+ desc "Generate configuration file where you can set/override Rostra options"
8
9
  def copy_config
9
10
  directory 'config'
10
11
  end
11
12
 
13
+ desc "Generate application helper file where you can set/override Rostra helper methods"
14
+ def copy_application_helper
15
+ directory 'app'
16
+ end
17
+
12
18
  end
13
19
  end
14
20
  end
@@ -0,0 +1,58 @@
1
+ module Rostra
2
+ module ApplicationHelper
3
+ # If you don't need to make any changes, you can delete this file.
4
+ #
5
+ # Include base helper methods required for Rostra views. You probably don't want to remove
6
+ # this line but you can add/override rostra methods in this file. The helpers which you may
7
+ # need to override are listed below. Just un-comment them and make changes.
8
+ #
9
+ include Rostra::BaseHelper
10
+
11
+ # If you want to user helper methods defined elsewhere in your app, you can include them here
12
+ # as well. For example:
13
+ #
14
+ # include MainAppHelper
15
+
16
+ # Creates a list of tags linking to the index showing only questions with that tag
17
+ #
18
+ # def tag_list(question)
19
+ # tags = question.tags.map { |tag| link_to tag, questions_path(:tag_search => "#{tag}")}.join
20
+ # content_tag :div, "Tags: #{tags}".html_safe, class: 'tags'
21
+ # end
22
+
23
+ # Finds the url to the user's avatar following this logic:
24
+ #
25
+ # 1. Calls <tt>avatar</tt> on the user object
26
+ # 2. Uses the users email address to look for a gravatar
27
+ # 3. Renders <tt>app/assets/images/rostra/anonymous_avatar.png</tt>
28
+ #
29
+ # def avatar_url(user)
30
+ # if user.respond_to?(:avatar)
31
+ # user.avatar
32
+ # else
33
+ # default_url = "#{main_app.root_url}assets/rostra/anonymous_avatar.png"
34
+ # gravatar_id = Digest::MD5.hexdigest(user.rostra_user_email.downcase)
35
+ # "http://gravatar.com/avatar/#{gravatar_id}.png?s=48&d=#{CGI.escape(default_url)}"
36
+ # end
37
+ # end
38
+
39
+ # Used to populate both the <tt>title</tt> and <tt>h1</tt> elements for each page.
40
+ #
41
+ # def page_title_helper
42
+ # case "#{controller_name}##{action_name}"
43
+ # when "questions#show" then @question.title
44
+ # when "questions#index" then
45
+ # if params[:tag_search].present?
46
+ # "Recent Questions for tag #{params[:tag_search]}"
47
+ # else
48
+ # "Recent Questions"
49
+ # end
50
+ # when "questions#new" then "Post a new question"
51
+ # when "questions#edit" then "Editing question"
52
+ # when "answers#edit" then "Editing answer"
53
+ # else "Recent Questions"
54
+ # end
55
+ # end
56
+
57
+ end
58
+ end
@@ -1,13 +1,5 @@
1
1
  # Use this setup block to configure all options available in Rostra.
2
2
  Rostra::Config.setup do |config|
3
-
4
- # If you want to access helpers defined in your main app, add them to this array.
5
- # For example, if you'd like to use helpers defined in your <tt>ApplicationHelper</tt>:
6
- #
7
- # config.included_helpers = [ ApplicationHelper ]
8
- #
9
- # config.included_helpers = []
10
-
11
3
  # Helper method used to access current user in the view
12
4
  # config.deliver_emails_from = 'change_me@example.com'
13
5
 
@@ -20,15 +12,6 @@ Rostra::Config.setup do |config|
20
12
  # Method called on the rostra'd model (e.g. User) to access the users email address
21
13
  # config.rostra_user_email = :email
22
14
 
23
- # Method called on the rostra'd model (e.g. User) to access the users avatar. It
24
- # looks for an avatar in this order:
25
- #
26
- # 1. Calls the method defined here
27
- # 2. Uses the users email address to looks for a gravatar
28
- # 3. Renders <tt>app/assets/images/rostra/anonymous_avatar.png</tt>
29
- #
30
- # config.rostra_user_avatar = :avatar
31
-
32
15
  # Route to your login page
33
16
  # config.main_app_login_path = :new_user_session_path
34
17
 
data/lib/rostra/config.rb CHANGED
@@ -1,14 +1,6 @@
1
1
  module Rostra
2
2
  module Config
3
3
 
4
- # If you want to access helpers defined in your main app, add them to this array.
5
- # For example, if you'd like to use helpers defined in your <tt>ApplicationHelper</tt>:
6
- #
7
- # config.included_helpers = [ ApplicationHelper ]
8
- #
9
- mattr_accessor :included_helpers
10
- @@included_helpers = []
11
-
12
4
  # Helper method used to access current user in the view
13
5
  #
14
6
  mattr_accessor :deliver_emails_from
@@ -29,16 +21,6 @@ module Rostra
29
21
  mattr_accessor :rostra_user_email
30
22
  @@rostra_user_email = :email
31
23
 
32
- # Method called on the rostra'd model (e.g. User) to access the users avatar. It looks
33
- # for an avatar in this order:
34
- #
35
- # 1. Calls the method defined here
36
- # 2. Uses the users email address to looks for a gravatar
37
- # 3. Renders <tt>app/assets/images/rostra/anonymous_avatar.png</tt>
38
- #
39
- mattr_accessor :rostra_user_avatar
40
- @@rostra_user_avatar = :avatar
41
-
42
24
  # Route to your login page
43
25
  #
44
26
  mattr_accessor :main_app_login_path
@@ -1,3 +1,3 @@
1
1
  module Rostra
2
- VERSION = "0.0.10"
2
+ VERSION = "0.0.11"
3
3
  end
data/lib/rostra.rb CHANGED
@@ -63,6 +63,22 @@ module Rostra
63
63
  end
64
64
  end
65
65
 
66
+ # By default anyone can read rostra content - even if they are not logged in. This method
67
+ # determines if users can contribute content (i.e. ask questions, give answers, and leave
68
+ # comments). If <tt>can_participate_in_rostra?</tt> returns true, the user can contribute
69
+ # content, otherwise they're restricted to read only.
70
+ #
71
+ # Under the hood, Rostra uses <tt>CanCan</tt> to set permissions and this is the only
72
+ # place where <tt>can_participate_in_rostra?</tt> is actully used. The default is very
73
+ # simple, if the user exists (i.e. they are logged in), then they may participate. But
74
+ # you can override this method in your <tt>User</tt> model to set more complicated
75
+ # conditions participation. If you need to specify even more complicated permissions,
76
+ # override <tt>app/models/rostra/ability.rb</tt> and go wild.
77
+ #
78
+ def can_participate_in_rostra?
79
+ !new_record?
80
+ end
81
+
66
82
  # Rostra will use this method to find a user's full name.
67
83
  #
68
84
  def rostra_user_name
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rostra
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.10
5
+ version: 0.0.11
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-20 00:00:00 -05:00
13
+ date: 2011-10-22 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -490,13 +490,13 @@ files:
490
490
  - app/controllers/rostra/comments_controller.rb
491
491
  - app/controllers/rostra/questions_controller.rb
492
492
  - app/helpers/rostra/application_helper.rb
493
+ - app/helpers/rostra/base_helper.rb
493
494
  - app/mailers/rostra/application_mailer.rb
494
495
  - app/models/comment.rb
495
496
  - app/models/rostra/ability.rb
496
497
  - app/models/rostra/answer.rb
497
498
  - app/models/rostra/question.rb
498
499
  - app/models/rostra/question_following.rb
499
- - app/models/rostra/vote.rb
500
500
  - app/models/vote.rb
501
501
  - app/views/layouts/rostra/application.html.erb
502
502
  - app/views/rostra/answers/_form.html.erb
@@ -526,6 +526,7 @@ files:
526
526
  - db/migrate/20111016021105_create_impressions_table.rb
527
527
  - db/migrate/20111019162723_create_rostra_question_followings.rb
528
528
  - lib/generators/rostra/install_generator.rb
529
+ - lib/generators/rostra/templates/app/helpers/rostra/application_helper.rb
529
530
  - lib/generators/rostra/templates/config/initializers/rostra.rb
530
531
  - lib/rostra/config.rb
531
532
  - lib/rostra/email_notifier.rb
@@ -1,19 +0,0 @@
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