diff --git a/app/assets/stylesheets/likes.scss b/app/assets/stylesheets/likes.scss new file mode 100644 index 00000000..1f08d329 --- /dev/null +++ b/app/assets/stylesheets/likes.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the likes controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb new file mode 100644 index 00000000..29dd6803 --- /dev/null +++ b/app/controllers/likes_controller.rb @@ -0,0 +1,33 @@ +class LikesController < ApplicationController + before_action :authenticate_user! + + def create + like = Like.new(like_params) + + if like.save + render json: like, status: :created + else + render json: { + error: I18n.t('errors.likes.create', message: like.errors.full_messages) + }, status: :unprocessable_entity + end + end + + def destroy + like = Like.where(like_params) + + if like.destroy + render json: {}, status: :no_content + else + render json: { + error: I18n.t('errors.likes.destroy', message: like.errors.full_messages) + }, status: :unprocessable_entity + end + end + + private + + def like_params + params.permit(:post_id).merge(user_id: current_user.id) + end +end diff --git a/app/helpers/likes_helper.rb b/app/helpers/likes_helper.rb new file mode 100644 index 00000000..a78a7596 --- /dev/null +++ b/app/helpers/likes_helper.rb @@ -0,0 +1,2 @@ +module LikesHelper +end diff --git a/app/models/like.rb b/app/models/like.rb new file mode 100644 index 00000000..8c97e474 --- /dev/null +++ b/app/models/like.rb @@ -0,0 +1,6 @@ +class Like < ApplicationRecord + belongs_to :user + belongs_to :post + + validates :user_id, uniqueness: { scope: :post_id } +end diff --git a/app/models/post.rb b/app/models/post.rb index 8f61f1cc..6a887450 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -2,6 +2,7 @@ class Post < ApplicationRecord belongs_to :board belongs_to :user belongs_to :post_status, optional: true + has_many :likes, dependent: :destroy has_many :comments, dependent: :destroy validates :title, presence: true, length: { in: 4..64 } diff --git a/app/models/user.rb b/app/models/user.rb index 1b6c7406..51633117 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,6 +4,7 @@ class User < ApplicationRecord :confirmable has_many :posts, dependent: :destroy + has_many :likes, dependent: :destroy has_many :comments, dependent: :destroy enum role: [:user, :moderator, :admin] diff --git a/config/locales/en.yml b/config/locales/en.yml index 16d67d31..19d63e90 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -4,5 +4,7 @@ en: post: create: 'Post create error: %{message}' update: 'Post update error: %{message}' + like: + create: 'Like create error: %{message}' comment: create: 'Comment create error: %{message}' \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 8865bdba..bed5ae49 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,9 +14,10 @@ Rails.application.routes.draw do devise_for :users - resources :boards, only: [:show] resources :posts, only: [:index, :create, :show, :update] do + resource :likes, only: [:create, :destroy] resources :comments, only: [:index, :create] end + resources :boards, only: [:show] resources :post_statuses, only: [:index] end diff --git a/db/migrate/20190927094233_create_likes.rb b/db/migrate/20190927094233_create_likes.rb new file mode 100644 index 00000000..8330e650 --- /dev/null +++ b/db/migrate/20190927094233_create_likes.rb @@ -0,0 +1,12 @@ +class CreateLikes < ActiveRecord::Migration[6.0] + def change + create_table :likes do |t| + t.references :user, null: false, foreign_key: true + t.references :post, null: false, foreign_key: true + + t.timestamps + end + + add_index :likes, [:user_id, :post_id], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 2a5f3068..bde2c8ff 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_09_18_151626) do +ActiveRecord::Schema.define(version: 2019_09_27_094233) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -36,6 +36,16 @@ ActiveRecord::Schema.define(version: 2019_09_18_151626) do t.index ["user_id"], name: "index_comments_on_user_id" end + create_table "likes", force: :cascade do |t| + t.bigint "user_id", null: false + t.bigint "post_id", null: false + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["post_id"], name: "index_likes_on_post_id" + t.index ["user_id", "post_id"], name: "index_likes_on_user_id_and_post_id", unique: true + t.index ["user_id"], name: "index_likes_on_user_id" + end + create_table "post_statuses", force: :cascade do |t| t.string "name", null: false t.string "color", null: false @@ -81,6 +91,8 @@ ActiveRecord::Schema.define(version: 2019_09_18_151626) do add_foreign_key "comments", "comments", column: "parent_id" add_foreign_key "comments", "posts" add_foreign_key "comments", "users" + add_foreign_key "likes", "posts" + add_foreign_key "likes", "users" add_foreign_key "posts", "boards" add_foreign_key "posts", "post_statuses" add_foreign_key "posts", "users" diff --git a/spec/factories/likes.rb b/spec/factories/likes.rb new file mode 100644 index 00000000..cde39142 --- /dev/null +++ b/spec/factories/likes.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :like do + user + post + end +end diff --git a/spec/models/like_spec.rb b/spec/models/like_spec.rb new file mode 100644 index 00000000..7be6ff04 --- /dev/null +++ b/spec/models/like_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' + +RSpec.describe Like, type: :model do + let(:like) { FactoryBot.build(:like) } + + it 'is valid' do + expect(like).to be_valid + end + + it 'must have a user_id' do + like.user = nil + expect(like).to be_invalid + end + + it 'must have a post_id' do + like.post = nil + expect(like).to be_invalid + end +end diff --git a/spec/routing/likes_routing_spec.rb b/spec/routing/likes_routing_spec.rb new file mode 100644 index 00000000..eeaab3b7 --- /dev/null +++ b/spec/routing/likes_routing_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +RSpec.describe 'likes routing', :aggregate_failures, type: :routing do + it 'routes likes' do + expect(post: '/posts/1/likes').to route_to( + controller: 'likes', action: 'create', post_id: "1" + ) + expect(delete: '/posts/1/likes').to route_to( + controller: 'likes', action: 'destroy', post_id: "1" + ) + + expect(get: '/posts/1/likes').not_to be_routable + expect(get: '/posts/1/likes/1').not_to be_routable + expect(get: '/posts/1/likes/new').not_to be_routable + expect(get: '/posts/1/likes/1/edit').not_to be_routable + expect(patch: '/posts/1/likes/1').not_to be_routable + end +end \ No newline at end of file