# Terminal rails g scaffold comments user:belongs_to rails g model emote user:belongs_to comment:belongs_to emoji rails action_text:install rails db:migrate





# models/user.rb class User < ApplicationRecord # Include default devise modules. Others available are:

# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable

devise :database_authenticatable, :registerable,

:recoverable, :rememberable, :validatable



has_many :comments, dependent: :destroy

has_many :emotes, dependent: :destroy

# has_many :emoted_comments, through: :emotes, class_name: "Comment" end





# models/emote.rb class Emote < ApplicationRecord belongs_to :user belongs_to :comment end





# models/emoji.rb class Emoji # [{key: emoji.png, text: Emoji}, {}]

# Emoji.all def self.all self.new.all end def all list_of_emojis end private def list_of_emojis Dir.children(emojis_path).map { |file| emoji_hash(file) } end def emojis_path Rails.root.join('app', 'assets', 'images', 'emojis') end def emoji_hash(file) { key: file, text: humanized(file) } end def humanized(file) basename(file).humanize end def basename(file) File.basename(file, File.extname(file)) end end





# models/comment.rb class Comment < ApplicationRecord belongs_to :user has_rich_text :content has_many :emotes, dependent: :destroy # has_many :emoters, through: :emotes, class_name: "User" def emotes_size(key) self.emotes.select { |e| e.emoji == key }.size end end





# views/comments/_form.html.erb <%= form_with(model: comment, local: true) do |form| %> <div class="field"> <%= form.rich_text_area :content %> </div> <div class="actions"> <%= form.submit %> </div> <% end %>





# views/comments/index.html.erb <% @comments.each do |comment| %> <div class='comment'> <%= comment.content %> <em class='meta'> <%= comment.user.name %> | <%= comment.created_at %> | <%= link_to 'Destroy', comment, method: :delete, data: { confirm: 'Are you sure?' } %> </em> <div class='emojis'> <% Emoji.all.each do |emoji| %> <% size = comment.emotes_size(emoji[:key]) %> <%= link_to comment_emote_path(comment, emote: emoji[:key]), class: "emoji #{size.zero? ? 'emoji-gray' : ''}" do %> <%= image_tag File.join('emojis', emoji[:key]), size: '25x25', title: emoji[:text] %> <%= content_tag :span, size, class: 'count' %> <% end %> <% end %> </div> </div> <% end %> <%= render 'form', comment: Comment.new %>





# controllers/comments_controller.rb class CommentsController < ApplicationController before_action :set_comment, only: :destroy def index @comments = Comment.includes(:emotes).all end def create @comment = current_user.comments.new(comment_params) if @comment.save redirect_to comments_path, notice: 'Comment was successfully created.' else render :new end end def destroy @comment.destroy redirect_to comments_url, notice: 'Comment was successfully destroyed.' end private def set_comment @comment = current_user.comments.find(params[:id]) end def comment_params params.require(:comment).permit(:content) end end





# controllers/emotes_controller.rb class EmotesController < ApplicationController def show comment = Comment.find_by(id: params[:comment_id]) emote = current_user.emotes.find_or_initialize_by(comment: comment, emoji: params[:emote]) if emote.new_record? emote.save else emote.destroy end redirect_to root_path end end





# routes.rb resources :comments do resource :emote, only: :show end





# db/migrate/20200202022753_create_emotes.rb class CreateEmotes < ActiveRecord::Migration[6.0] def change create_table :emotes do |t| t.belongs_to :user, null: false, foreign_key: true t.belongs_to :comment, null: false, foreign_key: true t.string :emoji, null: false t.timestamps end end end





# comments.scss .comment { border: 1px dashed gray; margin-bottom: 10px; padding: 10px; } .comment .meta, .comment .meta a { color: gray; } .emojis { margin-top: 10px; } .emoji img { padding: 5px; } .emoji.emoji-gray img { filter: grayscale(100%); } .emoji.emoji-gray img:hover { filter: grayscale(0%); } .emoji { position: relative; } .emoji .count { position: absolute; top: 10; left: 0; padding: 3px; background-color: #269ba5; text-decoration: none; color: #ffffff; border-radius: 20px; font-size: 10px; }



