Skip to content

Commit

Permalink
Merge pull request #81 from iaebots/polymorphic-relations
Browse files Browse the repository at this point in the history
Polymorphic relations
  • Loading branch information
Utzig26 authored Jul 10, 2021
2 parents 0456fdb + 7500bea commit 85e3f13
Show file tree
Hide file tree
Showing 16 changed files with 163 additions and 111 deletions.
50 changes: 25 additions & 25 deletions app/controllers/api/v1/comments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
module Api
module V1
class CommentsController < ApplicationController
before_action :find_post, only: :create
before_action :new_comment, only: :create
before_action :find_comment, only: %i[show destroy]
before_action :find_bot, only: :destroy
before_action :find_commentable, only: :create
before_action :create_comment, only: :create
before_action :find_comment, only: :destroy
before_action :find_commenter, only: :destroy
before_action :require_authorization!, only: :destroy

# POST /:username/posts/:post_id/resource
# POST /api/v1/:username/posts/:post_id/comment
def create
if @comment.save
render json: { status: 'success', message: 'Comment created', data: @comment }, status: :created
Expand All @@ -18,7 +18,7 @@ def create
end
end

# DELETE /:username/posts/:post_id/resource/:id
# DELETE /api/v1/:username/posts/:post_id/comment/:id
def destroy
if @comment.destroy
render json: { status: 'success', message: 'Comment deleted', data: @comment }, status: :accepted
Expand All @@ -27,44 +27,44 @@ def destroy
end
end

# GET /:username/posts/:post_id/resource/:id
def show
render json: { status: 'success', message: 'Comment loaded', data: @comment }, status: :ok
end

private

# Find post by post_id
def find_post
@post = Post.find(params[:post_id])
# Find commentable. If :post_id exists, commentable is a post
def find_commentable
@commentable = Post.find(params[:post_id]) if params[:post_id]
end

# Define what params are permitted
def comment_params
params.permit(:body)
params.require(:comment).permit(:id, :body, :post_id)
end

# Find comment by id
def find_comment
@comment = Comment.find(params[:id])
end

# Define new comment content
def new_comment
@comment = Comment.new(comment_params)
@comment.bot = @current_bot
@comment.post = @post
# Create new comment with body passed as param
# Bot as commenter
# Post as commentable
def create_comment
@comment = @commentable.comments.create(commenter_id: @current_bot.id, commenter_type: 'Bot',
body: params[:comment][:body])
end

# Find comment's bot
def find_bot
@bot = @comment.bot
# Find comment's commenter
def find_commenter
@commenter = @comment.commenter
end

# Verify if bot owns comment (is authorized)
# Return if current_bot is equal to commenter (comment's owner)
#
# Render unauthorized otherwise
def require_authorization!
return if @current_bot == @commenter

render json: { status: 'error', message: 'Resource does not belong to you' },
status: :unauthorized unless @current_bot == @bot
status: :unauthorized
end
end
end
Expand Down
36 changes: 24 additions & 12 deletions app/controllers/api/v1/likes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,55 @@
module Api
module V1
class LikesController < ApplicationController
before_action :find_post
before_action :find_likeable
before_action :find_like, only: :destroy

# POST /:username/posts/:post_id/like
# POST /:username/posts/:post_id/like if like belongs to a post
#
# POST /:username/posts/:post_id/comments/:comment_id/like if like belongs to a comment
def create
if already_liked?
render json: { status: 'error', message: 'Already liked', data: nil }, status: :unprocessable_entity
else
@post.likes.create(bot_id: @current_bot.id)
render json: { status: 'success', message: 'Post liked', data: @post }, status: :created if @post.save
@likeable.likes.create(liker_id: @current_bot.id, liker_type: 'Bot')
render json: { status: 'success', message: "#{@likeable.class.name} liked", data: @likeable }, status: :created if @likeable.save
end
end

# DELETE /:username/posts/:post_id/like
# DELETE /:username/posts/:post_id/like if like belongs to a post
#
# DELETE /:username/posts/:post_id/comments/:comment_id/like if like belongs to a comment
def destroy
if already_liked?
render json: { status: 'success', message: 'Post unliked', data: @post }, status: :accepted if @like.destroy
if @like.destroy
render json: { status: 'success', message: "#{@likeable.class.name} unliked", data: @likeable }, status: :accepted
end
else
render json: { status: 'error', message: 'Cannot unlike', data: nil }, status: :unprocessable_entity
end
end

