Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions app/controllers/api/v1/profiles_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ module API
module V1
# Controller class that is responsible for handling profile requests.
class ProfilesController < ApplicationController
before_action :set_profile, only: %i[show update]
before_action :authorize_profile!
before_action :set_profile, except: %i[index create]
before_action :set_tag, only: %i[remove_tag]
after_action :verify_authorized

# GET /profiles or /profiles.json
def index
render json: Profile.all, status: :ok
profiles = Profile.all
render json: profiles, status: :ok
end

# GET /profiles/:id or /profiles/:id.json
Expand All @@ -37,16 +39,45 @@ def update
end
end

private
# POST /profiles/:id/add_tag or /profiles/:id/add_tag.json
def add_tag
tag = Tag.find_or_create_by(params[:tag])
if tag_params.blank?
render json: { error: 'There was no tag data passed in so your profile could not be saved.' },
status: :unprocessable_entity
else
Comment thread
ilyabyar marked this conversation as resolved.
if @profile.tags << tag

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/IfInsideElse: Convert if nested inside else to elsif.

render json: @profile, status: :created
else
render json: @profile.errors, status: :unprocessable_entity
end
end
end

def set_profile
@profile = Profile.find_by(user_id: params[:user_id])
end

# DELETE /profiles/:profile_id/remove_tag/:id or /profiles/:profile_id/remove_tag/:id.json
def remove_tag
@profile.tags.destroy(@tag)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry this removes the tag completely from db but it should just unassigne tag from profile/post ...

head 204
end

private

def set_tag
@tag = Tag.find_by(name: params[:name])
end

def profile_params
params.permit(:surname, :name, :patronymic, :birthday, :phone, :about, :user_id)
end

def tag_params
params.permit(:name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear which name is that.
We need to explicitly say this attr is for tags.
so it should be params.require(:tag).perfmit(:name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

params = {
  "tag": { "name": ... },
  "profile": { "name": ... }
}

end

def authorize_profile!
authorize(@profile || Profile)
end
Expand Down
8 changes: 8 additions & 0 deletions app/policies/profile_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ def update?
owns_record?
end

def add_tag?
update?
end

def remove_tag?
update?
end

# Profile policy scope
class Scope < Scope
def resolve
Expand Down
2 changes: 1 addition & 1 deletion app/serializers/profile_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@
# Сlass responsible for serializing profile data
class ProfileSerializer < ActiveModel::Serializer
attributes :id, :surname, :name, :patronymic,
:birthday, :phone, :about
:birthday, :phone, :about, :tags
end
5 changes: 5 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@
post :subscribe, to: 'user_subscriptions#subscribe'
post :unsubscribe, to: 'user_subscriptions#unsubscribe'
end

resources :likes, only: %i[create destroy index]
resources :messages, except: %i[index, show]
resources :conversations do
post 'add_user/:user_id', to: 'conversations#add_user'
delete 'delete_user/:user_id', to: 'conversations#delete_user'
get :profile, to: 'profiles#show'
put :profile, to: 'profiles#update'
post '/add_tag', to: 'profiles#add_tag'
delete '/remove_tag/:name', to: 'profiles#remove_tag'
end
get '/search_profile', to: 'search#search_profile'
get '/search_conversation', to: 'search#search_conversation'
Expand Down
2 changes: 1 addition & 1 deletion spec/factories/tags.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
#
FactoryBot.define do
factory :tag do
name { Faker::Hobby.unique.activity }
name { Faker::Hobby.unique.activity.downcase.gsub(' ','_') }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance/StringReplacement: Use tr instead of gsub.
Layout/SpaceAfterComma: Space missing after comma.

end
end
6 changes: 3 additions & 3 deletions spec/policies/profile_policy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
end
end

permissions :update?, :edit?, :destroy? do
it "is not allowed to update and delete the instance that doesn't belong to him" do
permissions :update?, :edit?, :destroy?, :add_tag?, :remove_tag? do
it "is not allowed to update and delete the instance and that tags that doesn't belong to him" do
expect(policy).not_to permit(user, record)
end
end
Expand All @@ -33,7 +33,7 @@
let(:user) { create :user }
let(:record) { user.profile }

permissions :update?, :edit? do
permissions :update?, :edit?, :add_tag?, :remove_tag? do
it 'is allowed to update the instance' do
expect(policy).to permit(user, record)
end
Expand Down
77 changes: 77 additions & 0 deletions spec/requests/profiles_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'rails_helper'

# rubocop:disable Metrics/BlockLength
RSpec.describe 'Profiles', type: :request do
let(:current_user) { FactoryBot.create(:user) }
let(:auth_headers) { current_user.create_new_auth_token }
Expand Down Expand Up @@ -182,4 +183,80 @@
end
end
end

describe 'POST /api/v1/profiles/:id/add_tag' do
describe 'add tag to profile' do
let(:current_user_profile) { FactoryBot.create(:profile, user_id: current_user.id) }
let(:tag) { FactoryBot.create(:tag) }

before { post "/api/v1/profiles/#{current_user_profile.id}/add_tag", params: { name: tag.name }, headers: auth_headers }

context 'when user is authenticated' do
it 'creates profile tag' do
expect(response).to have_http_status(:created)
end

it 'returns http success' do
expect(response).to have_http_status(:success)
end

context 'with profile that is not current user\'s profile' do
let(:not_current_user_profile) { FactoryBot.create(:profile) }
let(:tag) { FactoryBot.create(:tag) }

before { post "/api/v1/profiles/#{not_current_user_profile.id}/add_tag", params: { name: tag.name }, headers: auth_headers }

it 'can\'t create profile tag' do
expect(response).to have_http_status(:forbidden)
end
end
end

context 'when user is not authenticated' do
before { post "/api/v1/profiles/#{current_user_profile.id}/add_tag", params: { name: tag.name } }

it 'have http status 401' do
expect(response).to have_http_status(:unauthorized)
end
end
end
end

describe 'DELETE /api/v1/profiles/:profile_id/remove_tag/:name' do
describe 'delete tag from profile' do
let(:current_user_profile) { create :profile, user: current_user }
let(:tag) { FactoryBot.create(:tag) }

before { delete "/api/v1/profiles/#{current_user_profile.id}/remove_tag/#{tag.name}", headers: auth_headers }

context 'when user is authenticated' do
it 'returns no content' do
expect(response).to have_http_status(:no_content)
end

it 'returns http success' do
expect(response).to have_http_status(:success)
end

context 'with profile that is not current user\'s profile' do
let(:not_current_user_profile) { FactoryBot.create(:profile) }

before { delete "/api/v1/profiles/#{not_current_user_profile.id}/remove_tag/#{tag.name}", headers: auth_headers }

it 'can\'t delete profile tag' do
expect(response).to have_http_status(:forbidden)
end
end
end

context 'when user is not authenticated' do
before { delete "/api/v1/profiles/#{current_user_profile.id}/remove_tag/#{tag.name}" }

it 'have http status 401' do
expect(response).to have_http_status(:unauthorized)
end
end
end
end
end
# rubocop:enable Metrics/BlockLength