From 835af696703484208882a70cc5dd47c5838ecf58 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Thu, 12 Oct 2023 17:10:34 -0400 Subject: Added blog post commenting --- app/assets/stylesheets/main/entries.scss | 62 ++++++++++++++++++++++++++++++++ app/assets/stylesheets/main/layout.scss | 4 +++ app/controllers/comments_controller.rb | 59 ++++++++++++++++++++++++++++++ app/helpers/application_helper.rb | 10 ++++-- app/helpers/comments_helper.rb | 5 +++ app/models/blog.rb | 2 ++ app/models/comment.rb | 36 +++++++++++++++++++ app/views/blogs/_blog.html.haml | 2 +- app/views/blogs/show.html.haml | 5 +-- app/views/comments/_comment.html.haml | 13 +++++++ app/views/comments/_form.html.haml | 23 ++++++++++++ app/views/comments/_layout.html.haml | 6 ++++ 12 files changed, 220 insertions(+), 7 deletions(-) create mode 100644 app/controllers/comments_controller.rb create mode 100644 app/helpers/comments_helper.rb create mode 100644 app/models/comment.rb create mode 100644 app/views/comments/_comment.html.haml create mode 100644 app/views/comments/_form.html.haml create mode 100644 app/views/comments/_layout.html.haml (limited to 'app') diff --git a/app/assets/stylesheets/main/entries.scss b/app/assets/stylesheets/main/entries.scss index 56cd221..5fbd4ef 100644 --- a/app/assets/stylesheets/main/entries.scss +++ b/app/assets/stylesheets/main/entries.scss @@ -219,3 +219,65 @@ margin-left: 1.5em; } } + +.blog-comment { + margin: 0 1em; + + .comment-avatar { + float: right; + margin-top: 1em; + } +} + +#comment-form { + fieldset { + border: 0; + + &#comment-body-field { + label { + display: none; + } + + textarea { + margin-top: 1em; + width: 99%; + height: 6em; + resize: none; + } + } + + &#comment-other-fields { + display: table; + padding: 1em; + width: 75%; + margin: 0 auto; + + .comment-field { + display: table-row; + + .comment-field-label { + text-align: right; + display: table-cell; + padding-right: 1em; + padding-bottom: 1em; + width: 50%; + + label:after { + content: ":"; + } + } + + .field_with_errors { + label { + color: red; + } + } + + .comment-field-input { + display: table-cell; + width: 50%; + } + } + } + } +} diff --git a/app/assets/stylesheets/main/layout.scss b/app/assets/stylesheets/main/layout.scss index 278113a..9283f36 100644 --- a/app/assets/stylesheets/main/layout.scss +++ b/app/assets/stylesheets/main/layout.scss @@ -199,3 +199,7 @@ blockquote.bubble.bottom::after { text-decoration: underline; } } + +.clear { + clear: both; +} diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb new file mode 100644 index 0000000..60c8f6a --- /dev/null +++ b/app/controllers/comments_controller.rb @@ -0,0 +1,59 @@ +class CommentsController < ApplicationController + def create + @blog = Blog.find_by_slug(params[:slug]) + + raise ActiveRecord::RecordNotFound unless @blog + raise ActiveRecord::RecordNotFound unless @blog.published + + @comment = @blog.comments.new(comment_params) + + unless @comment.valid? + flash.alert = "Error posting comment." + render "blogs/show" + return + end + + akismet_vars = %w{ HTTP_ACCEPT HTTP_ACCEPT_ENCODING } + akismet_params = { + type: "comment", + text: @comment.body, + created_at: DateTime.now, + author: @comment.username, + author_email: @comment.email, + author_url: @comment.website, + post_url: url_for(@comment.blog), + post_modified_at: @comment.blog.updated_at, + referrer: request.referrer, + env: request.env.slice(*akismet_vars) + } + + is_spam, is_blatant = Akismet.check(request.ip, request.user_agent, akismet_params) + + if is_blatant + # I am lying. + flash.notice = "Comment submitted successfully! It will need to be moderated before it shows up on the blog." + else + if is_spam + @comment.status = :pending + flash_message = "Comment submitted successfully! It will need to be moderated before it shows up on the blog." + else + @comment.status = :published + flash_message = "Comment posted successfully!" + end + + if @comment.save + flash.notice = flash_message + else + flash.alert = "Error posting comment." + end + end + + redirect_to @comment.blog + end + + private + + def comment_params + params.require(:comment).permit(:username, :email, :website, :body) + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 861dd11..14d56cf 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -19,9 +19,15 @@ module ApplicationHelper link_to title, {:sort => col, :dir => direction}, {:class => css_class} end - def markdown(text) + def markdown(text, params = {}) options = { fenced_code_blocks: true, highlight: true } - Redcarpet::Markdown.new(HTML.new(), options).render(text).html_safe + + html_options = {} + if params[:restricted] + html_options[:filter_html] = true + end + + Redcarpet::Markdown.new(HTML.new(html_options), options).render(text).html_safe end end diff --git a/app/helpers/comments_helper.rb b/app/helpers/comments_helper.rb new file mode 100644 index 0000000..5939adc --- /dev/null +++ b/app/helpers/comments_helper.rb @@ -0,0 +1,5 @@ +module CommentsHelper + def show_comments(blog) + render "comments/layout", blog: blog + end +end diff --git a/app/models/blog.rb b/app/models/blog.rb index 415167c..b677e2b 100644 --- a/app/models/blog.rb +++ b/app/models/blog.rb @@ -3,6 +3,8 @@ class Blog < ApplicationRecord acts_as_taggable + has_many :comments + validates :title, presence: true validates :body, presence: true, if: :published validates :slug, presence: true, format: /\A[-a-z0-9]+\z/, if: :published diff --git a/app/models/comment.rb b/app/models/comment.rb new file mode 100644 index 0000000..9697100 --- /dev/null +++ b/app/models/comment.rb @@ -0,0 +1,36 @@ +class Comment < ApplicationRecord + extend Enumerize + + belongs_to :blog + + validates :body, presence: true + validates :username, presence: true + validates :email, presence: true, format: URI::MailTo::EMAIL_REGEXP + + scope :published_and_ordered, -> { where(status: :published).order(published_at: :asc) } + + enumerize :status, + in: [:published, :pending, :rejected], + default: :published, + predicates: true + + before_save :set_published_at + + def gravatar_url + hash = Digest::MD5.hexdigest(email) + "https://www.gravatar.com/avatar/#{hash}?size=40&default=identicon&rating=g" + end + + private + + def set_published_at + if self.published? + if self.published_at.blank? + self.published_at = DateTime.now + end + else + self.published_at = nil + end + end + +end diff --git a/app/views/blogs/_blog.html.haml b/app/views/blogs/_blog.html.haml index 26657e7..8972c2e 100644 --- a/app/views/blogs/_blog.html.haml +++ b/app/views/blogs/_blog.html.haml @@ -15,4 +15,4 @@ %cite.bubble %strong Hatkirby on - = blog.published_at.strftime("%m-%d-%Y") + = blog.published_at.strftime("%B #{blog.published_at.day.ordinalize}, %Y at %-I:%M:%S%P") diff --git a/app/views/blogs/show.html.haml b/app/views/blogs/show.html.haml index 9bff12b..0c549ac 100644 --- a/app/views/blogs/show.html.haml +++ b/app/views/blogs/show.html.haml @@ -1,7 +1,4 @@ - title @blog.title .breadcrumb= link_to "← Back to home page", root_path = render @blog, short: false -%footer#blog-footer - This entry was posted on - = succeed "." do - %time= @blog.published_at.strftime("%B #{@blog.published_at.day.ordinalize}, %Y at %-I:%M:%S%P") += show_comments(@blog) diff --git a/app/views/comments/_comment.html.haml b/app/views/comments/_comment.html.haml new file mode 100644 index 0000000..3e10759 --- /dev/null +++ b/app/views/comments/_comment.html.haml @@ -0,0 +1,13 @@ +.blog-comment + %blockquote.bubble.rounded.bottom + = image_tag comment.gravatar_url, class: "comment-avatar" + = markdown(comment.body, { restricted: true }) + .clear + %cite.bubble + %strong + - if comment.website.empty? + = comment.username + - else + = link_to comment.username, comment.website + on + = comment.published_at.strftime("%B #{comment.published_at.day.ordinalize}, %Y at %-I:%M:%S%P") diff --git a/app/views/comments/_form.html.haml b/app/views/comments/_form.html.haml new file mode 100644 index 0000000..f6df807 --- /dev/null +++ b/app/views/comments/_form.html.haml @@ -0,0 +1,23 @@ += form_for @comment || blog.comments.new, html: { id: "comment-form" } do |f| + %fieldset#comment-body-field + %blockquote.bubble.rounded.bottom + = f.label :body + = f.text_area :body + %cite.bubble Feel free to post a comment! You may use Markdown. + - if @comment and @comment.errors.any? + %ul#form-errors + - @comment.errors.full_messages.each do |msg| + %li= msg + %fieldset#comment-other-fields + .comment-name-field.comment-field + .comment-field-label= f.label :username + .comment-field-input= f.text_field :username + .comment-email-field.comment-field + .comment-field-label= f.label :email + .comment-field-input= f.text_field :email, type: :email + .comment-website-field.comment-field + .comment-field-label= f.label :website, "Website (Optional)" + .comment-field-input= f.text_field :website, type: :url + .comment-submit-button.comment-field + .comment-field-label + .comment-field-input= f.submit "Post" diff --git a/app/views/comments/_layout.html.haml b/app/views/comments/_layout.html.haml new file mode 100644 index 0000000..9acf6b0 --- /dev/null +++ b/app/views/comments/_layout.html.haml @@ -0,0 +1,6 @@ +%a{ name: "comments" } +#comments + %h2 Comments + - blog.comments.published_and_ordered.each do |comment| + = render comment + = render "comments/form", blog: blog -- cgit 1.4.1