Use inheritance for very similar controllers in rails app - ruby-on-rails

I have a rails app with two controllers that have very similar behaviors.
One is a UsersController related to the concept of Hotel, the other is also named UsersController but related to the concept of association, so it is stored in a folder association :class Api::V1::Association::UsersController < Api::V1::BaseController
These controllers have very similar behaviors, methods with minor differences (they rely on different database tables for certain variables...). I was reading about inheritance and thought that it could be interesting to make the Association::UsersController inherit from the UsersController. Do you think this could be the right thing to do in my case ? For example I have been trying to rewritte the method invite of Association::UsersController to use inheritance but I am a bit confused on how to do it. Could you tell me how you would rewrite this method if the Association::UsersControllerinherits from the usersController. Here how both controllers look like :
users_controller.rb :
class Api::V1::UsersController < Api::V1::BaseController
skip_after_action :verify_authorized, only: [:invite, :update_specific, :show]
before_action :set_user, except: [:invite, :index, :update_specific]
before_action :set_account, only: [:index, :invite, :show]
# creates user linked to account / only account owner can create users linked to account
# input account_id & email
def invite
unless current_user.id != #account.admin_user_id
user_already_exists_or_email_blank?
set_new_user
ActiveRecord::Base.transaction do
set_hotels_access
save_user_and_send_invitation_email
end
else
render_error("not_admin")
end
end
def show
if ((current_user == #user) || (#account.admin == current_user))
else
render_error("unauthorized")
end
end
# admin can update employee or manager
def update_specific
#user_to_update = User.find(params[:id])
if #user_to_update.account != current_user.created_account
render_error("unauthorized")
else
ActiveRecord::Base.transaction do
update_user_and_hotels_access
end
end
end
# update self
def update
authorize #user
if #user.update(user_params)
render_success("updated")
else
render_error("")
end
end
def destroy
authorize #user
if #user.destroy
render json: {message: "User successfully destroyed"}
else
render json: {error: "There was an error please try again"}
end
end
# envoyer account params
def index
if (current_user.created_account == #account) || ((current_user.account == #account) && (current_user.status == "manager"))
#users = policy_scope(User).where(account: #account)
#admin = #account.admin
render json: {users: #users, admin: #admin}
else
render json: {message: "Unauthorized"}
end
end
# unlincks user from account
#input user_id
def unlinck
authorize #user
#user.account = nil
if #user.save && #user.hotels.delete_all.nil?
render json: {user: #user}
else
render_error("db")
end
end
private
def user_already_exists_or_email_blank?
if User.find_by_email(params[:user][:email])
render_error("mail_exists") and return
elsif params[:user][:email].blank?
render_error("empty_email") and return
end
end
def set_new_user
password = SecureRandom.hex
invitation_token = SecureRandom.uuid
#user = User.new(first_name: params[:user][:first_name], last_name: params[:user][:last_name], telephone: params[:user][:telephone], account_id: params[:user][:account_id], email: params[:user][:email], status: params[:user][:status], password: password, password_confirmation: password, invitation_token: invitation_token, invitation_created_at: Time.now, role: "hotel")
end
def set_hotels_access
if params[:hotel_access].first == "all"
#hotels = #account.hotels
else
#hotels = Hotel.where(id: params[:hotel_access])
end
end
def save_user_and_send_invitation_email
if #user.save && #user.hotels << #hotels
if UserMailer.send_invitation(#user, params[:app_base_url]).deliver_now
#user.invitation_sent_at = Time.now
if #user.save
render_success("mail_sent")
else
render_error("db")
end
else
render_error("mail_processing")
end
else
render_error("db")
end
end
def update_user_and_hotels_access
#hotels = Hotel.where(id: params[:hotel_access])
if #user_to_update.hotels.destroy_all
if #user_to_update.hotels << #hotels
if #user_to_update.update(user_params)
render json: {message: "User successfully updated"}
else
render_error("db")
end
else
render("db")
end
else
render_error("db")
end
end
def set_user
#user = User.find(params[:id])
end
def set_account
if params[:account_id]
#account = Account.find(params[:account_id])
elsif params[:user][:account_id]
#account = Account.find(params[:user][:account_id])
end
end
def user_params
params.require(:user).permit(
:email,
:account_id,
:first_name,
:last_name,
:telephone,
:position,
:status,
:user_id
)
end
def render_error(error_type)
case error_type
when "not_admin"
render json: {error: "You are not allowed to create a user for this account"}
when "mail_exists"
render json: {error: "Please fill the email field and try again"}
when "empty_email"
render json: {error: "Please fill the email field and try again"}
when "mail_processing"
render json: { error: "We couldnt send an email to your invitee. Please try again" }
when "db"
render json: {error: "An error occured. Please try again"}
when "unauthorized"
render json: {error: "Unauthorized"}
else
render json: { errors: #user.errors.full_messages }, status: :unprocessable_entity
end
end
def render_success(success_type)
case success_type
when "mail_sent"
render json: { success: "An email was sent to your collaborator asking him to join your Quickbed team." }
when "password_changed"
render json: {success: "Your password was successfully changed"}
when "updated"
render json: {success: "Your infos were successfully updated"}
end
end
end
association/users_controller.rb
class Api::V1::Association::UsersController < Api::V1::BaseController
skip_after_action :verify_authorized, only: [:invite, :update_specific, :show]
before_action :set_user, except: [:invite, :index, :update_specific]
before_action :set_account_asso, only: [:index, :show, :invite]
# creates user linked to account / only account owner can create users linked to account
# input account_id & email
def invite
unless current_user.id != #account_asso.admin_user_id
user_already_exists_or_email_blank?
set_new_user
ActiveRecord::Base.transaction do
set_offices_access
save_user_and_send_invitation_email
end
else
render_error("not_admin")
end
end
def show
if ((current_user == #user) || (#account_asso.admin == current_user))
else
render_error("unauthorized")
end
end
# admin can update employee or manager
def update_specific
#user_to_update = User.find(params[:id])
if #user_to_update.account != current_user.created_account
render_error("unauthorized")
else
ActiveRecord::Base.transaction do
update_user_and_offices_access
end
end
end
# update self
def update
authorize #user
if #user.update(user_params)
render_success("updated")
else
render_error("db")
end
end
def destroy
authorize #user
if #user.destroy
render json: {message: "User successfully destroyed"}
else
render_error("db")
end
end
# envoyer account params
def index
if (current_user.created_account_asso == #account_asso) || ((current_user.account_asso == #account_asso) && (current_user.status == "manager"))
#users = policy_scope(User).where(account_asso: #account_asso)
#admin = #account_asso.admin
render json: {users: #users, admin: #admin}
else
render_error("unauthorized")
end
end
# unlincks user from account
#input user_id
def unlinck
authorize #user
#user.account_asso = nil
if #user.save && #user.offices.delete_all.nil?
render json: {user: #user}
else
render_error("db")
end
end
private
def user_already_exists_or_email_blank?
if User.find_by_email(params[:user][:email])
render_error("mail_exists") and return
elsif params[:user][:email].blank?
render_error("empty_email") and return
end
end
def set_new_user
password = SecureRandom.hex
invitation_token = SecureRandom.uuid
#user = User.new(first_name: params[:user][:first_name], last_name: params[:user][:last_name], telephone: params[:user][:telephone], account_asso_id: params[:user][:account_asso_id], email: params[:user][:email], status: params[:user][:status], password: password, password_confirmation: password, invitation_token: invitation_token, invitation_created_at: Time.now, role: "asso")
end
def set_offices_access
if params[:office_access].first == "all"
#offices = account_asso.offices
else
#offices = Office.where(id: params[:office_access])
end
end
def save_user_and_send_invitation_email
if #user.save && #user.offices << offices
if UserMailer.send_invitation(#user, params[:app_base_url]).deliver_now
#user.invitation_sent_at = Time.now
if #user.save
render_success("mail_sent")
else
render_error("db")
end
else
render_error("mail_processing")
end
else
render_error("db")
end
end
def update_user_and_offices_access
#offices = Office.where(id: params[:office_access])
if #user_to_update.offices.destroy_all
if #user_to_update.offices << #offices
if #user_to_update.update(user_params)
render json: {message: "User successfully updated"}
else
render_error("db")
end
else
render("db")
end
else
render_error("db")
end
end
def set_user
#user = User.find(params[:id])
end
def set_account_asso
if params[:account_asso_id]
#account_asso = AccountAsso.find(params[:account_asso_id])
elsif params[:user][:account_asso_id]
#account_asso = AccountAsso.find(params[:user][:account_asso_id])
end
end
def user_params
params.require(:user).permit(
:email,
:account_id,
:first_name,
:last_name,
:telephone,
:position,
:status,
:user_id
)
end
def render_error(error_type)
case error_type
when "not_admin"
render json: {error: "You are not allowed to create a user for this account"}
when "mail_exists"
render json: {error: "Please fill the email field and try again"}
when "empty_email"
render json: {error: "Please fill the email field and try again"}
when "mail_processing"
render json: { error: "We couldnt send an email to your invitee. Please try again" }
when "db"
render json: {error: "An error occured. Please try again"}
when "unauthorized"
render json: {error: "Unauthorized"}
else
render json: { errors: #user.errors.full_messages }, status: :unprocessable_entity
end
end
def render_success(success_type)
case success_type
when "mail_sent"
render json: { success: "An email was sent to your collaborator asking him to join your Quickbed team." }
when "password_changed"
render json: {success: "Your password was successfully changed"}
when "updated"
render json: {success: "Your infos were successfully updated"}
end
end
end
Maybe I should rewritte the usersController linked to the concept of Hotel or maybe I should create a third superusersControllerfrom which both the usersController linked to the concept of hotel and the usersController linked to the concept of Association would inherit ? Could you help me find the best fit to my situation ?

You can take a look at Service Objects. They are just plain old Ruby objects. You can extract your invite method into something like UsersService#invite then call it from both controllers. Differences in logic can be handled by passing it a parameter in which context it runs in (users or associations)

Related

NoMethodError:undefined method `employee' for nil:NilClass for RSPEC test Rails

I want to run the rspec of Tickets controllers, I Have used scaffold and I have made some changes according to my project.
but I am getting some errors. I also have a login (using Devise).
How do I go ahead?
This is the controller-
class TicketsController < ApplicationController
before_action :set_ticket, only: %i[ show edit update destroy assign]
before_action :set_assign_ticket, only: %i[assignid]
# shows the landing page of employee
def landing
#tickets = current_user.employee.tickets.order('tstatus_id, id desc')
end
# Service engineer index showing the tickets which are assinged to him
def slanding
#tickets = Ticket.where(service_id: current_user.employee.service_id).order('tstatus_id, id desc')
end
# Showing tickets list based on the user type
def index
#tickets = if current_user.employee.designation.role == "ADMIN"
Ticket.all.order('tstatus_id ,id desc ')
else
Ticket.where(employee: current_user.employee)
end
end
def show
#tickets = Ticket.all
end
def new
#ticket = Ticket.new
end
#creating a new ticket
def create
#ticket = Ticket.new(ticket_params)
#ticket.employee = current_user.employee
respond_to do |format|
if #ticket.save
format.html { redirect_to landing_path}
else
format.html { render :new, status: :unprocessable_entity }
end
end
end
# updating a ticket
def update
respond_to do |format|
if #ticket.update(ticket_params)
if current_user.employee.designation.role == "ADMIN"
format.html { redirect_to tickets_url }
else
format.html { redirect_to slanding_path }
end
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end
private
def set_ticket
#ticket = Ticket.where(id: params[:id]).first
end
def ticket_params
params.require(:ticket).permit(:kind, :description, :dev_id, :service_id,:tstatus_id)
end
def set_assign_ticket
#ticket = Ticket.find(params[:id])
end
end
This is the model -
class Ticket < ApplicationRecord
belongs_to :service, optional: true
belongs_to :employee
belongs_to :tstatus
before_validation(on: :create) do
self.service_id = 4 # this will assign the service engineer to NONE
self.tstatus_id = 1 # this will assign the status to logged
end
validates :description, presence: true
end
My test cases are:
require 'rails_helper'
describe TicketsController, type: :controller do
# describe 'GET show' do
it 'gets show based on ID' do
#ticket = Ticket.new(id: 1,kind: "Example Ticket", description: "Ticket#example.com", service_id: 1, employee_id: 1,tstatus_id:1)
get :show, params: { id: #ticket.id }
expect(response.status).to eq(200)
end
# describe 'GET edit' do
it 'has 200 status code' do
get :new
expect(response.status).to eq(200)
end
describe 'POST create' do
it 'has 200 status code' do
mock = double('Employee')
expect(mock).to receive(:employee_id)
post :create, params: {
ticket: {
id: 1,kind: "Example Ticket", description: "Ticket#example.com", service_id: 1, employee_id: 1,tstatus_id:1
}
}
expect(response.status).to eq 302
end
end
end
I am a newbie to rails,
Can someone tell me how to write test cases for the controller above?

Pundit don't see user

I am a newbie when it comes to RubyOnRails. Recently while working with the gem pundit I encountered a problem. Pundit during function sort? authorization does not see the logged in user that is #user = nill. I don't know what the problem is because other authorizations with the same syntax works for example edit? I am uploading the code below:
lesson_controler.rb
class LessonsController < ApplicationController
before_action :set_lesson, only: [ :show, :edit, :update, :destroy ]
def sort
#course = Course.friendly.find(params[:course_id])
#lesson = Lesson.friendly.find(params[:lesson_id])
authorize #lesson
#lesson.update(lesson_params)
render body: nil
end
def index
#lessons = Lesson.all
end
def show
authorize #lesson
current_user.view_lesson(#lesson)
#lessons = #course.lessons
end
def new
#lesson = Lesson.new
#course = Course.friendly.find(params[:course_id])
end
def edit
authorize #lesson
end
def create
#lesson = Lesson.new(lesson_params)
#course = Course.friendly.find(params[:course_id])
#lesson.course_id = #course.id
authorize #lesson
respond_to do |format|
if #lesson.save
format.html { redirect_to course_lesson_path(#course,#lesson), notice: "Lesson was successfully created." }
format.json { render :show, status: :created, location: #lesson }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #lesson.errors, status: :unprocessable_entity }
end
end
end
def update
authorize #lesson
respond_to do |format|
if #lesson.update(lesson_params)
format.html { redirect_to course_lesson_path(#course,#lesson), notice: "Lesson was successfully updated." }
format.json { render :show, status: :ok, location: #lesson }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #lesson.errors, status: :unprocessable_entity }
end
end
end
def destroy
authorize #lesson
#lesson.destroy
respond_to do |format|
format.html { redirect_to course_path(#course), notice: "Lesson was successfully destroyed." }
format.json { head :no_content }
end
end
private
def set_lesson
#course = Course.friendly.find(params[:course_id])
#lesson = Lesson.friendly.find(params[:id])
end
def lesson_params
params.require(:lesson).permit(:title, :content, :row_order_position)
end
end
lesson_policy.rb:
class LessonPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.all
end
end
def sort?
#record.course.user_id == #user.id
end
def edit?
#record.course.user_id == #user.id
end
def update?
#record.course.user_id == #user.id
end
def destroy?
#record.course.user_id == #user.id
end
def show?
#record.course.user_id == #user.id || #user&.has_role?(:admin) || #record.course.bought(#user) == false
end
def new?
#record.course.user_id == #user.id
end
def create?
#record.course.user_id == #user.id
end
end
Application_policy.rb:
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
false
end
def show?
false
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
class Scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope.all
end
private
attr_reader :user, :scope
end
end
Console logs
How can I make a logged in user visible to pundit?

File doesn't attach on create but attaches on update for zendesk

The workflow should be users should be able to attach files to comments on zendesk ticket regardless if it's a new ticket or existing ticket.
Currently attaching files to comments on existing tickets works perfectly fine. However, if you look at the create action is where it does nothing as far as being able to attach the file. It doesn't throw an error but just doesn't attach the file. I'm sure it's the way my code is flowing but can't figure it out.
require_dependency 'zen_support/application_controller'
module ZenSupport
class TicketsController < ApplicationController
include SmartListing::Helper::ControllerExtensions
helper SmartListing::Helper
before_action :authenticate_user!, except: :zen_update
before_action :set_new_ticket, only: [:new, :create]
before_action :get_ticket, only: [:show, :edit, :update, :zen_update]
before_action :authorize_ticket, except: :zen_update
rescue_from ZendeskAPI::Error::NetworkError, with: :network_error
def new
respond_to do |format|
format.js
end
end
def index
if zen_list_type == 'datatable'
#tickets = tickets
else
smart_listing
end
respond_to do |format|
format.html
format.js
end
end
def create
if(!#ticket.valid? && (#ticket.errors.keys - [:zendesk_id]).present?)
# test if ticket is invalid beyond just missing zendesk_id
raise ActiveRecord::RecordInvalid.new #ticket
else
ActiveRecord::Base.transaction do
#zendesk_ticket.save!
upload_to_zendesk(params[:comment], params[:attachments])
#ticket.zendesk_id = #zendesk_ticket.id
#ticket.status = #zendesk_ticket.status
#ticket.save!
smart_listing
flash.now[:success] = "Your help request was successfully submitted.\n
Your support ticket number is ##{#zendesk_ticket.id}.\n\n
You should receive a confirmation email shortly.\n\n
Thank you!"
end
end
rescue Exception => exception
flash.now[:error] = exception.to_s
#zendesk_ticket.delete if #zendesk_ticket.id
render :new
end
def show
render action: :edit
end
def update
respond_to do |format|
format.js do
# don't save over comment, just use the field for validation
upload_to_zendesk(params[:comment], params[:attachments])
#zendesk_ticket.update(ticket_update_params)
if #ticket.valid? && #zendesk_ticket.save! && #ticket.update(updated_at: Time.now)
flash.now[:success] = "Your help request was successfully updated.\n
Your support ticket number is ##{#zendesk_ticket.id}.\n\n
You should receive a confirmation email shortly.\n\n
Thank you!"
else
flash.now[:error] = if #ticket.errors.present?
#ticket.errors.full_messages.join "\n"
else
'There was a problem sending out your request.'
end
render action: :edit
end
end
end
end
def zen_update
ZenSupport::Ticket.find_by(
zendesk_id: params[:id]
)&.update(zen_update_params)
render nothing: true
end
def network_error
flash.now[:error] = 'There was a network error connecting to the Zendesk API. Try again later.'
render 'network_error'
end
private
def upload_to_zendesk(comment_body, files)
#zendesk_ticket.comment = { value: comment_body }
Array(files).each do |file|
#zendesk_ticket.comment.uploads << file
end
end
def tickets
ZenSupport::Ticket.where user: current_user
end
def smart_listing
smart_listing_create(
:support_tickets,
tickets,
partial: 'zen_support/tickets/list',
array: tickets.count != 0
# we want to use array: true if there are records present because it pre-renders the activerecord
# objects so we can do sorting on the encrypted field 'subject'. BUT, if there are no records,
# then array: true gives us a pagination error
)
end
def ticket_params
{
subject: subject,
comment: comment,
zendesk_id: zendesk_id,
zendesk_submitter_id: submitter_id,
ticket_type: ticket_type,
priority: priority,
tags: tags,
user: current_user
}
end
def zendesk_ticket_params
{
subject: subject,
type: ticket_type,
comment: { value: comment },
submitter_id: submitter_id,
requester_id: requester_id,
priority: priority,
tags: tags
}
end
def ticket_update_params
{
comment: {
body: params[:comment],
author_id: zendesk_user.id
}
}
end
def zen_update_params
{
zendesk_id: zendesk_id,
status: #zendesk_ticket.status,
priority: #zendesk_ticket.priority,
updated_at: #zendesk_ticket.updated_at
}
end
def subject
params.dig :zen_support_ticket, :subject
end
def comment
params.dig :zen_support_ticket, :comment
end
def zendesk_id
#zendesk_ticket.id
end
def tags
[
*params.dig(:zen_support_ticket, :tags),
*ZenSupport.configuration.options[:support_ticket_attributes][:static_tags]
]
end
def ticket_type
params.dig(:zen_support_ticket, :ticket_type).to_s.downcase
end
def set_new_ticket
#zendesk_ticket = ZendeskAPI::Ticket.new(
zen_client, zendesk_ticket_params
)
#ticket = ZenSupport::Ticket.new(ticket_params)
end
def get_ticket
#zendesk_ticket = ZendeskAPI::Ticket.find!(
zen_client,
id: params[:id]
)
#ticket = ZenSupport::Ticket.find_by!(zendesk_id: params[:id])
end
def priority
(params.dig(:zen_support_ticket, :priority) || ZenSupport.configuration.options[:support_ticket_attributes][:default_priority]).downcase
end
def submitter_id
zendesk_user.id
end
def requester_id
zendesk_user.id
end
def user_params
params.require(:zen_support_user).permit(tags: [])
end
def zendesk_user
#zendesk_user ||= (get_zendesk_user || create_zendesk_user)
end
def get_zendesk_user
zen_client.users.search(
query: "email:#{zen_current_user.email}"
).first
end
def create_zendesk_user
ZendeskAPI::User.create(
zen_client,
email: zen_current_user.email,
name: zen_current_user.full_name,
tags: user_tags
)
end
def user_tags
ZenSupport.configuration.user_setup[:static_tags]
end
def authorize_ticket
authorize Ticket
end
end
end
try adding this one-line to your create-method
def create
if(!#ticket.valid? && (#ticket.errors.keys - [:zendesk_id]).present?)
# test if ticket is invalid beyond just missing zendesk_id
raise ActiveRecord::RecordInvalid.new #ticket
else
ActiveRecord::Base.transaction do
#zendesk_ticket.save!
upload_to_zendesk(params[:comment], params[:attachments])
#zendesk_ticket.save!
...

Unable to create user object in rails backend using JWT authentication

I am trying to create User objects in a rails PostgreSQL database using JWT authentication. When I fire the create user method from my React frontend the user is not created in the backend and I suspect this has something to do with how my controllers are set up.
Here is my User controller in my Rails backend:
class Api::V1::UsersController < ApplicationController
before_action :find_user, only: [:show]
skip_before_action :authorized, only: [:index, :create]
def index
#users = User.all
render json: #users
end
def show
render json: #user
end
def create
#user = User.create(user_params)
if #user.valid?
#token = encode_token(user_id: #user.id)
render json: { user: UserSerializer.new(#user), jwt: #token }, status: :created
else
render json: {error: "Could not create user"}, status: :unprocessible_entity
end
end
end
private
def user_params
params.permit(:username, :password)
end
def find_user
#user = User.find(params[:id])
end
Here is my 'auth' controller for JWT:
class Api::V1::AuthController < ApplicationController
skip_before_action :authorized, only: [:create]
def create # POST /api/v1/login
#user = User.find_by(username: user_login_params[:username])
if #user && #user.authenticate(user_login_params[:password])
#token = encode_token({ user_id: #user.id })
render json: { user: UserSerializer.new(#user), jwt: #token }, status: :accepted
else
render json: { message: 'Invalid username or password' }, status: :unauthorized
end
end
private
def user_login_params
params.require(:user).permit(:username, :password)
end
end
And my application controller (I suspect the issue is here and has to do with the way in which I am encoding and decoding the tokens):
class ApplicationController < ActionController::API
before_action :authorized
def encode_token(payload)
JWT.encode(payload, ENV["jwt_secret"])
end
def auth_header
request.headers['Authorization']
end
def decoded_token
if auth_header()
token = auth_header.split(' ')[1]
begin
JWT.decode(token, ENV["jwt_secret"], true, algorithm: 'HS256')
rescue JWT::DecodeError
nil
end
end
end
def current_user
if decoded_token()
user_id = decoded_token[0]['user_id']
#user = User.find_by(id: user_id)
else
nil
end
end
def logged_in?
!!current_user
end
def authorized
render json: { message: 'Please log in' }, status: :unauthorized unless logged_in?
end
end
From my front-end I am using a fetch method to POST to the /users/ endpoint like so:
export const signupUser = (username, password) => {
return(dispatch) => {
const data = {user: {username, password} }
fetch('http://localhost:3000/api/v1/users',{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: JSON.stringify(data)
})
.then(r=>r.json())
.then(r=>{
localStorage.setItem('jwt', r.jwt)
dispatch({
type: SET_CURRENT_USER,
payload: r.user
})
})
}
}
Apologies that this is long-winded. I wanted to include all the code necessary to figure this out. Any assistance would be appreciated.
I noticed you are not saving your user object when you using a function to create user. Please check app/controllers/api/v1/users_controller.rb and modify following with valid to save method
def create
#user = User.create(user_params)
if #user.valid?
#token = encode_token(user_id: #user.id)
render json: { user: UserSerializer.new(#user), jwt: #token }, status: :created
else
render json: {error: "Could not create user"}, status: :unprocessible_entity
end
end
Change the line #user.valid? to #user.save
def create
#user = User.create(user_params)
if #user.save
#token = encode_token(user_id: #user.id)
render json: { user: UserSerializer.new(#user), jwt: #token }, status: :created
else
render json: {error: "Could not create user"}, status: :unprocessible_entity
end
end
Please note .valid? is used to validate and check if any error, and .save is used to save it. You are just checking validation and not actually saving, validation happen automatically so there is no need for this method here.

Returning Devise errors based on conditions with Rails

When I post a session to rails/devise, I either get response with the user data, or i get a bland error message. How can I send back custom messages based on what goes wrong with creating if the session?
current code:
class V1::SessionsController < ApiBaseController
skip_before_action :verify_authenticity_token
def create
email = params[:user] && params[:user][:email]
username = params[:user] && params[:user][:username]
#user = User.where(email: email).first if email
#user = User.where(username: username).first if username
if #user&.valid_password?(params[:user] && params[:user][:password])
#user.update_user_login_timestamp
respond_to do |format|
format.json { render '/users/show', status: :ok }
end
else
render json: {success: false, message: "no good"}, status: 500
end
end
private
def user_params
params.require(:user).permit(:email, :password, :username)
end
end
What I'd like to do:
if username_found_but_password_doesnt_match
render json: {error: "bad password"} status: 500
elsif username_not_found
render json: {error: "doesnt exist"} status: 500
end
You can write the create action as:
def create
email = params[:user] && params[:user][:email]
username = params[:user] && params[:user][:username]
#user = User.where(email: email).first if email
#user = User.where(username: username).first if username
respond_to do |format|
if #user.blank?
format.json { render json: {error: "doesnt exist"}, status: 404 }
elsif #user.valid_password?(params[:user] && params[:user][:password])
#user.update_user_login_timestamp
format.json { render '/users/show', status: :ok }
else
format.json { render json: {error: "bad password"}, status: 422 }
end
end
end

Resources