Initial attempt at comments
This commit is contained in:
parent
86e1cd891c
commit
bbdc0001b4
36 changed files with 687 additions and 62 deletions
1
Gemfile
1
Gemfile
|
@ -21,6 +21,7 @@ gem 'bootstrap-sass'
|
||||||
gem 'simple_form'
|
gem 'simple_form'
|
||||||
|
|
||||||
gem 'friendly_id', '~> 5.1.0'
|
gem 'friendly_id', '~> 5.1.0'
|
||||||
|
gem 'ancestry'
|
||||||
|
|
||||||
gem 'bcrypt'
|
gem 'bcrypt'
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ GEM
|
||||||
ice_nine (~> 0.11.0)
|
ice_nine (~> 0.11.0)
|
||||||
memoizable (~> 0.4.0)
|
memoizable (~> 0.4.0)
|
||||||
addressable (2.3.8)
|
addressable (2.3.8)
|
||||||
|
ancestry (2.1.0)
|
||||||
|
activerecord (>= 3.0.0)
|
||||||
arel (6.0.0)
|
arel (6.0.0)
|
||||||
arrayfields (4.9.2)
|
arrayfields (4.9.2)
|
||||||
ast (2.0.0)
|
ast (2.0.0)
|
||||||
|
@ -365,6 +367,7 @@ PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
ancestry
|
||||||
bcrypt
|
bcrypt
|
||||||
better_errors
|
better_errors
|
||||||
binding_of_caller
|
binding_of_caller
|
||||||
|
|
3
app/assets/javascripts/comments.coffee
Normal file
3
app/assets/javascripts/comments.coffee
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Place all the behaviors and hooks related to the matching controller here.
|
||||||
|
# All this logic will automatically be available in application.js.
|
||||||
|
# You can use CoffeeScript in this file: http://coffeescript.org/
|
3
app/assets/stylesheets/comments.scss
Normal file
3
app/assets/stylesheets/comments.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// Place all the styles related to the Comments controller here.
|
||||||
|
// They will automatically be included in application.css.
|
||||||
|
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -42,6 +42,10 @@ $navbar-default-link-hover-color: #369;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
font-size: .8em;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
.logo {
|
.logo {
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
|
@ -49,32 +53,7 @@ $navbar-default-link-hover-color: #369;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.posts {
|
.contents {
|
||||||
.post {
|
|
||||||
p {
|
|
||||||
margin-bottom: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.details {
|
|
||||||
font-size: .8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.links {
|
|
||||||
font-size: .8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
border: 1px solid #369;
|
|
||||||
background-color: #fafafa;
|
|
||||||
border-radius: 7px; // need to work all browsers
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
@ -90,6 +69,38 @@ $navbar-default-link-hover-color: #369;
|
||||||
li:first-child {
|
li:first-child {
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details {
|
||||||
|
font-size: .8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.posts {
|
||||||
|
.post {
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin: 4px 0 4px 0;
|
||||||
|
border: 1px solid #369;
|
||||||
|
background-color: #fafafa;
|
||||||
|
border-radius: 7px; // need to work all browsers
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comments {
|
||||||
|
.comment {
|
||||||
|
margin: 15px 0 15px 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-custom {
|
.navbar-custom {
|
||||||
|
@ -99,3 +110,15 @@ $navbar-default-link-hover-color: #369;
|
||||||
.main {
|
.main {
|
||||||
margin: 0 5px 0 5px;
|
margin: 0 5px 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nested_comments {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.in-page {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
62
app/controllers/comments_controller.rb
Normal file
62
app/controllers/comments_controller.rb
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
class CommentsController < ApplicationController
|
||||||
|
before_filter :set_comment, only: [:show, :edit, :update, :destroy]
|
||||||
|
before_filter :set_post
|
||||||
|
before_filter :set_subcreddit
|
||||||
|
|
||||||
|
def show
|
||||||
|
@comments = @comment.subtree.arrange(order: :created_at)
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@comment = Comment.new(params[:parent_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@comment = @post.comments.build comment_params
|
||||||
|
@comment.user = current_user
|
||||||
|
|
||||||
|
if @comment.save
|
||||||
|
flash[:notice] = 'Comment saved'
|
||||||
|
else
|
||||||
|
flash[:alert] = 'Comment could not be saved'
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to subcreddit_post_path(@subcreddit, @post)
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
if @comment.update comment_params
|
||||||
|
redirect_to subcreddit_post_path(@subcreddit, @post),
|
||||||
|
notice: 'Comment updated'
|
||||||
|
else
|
||||||
|
render :edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@comment.destroy
|
||||||
|
redirect_to subcreddit_post_path(@subcreddit, @post),
|
||||||
|
notice: 'Comment deleted'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_subcreddit
|
||||||
|
@subcreddit = Subcreddit.friendly.find(params[:subcreddit_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_post
|
||||||
|
@post = Post.find(params[:post_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_comment
|
||||||
|
@comment = Comment.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def comment_params
|
||||||
|
params.require(:comment).permit(:parent_id, :content)
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,6 +3,7 @@ class PostsController < ApplicationController
|
||||||
before_filter :set_subcreddit
|
before_filter :set_subcreddit
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@comments = @post.comments.arrange(order: :created_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
|
|
@ -6,11 +6,11 @@ module ApplicationHelper
|
||||||
private
|
private
|
||||||
|
|
||||||
def bootstrap_classes
|
def bootstrap_classes
|
||||||
{
|
{
|
||||||
'alert' => 'alert-warning',
|
'alert' => 'alert-warning',
|
||||||
'error' => 'alert-danger',
|
'error' => 'alert-danger',
|
||||||
'notice' => 'alert-info',
|
'notice' => 'alert-info',
|
||||||
'success' => 'alert-success'
|
'success' => 'alert-success'
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
10
app/helpers/comments_helper.rb
Normal file
10
app/helpers/comments_helper.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module CommentsHelper
|
||||||
|
def nested_comments(comments)
|
||||||
|
comments.map do |comment, sub_comments|
|
||||||
|
render(comment, post: comment.post, subcreddit: comment.post.subcreddit) +
|
||||||
|
content_tag(:div,
|
||||||
|
nested_comments(sub_comments),
|
||||||
|
class: 'nested_comments')
|
||||||
|
end.join.html_safe
|
||||||
|
end
|
||||||
|
end
|
22
app/models/comment.rb
Normal file
22
app/models/comment.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
class Comment < ActiveRecord::Base
|
||||||
|
has_ancestry
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :post, counter_cache: true
|
||||||
|
|
||||||
|
delegate :username, to: :user, prefix: true
|
||||||
|
|
||||||
|
validates :content, presence: true
|
||||||
|
|
||||||
|
def content
|
||||||
|
destroyed? ? '[deleted]' : read_attribute(:content)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
update_attribute(:deleted_at, Time.now)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroyed?
|
||||||
|
self.deleted_at != nil
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,6 +2,8 @@ class Post < ActiveRecord::Base
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :subcreddit
|
belongs_to :subcreddit
|
||||||
|
|
||||||
|
has_many :comments
|
||||||
|
|
||||||
delegate :username, to: :user, prefix: true
|
delegate :username, to: :user, prefix: true
|
||||||
|
|
||||||
validates :title,
|
validates :title,
|
||||||
|
@ -12,6 +14,16 @@ class Post < ActiveRecord::Base
|
||||||
length: { maximum: 15000 }
|
length: { maximum: 15000 }
|
||||||
|
|
||||||
def to_param
|
def to_param
|
||||||
|
# This "just works" because of the way Rails IDs work. .to_i must be run on
|
||||||
|
# any incoming ID. "1-title-parameterized" will automatically be converted
|
||||||
|
# to 1 and "2-title-paramerterized-with-number-2" will automatically be
|
||||||
|
# converted to 2. This gives us desired functionality without adding code
|
||||||
|
# to properly handle retrieving based on slug. Hopefully, this does not
|
||||||
|
# cause issues later on.
|
||||||
"#{self.id}-#{self.title.parameterize}"
|
"#{self.id}-#{self.title.parameterize}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def comments?
|
||||||
|
self.comments_count != 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
13
app/views/comments/_comment.html.slim
Normal file
13
app/views/comments/_comment.html.slim
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
.comment
|
||||||
|
p.details= "#{comment.user_username} X points #{distance_of_time_in_words comment.created_at, Time.now} ago"
|
||||||
|
p.content= comment.content
|
||||||
|
ul.links.list-inline
|
||||||
|
li= link_to 'permalink', subcreddit_post_comment_path(subcreddit, post, comment)
|
||||||
|
li= link_to 'save', ''
|
||||||
|
- if comment.parent
|
||||||
|
li= link_to 'parent', subcreddit_post_comment_path(subcreddit, post, comment.parent)
|
||||||
|
li= link_to 'edit', edit_subcreddit_post_comment_path(subcreddit, post, comment)
|
||||||
|
li= link_to 'delete', subcreddit_post_comment_path(subcreddit, post, comment), method: :delete
|
||||||
|
li= link_to 'spam', ''
|
||||||
|
li= link_to 'remove', ''
|
||||||
|
li= link_to 'give gold', ''
|
7
app/views/comments/_form.html.slim
Normal file
7
app/views/comments/_form.html.slim
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
= simple_form_for [subcreddit, post, comment] do |f|
|
||||||
|
- if local_assigns.has_key?(:parent) && parent
|
||||||
|
= f.hidden_field :parent_id, value: parent.id
|
||||||
|
.form-inputs
|
||||||
|
= f.input :content, label: false
|
||||||
|
.form-actions
|
||||||
|
= f.button :submit
|
2
app/views/comments/edit.html.slim
Normal file
2
app/views/comments/edit.html.slim
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
h1 Edit comment
|
||||||
|
== render 'form', subcreddit: @subcreddit, post: @post, comment: @comment
|
0
app/views/comments/new.html.slim
Normal file
0
app/views/comments/new.html.slim
Normal file
8
app/views/comments/show.html.slim
Normal file
8
app/views/comments/show.html.slim
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
== render 'posts/post', post: @post
|
||||||
|
.alert.alert-info.in-page
|
||||||
|
p you are viewing a single comment's thread.
|
||||||
|
p #{link_to 'view the rest of the comments', subcreddit_post_path(@subcreddit, @post)} →
|
||||||
|
= "Commenting as: #{current_user.username}"
|
||||||
|
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: @comment
|
||||||
|
.comments.contents
|
||||||
|
== nested_comments(@comments)
|
|
@ -7,7 +7,7 @@ html
|
||||||
= csrf_meta_tags
|
= csrf_meta_tags
|
||||||
body
|
body
|
||||||
== render 'navbar'
|
== render 'navbar'
|
||||||
.container
|
.container-fluid
|
||||||
== render 'flash_messages'
|
== render 'flash_messages'
|
||||||
.main.container-fluid
|
.main.container-fluid
|
||||||
.col-md-3.pull-right
|
.col-md-3.pull-right
|
||||||
|
|
14
app/views/posts/_post.html.slim
Normal file
14
app/views/posts/_post.html.slim
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.posts.contents
|
||||||
|
.post.show
|
||||||
|
p.title= link_to post.title, [post.subcreddit, post]
|
||||||
|
p.details= "submitted #{distance_of_time_in_words post.created_at, Time.now} ago by #{post.user_username}"
|
||||||
|
p.content= post.content
|
||||||
|
ul.links.list-inline
|
||||||
|
li= link_to "#{post.comments_count} comments", subcreddit_post_path(post.subcreddit, post)
|
||||||
|
li= link_to 'share', ''
|
||||||
|
li= link_to 'edit', edit_subcreddit_post_path(post.subcreddit, post)
|
||||||
|
li= link_to 'save', ''
|
||||||
|
li= link_to 'hide', ''
|
||||||
|
li= link_to 'remove', ''
|
||||||
|
li= link_to 'approve', ''
|
||||||
|
li= link_to 'nsfw', ''
|
|
@ -1,18 +1,9 @@
|
||||||
.posts
|
== render 'post', post: @post
|
||||||
.post.show
|
- if @post.comments?
|
||||||
p.title= link_to @post.title, [@subcreddit, @post]
|
.title= "all #{@post.comments_count} comments"
|
||||||
p.details= "submitted #{distance_of_time_in_words @post.created_at, Time.now} ago by #{@post.user_username}"
|
- else
|
||||||
ul.links.list-inline
|
.title= "no comments (yet)"
|
||||||
li= link_to 'XXX comments', ''
|
= "Commenting as: #{current_user.username}"
|
||||||
li= link_to 'source', ''
|
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: nil
|
||||||
li= link_to 'share', ''
|
.comments.contents
|
||||||
li= link_to 'save', ''
|
== nested_comments(@comments)
|
||||||
li= link_to 'hide', ''
|
|
||||||
li= link_to 'give gold', ''
|
|
||||||
li= link_to 'spam', ''
|
|
||||||
li= link_to 'remove', ''
|
|
||||||
li= link_to 'approve', ''
|
|
||||||
li= link_to 'report', ''
|
|
||||||
li= link_to 'nsfw', ''
|
|
||||||
li= link_to 'hide all child comments', ''
|
|
||||||
p.content= @post.content
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
- if @subcreddit.closed?
|
- if @subcreddit.closed?
|
||||||
= "Board has been closed"
|
= "Board has been closed"
|
||||||
- else
|
- else
|
||||||
.posts
|
.posts.contents
|
||||||
ul
|
ul
|
||||||
- @subcreddit.posts.order('created_at DESC').each_with_index do |post, rank|
|
- @subcreddit.posts.order('created_at DESC').each_with_index do |post, rank|
|
||||||
li
|
li
|
||||||
.post
|
.post
|
||||||
p.title= link_to post.title, [@subcreddit, post]
|
p.title= link_to post.title, subcreddit_post_path(@subcreddit, post)
|
||||||
p.details= "submitted #{distance_of_time_in_words post.created_at, Time.now} ago by #{post.user_username}"
|
p.details= "submitted #{distance_of_time_in_words post.created_at, Time.now} ago by #{post.user_username}"
|
||||||
ul.links.list-inline
|
ul.links.list-inline
|
||||||
li= link_to 'XXX comments', ''
|
li= link_to "#{post.comments_count} comments", subcreddit_post_path(@subcreddit, post)
|
||||||
li= link_to 'share', ''
|
li= link_to 'share', ''
|
||||||
|
|
|
@ -38,4 +38,11 @@ Rails.application.configure do
|
||||||
|
|
||||||
# Raises error for missing translations
|
# Raises error for missing translations
|
||||||
# config.action_view.raise_on_missing_translations = true
|
# config.action_view.raise_on_missing_translations = true
|
||||||
|
|
||||||
|
# Bullet
|
||||||
|
config.after_initialize do
|
||||||
|
Bullet.enable = true
|
||||||
|
Bullet.bullet_logger = true
|
||||||
|
Bullet.add_footer = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,9 @@ Rails.application.routes.draw do
|
||||||
get 'signout', to: 'user_sessions#destroy', as: :signout
|
get 'signout', to: 'user_sessions#destroy', as: :signout
|
||||||
|
|
||||||
resources :subcreddits, path: 'c', except: [:destroy] do
|
resources :subcreddits, path: 'c', except: [:destroy] do
|
||||||
resources :posts, except: [:index]
|
resources :posts, path: '', constraints: { id: /\d+\-.+/ }, except: [:index] do
|
||||||
|
resources :comments, path: '', constraints: { id: /\d+/ }, except: [:index]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :user_sessions, only: [:new, :create, :destroy]
|
resources :user_sessions, only: [:new, :create, :destroy]
|
||||||
|
|
14
db/migrate/20150716155403_create_comments.rb
Normal file
14
db/migrate/20150716155403_create_comments.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
class CreateComments < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :comments do |t|
|
||||||
|
t.references :user, index: true, foreign_key: true
|
||||||
|
t.references :post, index: true, foreign_key: true
|
||||||
|
t.string :ancestry
|
||||||
|
t.text :content
|
||||||
|
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :comments, :ancestry
|
||||||
|
end
|
||||||
|
end
|
10
db/migrate/20150804000313_add_comments_count_to_post.rb
Normal file
10
db/migrate/20150804000313_add_comments_count_to_post.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
class AddCommentsCountToPost < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :posts, :comments_count, :integer, default: 0
|
||||||
|
|
||||||
|
Post.reset_column_information
|
||||||
|
Post.all.each do |p|
|
||||||
|
p.update_attribute :comments_count, p.comments.length
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
5
db/migrate/20150804145405_add_deleted_at_to_comments.rb
Normal file
5
db/migrate/20150804145405_add_deleted_at_to_comments.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class AddDeletedAtToComments < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :comments, :deleted_at, :datetime
|
||||||
|
end
|
||||||
|
end
|
21
db/schema.rb
21
db/schema.rb
|
@ -11,7 +11,21 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20150716050055) do
|
ActiveRecord::Schema.define(version: 20150804145405) do
|
||||||
|
|
||||||
|
create_table "comments", force: :cascade do |t|
|
||||||
|
t.integer "user_id"
|
||||||
|
t.integer "post_id"
|
||||||
|
t.string "ancestry"
|
||||||
|
t.text "content"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.datetime "deleted_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index "comments", ["ancestry"], name: "index_comments_on_ancestry"
|
||||||
|
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
|
||||||
|
add_index "comments", ["user_id"], name: "index_comments_on_user_id"
|
||||||
|
|
||||||
create_table "friendly_id_slugs", force: :cascade do |t|
|
create_table "friendly_id_slugs", force: :cascade do |t|
|
||||||
t.string "slug", null: false
|
t.string "slug", null: false
|
||||||
|
@ -32,8 +46,9 @@ ActiveRecord::Schema.define(version: 20150716050055) do
|
||||||
t.string "title"
|
t.string "title"
|
||||||
t.string "link"
|
t.string "link"
|
||||||
t.text "content"
|
t.text "content"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
|
t.integer "comments_count", default: 0
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "posts", ["subcreddit_id"], name: "index_posts_on_subcreddit_id"
|
add_index "posts", ["subcreddit_id"], name: "index_posts_on_subcreddit_id"
|
||||||
|
|
201
spec/controllers/comments_controller_spec.rb
Normal file
201
spec/controllers/comments_controller_spec.rb
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CommentsController, type: :controller do
|
||||||
|
let!(:user) { build(:user) }
|
||||||
|
let!(:subcreddit) { create(:subcreddit) }
|
||||||
|
let!(:tpost) { create(:post, subcreddit: subcreddit) }
|
||||||
|
let(:data) { { content: 'Here is some updated content for a comment' } }
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
allow_any_instance_of(ApplicationController)
|
||||||
|
.to receive(:current_user).and_return(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#show' do
|
||||||
|
let!(:comment) { create(:comment) }
|
||||||
|
before(:each) do
|
||||||
|
get :show,
|
||||||
|
subcreddit_id: comment.post.subcreddit,
|
||||||
|
post_id: comment.post,
|
||||||
|
id: comment
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should render :show' do
|
||||||
|
expect(response).to render_template(:show)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should assign correct Comment to @comment' do
|
||||||
|
expect(assigns(:comment)).to eq(comment)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#new' do
|
||||||
|
let(:comment) { build(:comment) }
|
||||||
|
before(:each) do
|
||||||
|
get :new,
|
||||||
|
subcreddit_id: comment.post.subcreddit,
|
||||||
|
post_id: comment.post
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should render :new' do
|
||||||
|
expect(response).to render_template(:new)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should assign new Comment to @comment' do
|
||||||
|
expect(assigns(:comment)).to be_a_new(Comment)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#create' do
|
||||||
|
context 'with valid data' do
|
||||||
|
it 'should create a comment' do
|
||||||
|
expect do
|
||||||
|
post :create,
|
||||||
|
subcreddit_id: subcreddit,
|
||||||
|
post_id: tpost,
|
||||||
|
comment: data
|
||||||
|
end.to change(Comment, :count).by(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should redirect to the parent post' do
|
||||||
|
expect(post :create,
|
||||||
|
subcreddit_id: subcreddit,
|
||||||
|
post_id: tpost,
|
||||||
|
comment: data
|
||||||
|
).to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
|
||||||
|
assigns(:post)))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should send a notice flash message' do
|
||||||
|
expect(post :create,
|
||||||
|
subcreddit_id: subcreddit,
|
||||||
|
post_id: tpost,
|
||||||
|
comment: data)
|
||||||
|
|
||||||
|
expect(flash[:notice]).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with invalid data' do
|
||||||
|
before(:each) { data['content'] = '' }
|
||||||
|
|
||||||
|
it 'should not create a new comment' do
|
||||||
|
expect do
|
||||||
|
post :create,
|
||||||
|
subcreddit_id: subcreddit,
|
||||||
|
post_id: tpost,
|
||||||
|
comment: data
|
||||||
|
end.to change(Comment, :count).by(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should render :new' do
|
||||||
|
expect(post :create,
|
||||||
|
subcreddit_id: subcreddit,
|
||||||
|
post_id: tpost,
|
||||||
|
comment: data
|
||||||
|
).to redirect_to(subcreddit_post_path(subcreddit, tpost))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#edit' do
|
||||||
|
let!(:comment) { create(:comment) }
|
||||||
|
before(:each) do
|
||||||
|
get :edit,
|
||||||
|
id: comment,
|
||||||
|
post_id: comment.post,
|
||||||
|
subcreddit_id: comment.post.subcreddit
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with valid comment' do
|
||||||
|
it 'should render :edit' do
|
||||||
|
expect(response).to render_template(:edit)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should assign correct Comment to @comment' do
|
||||||
|
expect(assigns(:comment)).to eq(comment)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#update' do
|
||||||
|
let!(:comment) { create(:comment) }
|
||||||
|
let(:data) { { content: 'Some edited comment content goes here' } }
|
||||||
|
|
||||||
|
context 'with valid data' do
|
||||||
|
before(:each) do
|
||||||
|
put :update,
|
||||||
|
id: comment,
|
||||||
|
post_id: comment.post,
|
||||||
|
subcreddit_id: comment.post.subcreddit,
|
||||||
|
comment: data
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should assign correct Comment to @comment' do
|
||||||
|
expect(assigns(:comment)).to eq(comment)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should update the comment' do
|
||||||
|
comment.reload
|
||||||
|
|
||||||
|
expect(comment.content).to eq(data[:content])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should redirect to the post' do
|
||||||
|
expect(response)
|
||||||
|
.to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
|
||||||
|
assigns(:post)))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should display a notice flash message' do
|
||||||
|
expect(flash[:notice]).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with invalid data' do
|
||||||
|
before(:each) { data[:content] = '' }
|
||||||
|
|
||||||
|
it 'should render :edit' do
|
||||||
|
put :update,
|
||||||
|
id: comment,
|
||||||
|
post_id: comment.post,
|
||||||
|
subcreddit_id: comment.post.subcreddit,
|
||||||
|
comment: data
|
||||||
|
|
||||||
|
expect(response).to render_template(:edit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#destroy' do
|
||||||
|
let!(:comment) { create(:comment) }
|
||||||
|
|
||||||
|
it 'should delete the post' do
|
||||||
|
delete :destroy,
|
||||||
|
id: comment,
|
||||||
|
post_id: comment.post,
|
||||||
|
subcreddit_id: comment.post.subcreddit
|
||||||
|
|
||||||
|
comment.reload
|
||||||
|
expect(comment.destroyed?).to be(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should redirect to the post' do
|
||||||
|
delete :destroy,
|
||||||
|
id: comment,
|
||||||
|
post_id: comment.post,
|
||||||
|
subcreddit_id: comment.post.subcreddit
|
||||||
|
|
||||||
|
expect(response).to redirect_to(subcreddit_post_path(assigns(:subcreddit),
|
||||||
|
assigns(:post)))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should send a notice flash message' do
|
||||||
|
delete :destroy,
|
||||||
|
id: comment,
|
||||||
|
post_id: comment.post,
|
||||||
|
subcreddit_id: comment.post.subcreddit
|
||||||
|
expect(flash[:notice]).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
spec/factories/comment_factory.rb
Normal file
7
spec/factories/comment_factory.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
FactoryGirl.define do
|
||||||
|
factory :comment do
|
||||||
|
user
|
||||||
|
post
|
||||||
|
content { Faker::Lorem.paragraph }
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,6 @@
|
||||||
FactoryGirl.define do
|
FactoryGirl.define do
|
||||||
factory :user do
|
factory :user do
|
||||||
username { Faker::Internet.user_name }
|
sequence(:username) { |n| Faker::Internet.user_name + "#{n}" }
|
||||||
password { Faker::Internet.password(8, 50) }
|
password { Faker::Internet.password(8, 50) }
|
||||||
email { Faker::Internet.email }
|
email { Faker::Internet.email }
|
||||||
end
|
end
|
||||||
|
|
30
spec/features/comments/edit_comment_spec.rb
Normal file
30
spec/features/comments/edit_comment_spec.rb
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'Edit Comment', type: :feature do
|
||||||
|
let!(:user) { create(:user) }
|
||||||
|
let!(:post) { create(:post) }
|
||||||
|
let!(:comment) { create(:comment, post: post, user: user) }
|
||||||
|
|
||||||
|
context 'when signed in' do
|
||||||
|
let(:content) { 'Some different data' }
|
||||||
|
before(:each) { signin(user: user) }
|
||||||
|
|
||||||
|
context 'with valid data' do
|
||||||
|
before(:each) do
|
||||||
|
visit edit_subcreddit_post_comment_path(post.subcreddit, post, comment)
|
||||||
|
|
||||||
|
fill_in :comment_content, with: content
|
||||||
|
|
||||||
|
click_button 'Update Comment'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should notify that the comment was edited' do
|
||||||
|
expect(page).to have_content('updated')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should update the comment' do
|
||||||
|
expect(page).to have_content(content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
57
spec/features/comments/new_comment_spec.rb
Normal file
57
spec/features/comments/new_comment_spec.rb
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'New Comment', type: :feature do
|
||||||
|
let!(:post) { create(:post) }
|
||||||
|
let(:comment) { build(:comment) }
|
||||||
|
|
||||||
|
context 'when signed in' do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
|
||||||
|
before(:each) { signin(user: user) }
|
||||||
|
|
||||||
|
context 'with valid data' do
|
||||||
|
before(:each) do
|
||||||
|
visit subcreddit_post_path(post.subcreddit, post)
|
||||||
|
|
||||||
|
fill_in :comment_content, with: comment.content
|
||||||
|
|
||||||
|
click_button 'Create Comment'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should notify that a new content was created' do
|
||||||
|
expect(page).to have_content('saved')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should display the new comment' do
|
||||||
|
expect(page).to have_content(comment.content)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when nesting comment' do
|
||||||
|
let!(:comment) { create(:comment, post: post) }
|
||||||
|
|
||||||
|
it 'should display a nested comment' do
|
||||||
|
visit subcreddit_post_comment_path(post.subcreddit, post, comment)
|
||||||
|
|
||||||
|
fill_in :comment_content, with: comment.content
|
||||||
|
click_button 'Create Comment'
|
||||||
|
|
||||||
|
expect(page).to have_css('div.nested_comments')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with invalid data' do
|
||||||
|
before(:each) do
|
||||||
|
visit subcreddit_post_path(post.subcreddit, post)
|
||||||
|
|
||||||
|
fill_in :comment_content, with: ''
|
||||||
|
|
||||||
|
click_button 'Create Comment'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should display errors' do
|
||||||
|
expect(page).to have_content('could not')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -24,8 +24,9 @@ describe 'Edit Post', type: :feature do
|
||||||
expect(page).to have_content('updated')
|
expect(page).to have_content('updated')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should show the post' do
|
it 'should show the updated post' do
|
||||||
expect(page).to have_content(new_post.title)
|
expect(page).to have_content(new_post.title)
|
||||||
|
expect(page).to have_content(new_post.content)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe 'List Posts', type: :feature do
|
||||||
|
|
||||||
posts.each do |post|
|
posts.each do |post|
|
||||||
expect(page)
|
expect(page)
|
||||||
.to have_link(post.title, subcreddit_post_path(post, post.subcreddit))
|
.to have_link(post.title, subcreddit_post_path(post.subcreddit, post))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
7
spec/helpers/comments_helper_spec.rb
Normal file
7
spec/helpers/comments_helper_spec.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CommentsHelper do
|
||||||
|
describe '#nested_comments' do
|
||||||
|
it 'renders the comment partial'
|
||||||
|
end
|
||||||
|
end
|
63
spec/models/comment_spec.rb
Normal file
63
spec/models/comment_spec.rb
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Comment, type: :model do
|
||||||
|
let(:comment) { build(:comment) }
|
||||||
|
|
||||||
|
it { should belong_to(:user) }
|
||||||
|
it { should belong_to(:post).counter_cache(true) }
|
||||||
|
|
||||||
|
it { should delegate_method(:username).to(:user).with_prefix }
|
||||||
|
|
||||||
|
context 'with valid data' do
|
||||||
|
it 'should be valid' do
|
||||||
|
expect(comment).to be_valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with invalid data' do
|
||||||
|
it 'should not be valid with blank content' do
|
||||||
|
comment.content = ''
|
||||||
|
|
||||||
|
expect(comment).to be_invalid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when comment is deleted' do
|
||||||
|
before(:each) { comment.deleted_at = Time.now }
|
||||||
|
|
||||||
|
context '#destroyed?' do
|
||||||
|
it 'should respond with true' do
|
||||||
|
expect(comment.destroyed?).to be(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#content' do
|
||||||
|
it 'should return [deleted]' do
|
||||||
|
expect(comment.content).to eq('[deleted]')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when comment is not deleted' do
|
||||||
|
context '#destroyed?' do
|
||||||
|
it 'should respond with false' do
|
||||||
|
expect(comment.destroyed?).to be(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#content' do
|
||||||
|
it 'should return comment content' do
|
||||||
|
expect(comment.content).to eq(comment.content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#destroy' do
|
||||||
|
it 'should set the deleted_at time appropriately' do
|
||||||
|
Timecop.freeze do
|
||||||
|
comment.destroy
|
||||||
|
expect(comment.deleted_at).to eq(Time.now)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,9 +5,20 @@ describe Post, type: :model do
|
||||||
|
|
||||||
it { should belong_to(:user) }
|
it { should belong_to(:user) }
|
||||||
it { should belong_to(:subcreddit) }
|
it { should belong_to(:subcreddit) }
|
||||||
|
it { should have_many(:comments) }
|
||||||
|
|
||||||
it { should delegate_method(:username).to(:user).with_prefix }
|
it { should delegate_method(:username).to(:user).with_prefix }
|
||||||
|
|
||||||
|
context 'when adding a comment' do
|
||||||
|
let(:post) { create(:post) }
|
||||||
|
|
||||||
|
it 'should update the cache_counter for comments' do
|
||||||
|
expect do
|
||||||
|
create(:comment, post: post)
|
||||||
|
end.to change { post.comments_count }.by(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with valid data' do
|
context 'with valid data' do
|
||||||
it 'should be valid' do
|
it 'should be valid' do
|
||||||
expect(post).to be_valid
|
expect(post).to be_valid
|
||||||
|
@ -53,4 +64,24 @@ describe Post, type: :model do
|
||||||
expect(post.to_param).to eq("#{post.id}-#{post.title.parameterize}")
|
expect(post.to_param).to eq("#{post.id}-#{post.title.parameterize}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context '#comments?' do
|
||||||
|
let(:post) { create(:post) }
|
||||||
|
|
||||||
|
context 'with comments' do
|
||||||
|
before(:each) do
|
||||||
|
create(:comment, post: post)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should respond with true' do
|
||||||
|
expect(post.comments?).to be(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without comments' do
|
||||||
|
it 'should respond with false' do
|
||||||
|
expect(post.comments?).to be(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue