I'm new to Rails and have a couple questions about validating parameters and returning error responses. I want to create a JSON API using the new Rails 5 API mode.
As far as I can tell, Rails recommends using "strong parameters" as a baseline for validating parameters. If I want to, for example, create a User class that requires either a phone number or email, I start with something like this in my UsersController.
def create
@user = User.new(create_user_params)
end
def create_user_params
params.require(:user).permit(:email, :phone)
end
Now if I want something a little more complex, I might add the following
def create
arr_contains_at_least_one(params[:user], [:email, :phone])
@user = User.new(create_user_params)
end
This brings us to my question.
What's the best way to return a "pretty" error response, both in the event of a default Rails error (ActionController::ParameterMissing) or a custom error? By pretty I mean, if I called the API endpoint in a browser, it'd return readable JSON with a descriptive message. If I run my server in production mode, and fail to provide a user parameter in the first example, rails returns:
An unhandled lowlevel error occurred. The application logs may have details.
This is obviously no good, especially if I wished to display the error to an end user. Here I assume the strong parameters pattern is for security and data integrity, not user experience. It would seem the same is true of model field validation. So I make the following adjustments.
def create
return error_response("some error") unless arr_contains_at_least_one(params[:user], [:email, :phone])
@user = User.new(create_user_params)
end
def error_response(msg, status = 400)
render json: {"code":status, "message": msg}, :status => status
end
This works, but now I'm forced to manually write parameter checks (to check for presence of mandatory parameters, and to validate parameters such as email addresses) and their corresponding error responses. If I'm using Rails's built-in field validation on models as well, this seems to violate the DRY principle. Further, designing a good error handling pattern requires quite a bit of custom implementation.
Am I missing out on some Rails magic or am I on the right track here?
EDIT: It looks like active record validations can be fairly easily wrapped in a JSON response (http://guides.rubyonrails.org/active_record_validations.html) but the question still remains for validating presence of parameters.
I think you are confusing the use of strong_parameters
with validation methods.
Strong parameters provides an interface for protecting attributes from end-user assignment. This makes Action Controller parameters forbidden to be used in Active Model mass assignment until they have been whitelisted.
http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
If you whitelist parameters in strong-parameters, it means you will be able to mass-assign them to your ActiveRecord model. Or better, attributes which are not whitelisted will not get passed to your model.
They actually have nothing to do with validations itself. They are meant to protect your model for unpermitted parameter injection.
def create
@user = User.new(create_user_params)
end
def create_user_params
params.require(:user).permit(:email, :phone)
end
so your example:
POST /users body={user: {email: '[email protected]', phone: '1234', some_other: 'some other'}}
the some_other
attribute will not get passed to your User.new
What you are looking for IS activerecord validations. In your specific case, I would write something like:
def create
@user = User.new(create_user_params)
if @user.save
render json: @user
else
render @user.errors.full_messages.as_json, status: 400
end
end
def create_user_params
params.require(:user).permit(:email, :phone)
end
and then in your model:
class User < ActiveRecord::Base
validates_precense_of :some_other #this will cause the user not to save, end thus, report an errer message
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With