Hey Guys, Welcome back to series, there is a lot for this week let’s dive into the stuff then..
So, i started my week with some tweaks to the already completed User
and authentication
API. But hey, wait life isn’t so easy so are the tweaks.. Here comes codeclimate
to give you some chills. But @tachyons told me not to worry about some of those issues and my PR was merged.. What a relief was that :).. but but be with me codeclimate
is not gonna leave me like this :D
Ok enough talk let’s talk some coding..
I had some hands on projects controller
that would handle all projects related stuff that includes starring, forking, sorting filtering and all..
# GET /api/v1/projects
def index
@projects = if @current_user.nil?
Project.public_access
else
Project.where("author_id = ? OR project_access_type = ?", @current_user.id, "Public")
end
@options[:links] = link_attrs(paginate(@projects), api_v1_projects_url)
render json: Api::V1::ProjectSerializer.new(paginate(@projects), @options)
end
# Want some details hit this GET /api/v1/projects/:id
def show
@project = Project.find(params[:id])
@author = @project.author
authorize @project, :check_view_access? # you should have access though :)
render json: Api::V1::ProjectSerializer.new(@project, @options)
end
# Want to change something, PATCH /api/v1/projects/:id
def update
authorize @project, :check_edit_access? # do you have edit access.. ??
@project.update!(project_params)
end
# DELETE /api/v1/projects/:id
def destroy
authorize @project, :author_access? # no need to mention access everywhere, oh i just did :P
@project.destroy!
render json: {}, status: :no_content
end
# Wan't your project featured, have a look at those first
# GET /api/v1/projects/featured
def featured_circuits
@projects = Project.joins(:featured_circuit).all
render json: Api::V1::ProjectSerializer.new(paginate(@projects), @options)
end
Wan’t to filter or sort your projects…
def filter
@projects = @projects.tagged_with(params[:filter][:tag]) if params.key?(:filter)
end
def sort
return unless params.key?(:sort)
@projects = @projects.order(SortingHelper.sort_fields(params[:sort], SORTABLE_FIELDS))
end
These covers the basics, for further details make sure to checkout our github.
Just a side note, it feels ecstatic to see coveralls
coverage go up in your PR..
Let’s head over to some other stuff.. Projects is done.. You might wanna form groups, add members, assignments..
“Keep calm and believe in CircuitVerse”
As far as groups are concerned we have groups
, group_members
, assignments
controller.
First things first, groups_controller.rb
. We haven’t talked about selective including
yet but will have a look over that here..
# Want to see your groups, GET /api/v1/groups
def index
@groups = paginate(@current_user.groups)
# selective including assignments and group_members
@options[:include] = include_resource if params.key?(:include)
render json: Api::V1::GroupSerializer.new(@groups, @options)
end
# Mentors and student at same time, not allowed in GSoC but we do at CircuitVerse :P
# GET /api/v1/groups_mentored
def groups_mentored
@groups = paginate(@current_user.groups_mentored)
@options[:include] = include_resource if params.key?(:include)
render json: Api::V1::GroupSerializer.new(@groups, @options)
end
# GET /api/v1/groups/:id
def show
@group = Group.find(params[:id])
render json: Api::V1::GroupSerializer.new(@group)
end
# Let's not repeat update and destroy pretty straight forward
# PATCH /api/v1/groups/:id
# DELETE /api/v1/groups/:id
# the promised stuff, include=group_members,assignments
def include_resource
params[:include].split(",")
.map { |resource| resource.strip.to_sym }
.select { |resource| ALLOWED_TO_BE_INCLUDED.include?(resource) }
end
You might want to add and delete members to your groups..group_members_controller.rb
to the rescue. For routing we use shallow routing here.. More details here
# Want to add someone to your group, we've got you covered
# POST /api/v1/groups/:group_id/group_members/
def create
parse_mails(params[:emails])
newly_added = @valid_mails - @existing_mails
newly_added.each do |email|
user = User.find_by(email: email)
if user.nil?
@pending_mails.push(email)
PendingInvitation.where(group_id: @group.id, email: email).first_or_create
else
@added_mails.push(email)
GroupMember.where(group_id: @group.id, user_id: user.id).first_or_create
end
end
render json: { added: @added_mails, pending: @pending_mails, invalid: @invalid_mails }
end
# Got some reason to delete a student from your group, don't hold back your hands
# DELETE /api/v1/group_members/:id
def destroy
@group_member = GroupMember.find(params[:id])
@group_member.destroy!
render json: {}, status: :no_content
end
Evaluations in mind, student’s life is gonna be hard but yes that’s important (says an undergrad smirks
). Assignments obviously would live in assignments_controller.rb
..
# GET /api/v1/groups/:group_id/assignments
def index
@assignments = paginate(@group.assignments)
render json: Api::V1::AssignmentSerializer.new(@assignments, @options)
end
# Details time :P GET /api/v1/assignments/:id
def show
authorize @assignment, :show?
render json: Api::V1::AssignmentSerializer.new(@assignment)
end
# Don't want this to be repetitive so skipping create, update, destroy
# POST /api/v1/groups/:group_id/assignments
# PATCH /api/v1/assignments/:id
# DELETE /api/v1/assignments/:id
# Assignment closed but wan't to reopen it, stay calm and hit
# GET /api/v1/assignments/:id/reopen
def reopen
if @assignment.status != "open"
@assignment.status = "open"
@assignment.deadline = Time.zone.now + 1.day
@assignment.save!
render json: { "message": "Assignment has been reopened!" }
else
api_error(status: 409, errors: "Project is already opened!")
end
end
# Wanna score better than your peers, start early is the key but how do we start
# GET /api/v1/assignments/:id/start
def start
authorize @assignment # can't ley you in if you are not for this, don't take it otherwise :P
@project = @current_user.projects.new
@project.name = @current_user.name + "/" + @assignment.name
@project.assignment_id = @assignment.id
@project.project_access_type = "Private"
@project.save!
render json: {
"message": "Voila! Project set up under name #{@project.name}"
}
end
Let’s leave too mainstream stuff here & catchup on some interesting one.. We need to have the name
and email
for the group_members
but we don’t have them directly plugged into our group_member_model
So, how do we serialize, we’ve, technically Netflix’s fast jsonapi got you covered :)
class Api::V1::GroupMemberSerializer
include FastJsonapi::ObjectSerializer
attributes :group_id, :user_id, :created_at, :updated_at
# here's how we do it, group_member model has_many :users
attribute :name do |object|
object.user.name
end
attribute :email do |object|
object.user.email
end
end
“So far so good”
“Enter Codeclimate and your life will never be same”
Hey Hey you said codeclimate
gives you chills, Yes, i did Let’s go over that. Codeclimate
“reviewed” my PR and loved it so much that it threw “only” (sarcasm intended :p) 243 issues for me to resolve and i was “flabbergasted”..
Well with some refactoring and a lot of head scratching, i was able to boil down the issues to 37. Also, this magical command has earned a special respect in my <3 rubocop -a /path/to/file/that/haunts/you
It’s sort of becoming sad, Cheer up guys, The same PR #1441 has got coveralls coverage
increased by 1.07% ,Not bad huh… Devs might connect :)
Now that’s all folks :)
For the complete documentation of the API, you gotta go to docs and for the details of this PR head over to #1441.
Next up imma shoot another PR for the groups, assignments and stuff’s API. We will also talk about project collaborations and some rspecs too but that’s a story for next Week.
Written on May 23rd , 2020 by Nitish AggarwalTill then Sayonara!