private

# Find post by post_id
def find_post
@post = Post.find(params[:post_id])
# Find likeable
# Likeable is a Post if post_id is present and comment_id is not present
# This happens because comments belong to posts, therefore post_id is always going to be present
def find_likeable
if params[:post_id] && !params[:comment_id]
@likeable = Post.find(params[:post_id])
elsif params[:comment_id]
@likeable = Comment.find(params[:comment_id])
end
end

# Find current bot's like by current_bot.id
def find_like
@like = @post.likes.find_by(bot_id: @current_bot.id)
@like = @likeable.likes.where(liker_id: @current_bot.id, liker_type: 'Bot').first
end

# Check if current bot already liked post
# Check if current bot has already liked current resource
def already_liked?
Like.where(bot_id: @current_bot.id, post_id: params[:post_id]).exists?
@likeable.likes.where(liker_id: @current_bot.id, liker_type: 'Bot').exists?
end
end
end
Expand Down
10 changes: 5 additions & 5 deletions app/controllers/api/v1/posts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def destroy

# Define permitted params
def post_params
params.permit(:body, :media)
params.permit(:body, :media, :username)
end

# Define new post content
Expand All @@ -47,7 +47,7 @@ def new_post
# Set post and its content (comment and likes)
def set_post
@post = Post.find(params[:id])
@comments = Comment.where(post_id: @post.id)
@comments = @post.comments.where(commentable_id: @post.id, commentable_type: 'Post').first
@likes = @post.likes.count
end

Expand All @@ -61,9 +61,9 @@ def set_response
end

def require_authorization!
unless @current_bot == @post.bot
render json: { status: 'error', message: 'Resource does not belong to you' }, status: :unauthorized
end
return if @current_bot == @post.bot

render json: { status: 'error', message: 'Resource does not belong to you' }, status: :unauthorized
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/models/bot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

class Bot < ApplicationRecord
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
has_many :likes, dependent: :destroy
has_many :comments, as: :commenter, dependent: :destroy
has_many :likes, as: :liker, dependent: :destroy

mount_uploader :avatar, AvatarUploader

Expand Down
6 changes: 4 additions & 2 deletions app/models/comment.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# frozen_string_literal: true

class Comment < ApplicationRecord
belongs_to :post
belongs_to :bot
belongs_to :commentable, polymorphic: true
belongs_to :commenter, polymorphic: true

has_many :likes, as: :likeable, dependent: :destroy

validates_presence_of :body
validates_length_of :body, maximum: 512 # validates length of a comment
Expand Down
4 changes: 2 additions & 2 deletions app/models/like.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class Like < ApplicationRecord
belongs_to :post
belongs_to :bot, optional: true
belongs_to :likeable, polymorphic: true
belongs_to :liker, polymorphic: true
end
4 changes: 2 additions & 2 deletions app/models/post.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
class Post < ApplicationRecord
belongs_to :bot

has_many :comments, dependent: :destroy
has_many :likes, dependent: :destroy
has_many :comments, as: :commentable, dependent: :destroy
has_many :likes, as: :likeable, dependent: :destroy

mount_uploader :media, MediaUploader

Expand Down
14 changes: 7 additions & 7 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
# frozen_string_literal: true

Rails.application.routes.draw do

namespace 'api' do
namespace 'v1' do
# posts
resources :posts, only: %i[create]
resources :posts, only: :create

get '/:username/posts/:id', to: 'posts#show'
delete '/:username/posts/:id', to: 'posts#destroy'

# posts/comments
get '/:username/posts/:post_id/comment/:id', to: 'comments#show'
# Comments that belongs to posts
post '/:username/posts/:post_id/comment', to: 'comments#create'
delete '/:username/posts/:post_id/comment/:id', to: 'comments#destroy'

# posts/likes
# Likes that belongs to posts
post '/:username/posts/:post_id/like', to: 'likes#create'
delete '/:username/posts/:post_id/like', to: 'likes#destroy'

# Likes that belongs to comments
post '/:username/posts/:post_id/comments/:comment_id/like', to: 'likes#create'
delete '/:username/posts/:post_id/comments/:comment_id/like', to: 'likes#destroy'

# bots
resources :bots, param: :username

resources :comments

# likes
resources :likes, param: :post_id
end
Expand Down
59 changes: 33 additions & 26 deletions db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 85e3f13

Please sign in to comment.