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 'friendly_id', '~> 5.1.0'
|
||||
gem 'ancestry'
|
||||
|
||||
gem 'bcrypt'
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ GEM
|
|||
ice_nine (~> 0.11.0)
|
||||
memoizable (~> 0.4.0)
|
||||
addressable (2.3.8)
|
||||
ancestry (2.1.0)
|
||||
activerecord (>= 3.0.0)
|
||||
arel (6.0.0)
|
||||
arrayfields (4.9.2)
|
||||
ast (2.0.0)
|
||||
|
@ -365,6 +367,7 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
ancestry
|
||||
bcrypt
|
||||
better_errors
|
||||
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 {
|
||||
.logo {
|
||||
margin-top: 3px;
|
||||
|
@ -49,32 +53,7 @@ $navbar-default-link-hover-color: #369;
|
|||
}
|
||||
}
|
||||
|
||||
.posts {
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
.contents {
|
||||
ul {
|
||||
list-style: none;
|
||||
list-style-type: none;
|
||||
|
@ -90,6 +69,38 @@ $navbar-default-link-hover-color: #369;
|
|||
li:first-child {
|
||||
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 {
|
||||
|
@ -99,3 +110,15 @@ $navbar-default-link-hover-color: #369;
|
|||
.main {
|
||||
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
|
||||
|
||||
def show
|
||||
@comments = @post.comments.arrange(order: :created_at)
|
||||
end
|
||||
|
||||
def new
|
||||
|
|
|
@ -12,5 +12,5 @@ module ApplicationHelper
|
|||
'notice' => 'alert-info',
|
||||
'success' => 'alert-success'
|
||||
}
|
||||
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 :subcreddit
|
||||
|
||||
has_many :comments
|
||||
|
||||
delegate :username, to: :user, prefix: true
|
||||
|
||||
validates :title,
|
||||
|
@ -12,6 +14,16 @@ class Post < ActiveRecord::Base
|
|||
length: { maximum: 15000 }
|
||||
|
||||
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}"
|
||||
end
|
||||
|
||||
def comments?
|
||||
self.comments_count != 0
|
||||
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
|
||||
body
|
||||
== render 'navbar'
|
||||
.container
|
||||
.container-fluid
|
||||
== render 'flash_messages'
|
||||
.main.container-fluid
|
||||
.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
|
||||
.post.show
|
||||
p.title= link_to @post.title, [@subcreddit, @post]
|
||||
p.details= "submitted #{distance_of_time_in_words @post.created_at, Time.now} ago by #{@post.user_username}"
|
||||
ul.links.list-inline
|
||||
li= link_to 'XXX comments', ''
|
||||
li= link_to 'source', ''
|
||||
li= link_to 'share', ''
|
||||
li= link_to 'save', ''
|
||||
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
|
||||
== render 'post', post: @post
|
||||
- if @post.comments?
|
||||
.title= "all #{@post.comments_count} comments"
|
||||
- else
|
||||
.title= "no comments (yet)"
|
||||
= "Commenting as: #{current_user.username}"
|
||||
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: nil
|
||||
.comments.contents
|
||||
== nested_comments(@comments)
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
- if @subcreddit.closed?
|
||||
= "Board has been closed"
|
||||
- else
|
||||
.posts
|
||||
.posts.contents
|
||||
ul
|
||||
- @subcreddit.posts.order('created_at DESC').each_with_index do |post, rank|
|
||||
li
|
||||
.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}"
|
||||
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', ''
|
||||
|
|
|
@ -38,4 +38,11 @@ Rails.application.configure do
|
|||
|
||||
# Raises error for missing translations
|
||||
# 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
|
||||
|
|
|
@ -4,7 +4,9 @@ Rails.application.routes.draw do
|
|||
get 'signout', to: 'user_sessions#destroy', as: :signout
|
||||
|
||||
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
|
||||
|
||||
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
|
17
db/schema.rb
17
db/schema.rb
|
@ -11,7 +11,21 @@
|
|||
#
|
||||
# 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|
|
||||
t.string "slug", null: false
|
||||
|
@ -34,6 +48,7 @@ ActiveRecord::Schema.define(version: 20150716050055) do
|
|||
t.text "content"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.integer "comments_count", default: 0
|
||||
end
|
||||
|
||||
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
|
||||
factory :user do
|
||||
username { Faker::Internet.user_name }
|
||||
sequence(:username) { |n| Faker::Internet.user_name + "#{n}" }
|
||||
password { Faker::Internet.password(8, 50) }
|
||||
email { Faker::Internet.email }
|
||||
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')
|
||||
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.content)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ describe 'List Posts', type: :feature do
|
|||
|
||||
posts.each do |post|
|
||||
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
|
||||
|
|
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(:subcreddit) }
|
||||
it { should have_many(:comments) }
|
||||
|
||||
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
|
||||
it 'should be valid' do
|
||||
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}")
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue