Skip to content

Commit

Permalink
[fixes #4] add Blog CRUD
Browse files Browse the repository at this point in the history
refactor controllers
add specs
  • Loading branch information
kuldeepaggarwal committed Nov 28, 2016
1 parent 4f4da5b commit 0535f0a
Show file tree
Hide file tree
Showing 22 changed files with 538 additions and 53 deletions.
1 change: 1 addition & 0 deletions app/abilities/blogger_ability.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class BloggerAbility < Ability
def initialize(user)
can [:show, :destroy, :update], User, { id: user.id }
can [:create, :destroy, :update], Blog, { user_id: user.id }
super
end
end
20 changes: 20 additions & 0 deletions app/controllers/api/v1/blogs_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Api::V1::BlogsController < Api::V1::ResourceController
skip_before_action :authenticate_user!, only: [:show, :index]

before_action :set_blogs, only: :index
load_resource only: :show

with_options only: [:create, :update, :destroy] do
load_and_authorize_resource :user
load_and_authorize_resource :blog, through: :user, shallow: true
end

private
def set_blogs
@blogs = Blog.all.includes(:author)
end

def resource_params
params.require(:blog).permit(:title, :description)
end
end
56 changes: 56 additions & 0 deletions app/controllers/api/v1/resource_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
class Api::V1::ResourceController < Api::V1::BaseController
def index
resources = paginate(self.resources)
render json: collection_serializer_klass.new(
resources,
each_serializer: collection_each_serializer_klass,
root: controller_name,
meta: meta_attributes(resources)
)
end

def show
render json: resource
end

def create
if resource.save
render json: resource, status: :created
else
render json: resource.errors.full_messages, status: :unprocessable_entity
end
end

def update
if resource.update(resource_params)
render json: resource, status: :ok
else
render json: resource.errors.full_messages, status: :unprocessable_entity
end
end

def destroy
if resource.destroy
render json: { message: 'resource deleted successfully' }, status: :ok
else
render json: resource.errors.full_messages, status: :unprocessable_entity
end
end

protected
def resource
instance_variable_get("@#{ controller_name.singularize }")
end

def resources
instance_variable_get("@#{ controller_name }")
end

def collection_each_serializer_klass
Api::V1.const_get("#{ controller_name.classify }Serializer")
end

def collection_serializer_klass
ActiveModel::ArraySerializer
end
end
41 changes: 1 addition & 40 deletions app/controllers/api/v1/users_controller.rb
Original file line number Diff line number Diff line change
@@ -1,45 +1,6 @@
class Api::V1::UsersController < Api::V1::BaseController
class Api::V1::UsersController < Api::V1::ResourceController
load_and_authorize_resource

def show
render json: @user
end

def index
users = paginate(User.all)
render json: ActiveModel::ArraySerializer.new(
users,
each_serializer: Api::V1::UserSerializer,
root: 'users',
meta: meta_attributes(users)
)
end

def destroy
if @user.destroy
render json: { message: 'resource deleted successfully' }, status: :ok
else
render json: @user.errors.full_messages, status: :unprocessable_entity
end
end

def create
user = User.new(resource_params)
if user.save
render json: user, status: :created
else
render json: user.errors.full_messages, status: :unprocessable_entity
end
end

def update
if @user.update(resource_params)
render json: @user, status: :ok
else
render json: @user.errors.full_messages, status: :unprocessable_entity
end
end

private
def resource_params
params.require(:user)
Expand Down
9 changes: 6 additions & 3 deletions app/controllers/concerns/pagination_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module PaginationHelpers
extend ActiveSupport::Concern

private
# collection must be a pagination object
def meta_attributes(collection)
{
current_page: collection.current_page,
Expand All @@ -13,8 +14,10 @@ def meta_attributes(collection)
end

def paginate(collection, options = {})
collection
.page(params[:page] || options[:page])
.per_page(params[:per_page] || options[:per_page] || WillPaginate.per_page)
require 'will_paginate/array' if collection.is_a?(Array)
collection.paginate({
page: params[:page] || options[:page],
per_page: params[:per_page] || options[:per_page] || WillPaginate.per_page
})
end
end
1 change: 1 addition & 0 deletions app/models/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ class Ability

def initialize(user)
cannot [:index], User
can [:show, :index], Blog
end

def self.for_user(user)
Expand Down
7 changes: 7 additions & 0 deletions app/models/blog.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Blog < ApplicationRecord
# Associations
belongs_to :author, foreign_key: :user_id, class_name: :User

# Validations
validates :title, :description, presence: true
end
3 changes: 3 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ class User < ApplicationRecord
# Enums
enum role: { guest: 3, blogger: 4, admin: 5 }

# Associations
has_many :blogs, dependent: :destroy

# Validations
validates :email, :first_name, presence: true
with_options allow_blank: true do
Expand Down
5 changes: 5 additions & 0 deletions app/serializers/api/v1/blog_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Api::V1::BlogSerializer < ActiveModel::Serializer
attributes :id, :title, :description

has_one :author, serializer: UserSerializer
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
# Require `belongs_to` associations by default. This is a new Rails 5.0
# default, so it is introduced as a configuration option to ensure that apps
# made on earlier versions of Rails are not affected when upgrading.
Rails.application.config.active_record.belongs_to_required_by_default = true
# Rails.application.config.active_record.belongs_to_required_by_default = true
#
# [HACK]: `cancancan` gem hinder the loading sequence.
# see: https://github.com/CanCanCommunity/cancancan/pull/292/files
ActiveRecord::Base.belongs_to_required_by_default = true
6 changes: 6 additions & 0 deletions config/initializers/overrides/strong_parameters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# https://github.com/rails/rails/pull/22830
module ActionController
class Parameters
delegate :include?, to: :@parameters
end
end
10 changes: 5 additions & 5 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html

# Serve websocket cable requests in-process
# mount ActionCable.server => '/cable'

namespace :api do
namespace :v1 do
controller :sessions do
post :login, action: :create
end
resources :users, only: [:index, :create, :show, :update, :destroy]

resources :users, only: [:index, :create, :show, :update, :destroy] do
resources :blogs, only: [:create, :show, :update, :destroy], shallow: true
end
resources :blogs, only: [:index]
end
end
end
11 changes: 11 additions & 0 deletions db/migrate/20160128192002_create_blogs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CreateBlogs < ActiveRecord::Migration[5.0]
def change
create_table :blogs do |t|
t.references :user, index: true, foreign_key: true
t.string :title
t.text :description

t.timestamps
end
end
end
11 changes: 10 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20160128165609) do
ActiveRecord::Schema.define(version: 20160128192002) do

create_table "blogs", force: :cascade do |t|
t.integer "user_id"
t.string "title"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_blogs_on_user_id"
end

create_table "users", force: :cascade do |t|
t.string "email"
Expand Down
Loading

0 comments on commit 0535f0a

Please sign in to comment.