Reputation: 2834
I am trying to create a web API that allows creation of FriendShip
by email or phone_number.
class Api::FriendshipsController < Api::BaseController
respond_to :json
def create
friend = User.where("email = ? OR phone_number = ?", params[:emailOrPhone], params[:emailOrPhone]).first # create a friend by email or phone_number
if friend.valid? # check if the friend exists, if it does we create our new friendship
friendship = Friendship.new
friendship.user = current_user
friendship.friend = friend
if friendship.valid? # check if friendship is valid
friendship.save # if it is, we save and return a success JSON response
render json: {created: true}, status: 200
else # if it's not a valid friendship, we display a error JSON response
render json: {created: false}, status: 400
end
end
end
end
Here is my FriendShip
model
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => "User"
validates_uniqueness_of :user_id, scope: :friend_id, :message => '%{friend_id} is already a friend'
validate :check_friend_and_user # prevent user trying to add him/herself as friend.
def check_friend_and_user
errors.add(:friend, "can't be the same as user") if user == friend
end
end
Whenever the uniqueness constrain is violated, an error missing interpolation argument :friend_id in "%{friend_id} is already a friend" ({:model=>"Friendship", :attribute=>"User", :value=>2} given)
with error code 500
How do I make it not throw an error but instead proceed to give back a 'fail json response' with status code 400
I want the caller of this API to know that they are trying to add someone that is already a friend. Getting back a status code 500
and a bunch of html does not seems to uniquely identify it. So I would like to throw a error in the form of JSON and status 200
Upvotes: 0
Views: 47
Reputation: 3935
What you seem to be trying to do is determine if the friend is already associated to the User via the friendship class. Which you can simplify with a has_many :friendships association on the User object.
Also, the way you're looking up by email OR phone is IMO unnecessarily ambiguous and will be problematic if you want to separately track one or the other for other purposes. Which you seem to be wanting to do since you have them broken out into separate database columns. I think you could just put two form inputs email or phone number and only pass one along to the controller. If you must have only one then you could determine what the form submits in Javascript or something.
In that case, you'd be better off sending the type of identifier with your initial data from your form, so you can look for one or the other. So your form would explicitly send the column lookup identifier, e.g. the params would be equivalent to the ruby hash
{friendship: {email: "[email protected]"}}
With that in the params then you could do what your trying with this code
# assuming you're passing via a params hash that would look like
# one or the other of the following
# {friendship: {email: "[email protected]"}}
# {friendship: {phone_number: "123-123-1234"}}
def create
if current_user.friendships.find_or_create_by(friendship_params)
render json: {created: true}, status: 200
else # if it's not a valid friendship, we display a error JSON response
render json: {created: false}, status: 400
end
end
protected
def friendship_params
require(:friendship).permit(:email, :phone_number)
end
Upvotes: 1