sending error message in json using ruby on rails - ruby-on-rails

I am validating input fields in ruby on rails. I checking whether user have entered or filled these fields or not. If lets say name field is not filled then send an error message to user with indication that name field is not filled. Same goes with other errors. How can I send this kind of message in json using ruby on rails.
Here is what I am doing right now.
this model
validates :email, :name, :company, :presence => true
validates_format_of :email, :with => /\A[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z/
Here is how I am currently sending json data to client
#contacts = Contact.new(params[:contact])
if #contacts.save
render :json => { :error => 0, :success => 1 }
else
render :json => { :error => 1, :success => 0 }
end

The simplest way would be to send down a hash of the errors.
so:
render :json => { :errors => #contacts.errors.as_json }, :status => 420
note that :status => 420 is required to make things like jquery's $.ajax method call their error callback and you should never return a 200 status (the default) when there is an error.

You really should use http status codes to tell the user what is going on, so for invalid record there is
420 Invalid Record Record could not be saved
And then in your JSON return you could also have an error message that would return your active record / active model error messages in it to give them more information.

Related

Patch and delete always returning 204: no content?

I have two models: card and lane, where a lane has many cards and a card belongs to a lane.
def create
lane = lane_find
card = lane.cards.build(card_params)
if card.save
respond_with lane, :include => :cards
else
respond_with({ :errors => card.errors.full_messages }, :status => 422, :location => nil)
end
end
def update
card = Card.find(params[:id])
if card.update_attributes(card_params)
respond_with card.lane
else
respond_with({ :errors => card.errors.full_messages }, :status => 422, :location => nil)
end
end
(Note: lane_find is a private function not shown here but it simply does Lane.find(params[:lane_id]))
The intended behaviour is for the API client to receive a 422 error code when it does not save correctly, and to pass the errors alongs (such as being non-unique or being blank).
The strange thing is the create action works perfectly, as intended, while the update and destroy actions (not shown here) always return 204 on invalid input!
Testing manually on the command-line shows that the validations are set up correctly and card.update_attributes(content: "") returns false.
This is really bugging me! I would love your feedback :)
EDIT: card.rb
class Card < ActiveRecord::Base
validates :content, :uniqueness => {:case_sensitive => false}, :length => { minimum: 1 }, presence: true
belongs_to :lane
end

Unable to customize devise error message

I'm using Devise 3.2.2 and I want to customize error messages for my custom devise registrations controller, as suggested here. When passing in an already used email address, the (custom) controller code
if user.save
render :json => user.as_json, :status => 201
else
warden.custom_failure!
render :json => user.errors, :status => 422
end
produces the following json
{"email":["has already been taken"]}
I'd like to have this error message read
{"messages": ["The email address has already been taken."]}
Unfortunately, I can't find the string "has already been taken" in the config/locales/en.yml-file (nor do I see it on GitHub). In other words, the suggested resolution is not directly applicable to the problem at hand.
Where can I find the error message in question? Is there a clean way to produce a human readable array of error messages in my custom controller?
Wow - RoR blew my mind for the n'th time. What a framework. I love it!
So, user.errors is just an ActiveModel::Errors object. Some errors are, as far as I understand, specified in the locale in the Devise gem. Others, like uniqueness of indexed fields etc. (like the email field), are provided by ActiveModel-validation. That's why I couldn't find the given error in the gem locale.
Now; the ActiveModel::Errors documentation has something pretty interesting to say. It says that there is a method, named full_messages(), that "returns all the full error messages in an array". My controller now looks like this:
if user.save
render :json => user.as_json, :status => 201
else
warden.custom_failure!
render :json => { :messages => player.errors.full_messages }, :status => 422
end
That's it.

Update fails with namespaced model

I have an update form in Rails 3 for admin users that fails silently, despite having validations. It was working previously, but when I moved everything to a namespace, it no longer saves.
Here is the relevant code from my controller:
def update
#admin = Admin::Admin.find(params[:id])
respond_to do |format|
if #admin.update_attributes(params[:admin])
flash[:success] = "'#{#admin.name}' was successfully updated."
format.html { redirect_to admin_admins_path }
else
format.html { render action: "edit" }
end
end
end
And the model (unfinished, but previously working):
class Admin::Admin < ActiveRecord::Base
validates :name, :presence=>{:message=>"Name can't be blank"}
validates :email, :presence=>{:message=>"Email can't be blank"},
:length => {:minimum => 3, :maximum => 254, :message=>"Email must be between 3 and 254 characters"},
:uniqueness=>{:message=>"Email has already been registered"},
:format=>{:with=>/^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :message=>"Email must be a valid email format"}
validates :password, :presence=>{:message=>"Password can't be blank"}
end
And the first part of the form partial:
<%= form_for(#admin) do |f| %>
Everything loads properly, but when I try to save, my validations are ignored and it redirects to the index page with a success message, but without saving the data. I have a feeling I'm missing something to do with namespaces, but I'm not completely sure what the problem is. Could it be looking for the model in the base model directory?
Did you inspect the params? I could imagine that params[:admin] does not contain the forms values anymore.
So, VirtuosiMedia and I stepped through it, and RoR adds an "admin_" to represent the Admin:: namespace, so we had to look for params[:admin_admin].

Rails, Alphanumeric validation in the controller

In my app I let users select a username, just like the twitter signup page: https://twitter.com/signup
When the user starts typing a username, I want in real-time to let the user know if the username is available & valid.
The regex I've been using to validate the username is alphanumeric is:
/^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i
Given params[:username]
In the controller, how can I validate if the username is alphanumeric or not. Note, I'm not saving the record here just validation. so a model validation wouldn't work.
Ideas? Thanks
You'd still want to use model validations.
Something like this perhaps:
class User
validates :username, :format => { :with => /your regex/ }, :uniqueness => true
end
# then in some controller action or rack app
def test_username
user = User.new(:username => params[:username])
# Call user.valid? to trigger the validations, then test to see if there are
# any on username, which is all you're concerned about here.
#
# If there are errors, they'd be returned so you can use them in the view,
# if not, just return success or something.
#
if !user.valid? && user.errors[:username].any?
render :json => { :success => false, :errors => user.errors[:username] }
else
render :json => { :success => true }
end
end
r = /^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i
unless your_string.match(r).nil?
# validation succeeded
end
I think your regex is a little overly verbose. I'd actually try the following regex for the alphanumeric validation:
/\A[A-Z0-9]+\z/i

When creating an object in Ruby on Rails, which method of saving do you prefer, and why?

When writing the "create" method for an object in a Ruby on Rails app, I have used two methods. I would like to use one method for the sake of cleaner and more consistent code. I will list the two methods below. Does anyone know if one is better than the other? If so, why?
Method 1:
def create1
# is this unsecure? should we grab user_id from the session
params[:venue]['user_id'] = params[:user_id]
begin
venue = Venue.create(params[:venue])
#user_venues = #user.venues
render :partial => 'venue_select_box', :success => true, :status => :ok
rescue ActiveRecord::RecordInvalid
render :text => 'Put errors in here', :success => false, :status => :unprocessable_entity
end
end
Method 2:
def create2
# is this unsecure? should we grab user_id from the session
params[:venue]['user_id'] = params[:user_id]
venue = Venue.new(params[:venue])
if venue.save
#user_venues = #user.venues
render :partial => 'venue_select_box', :success => true, :status => :ok
else
render :text => 'Put errors in here', :success => false, :status => :unprocessable_entity
end
end
class VenuesController < ApplicationController
def create
#venue = #user.venues.create!(params[:venue])
render :partial => 'venue_select_box', :success => true, :status => :ok
end
rescue_from ActiveRecord::RecordInvalid do
render :text => 'Put errors in here', :success => false, :status => :unprocessable_entity
end
end
Using #user.venues in this way ensure that the user ID will always be set appropriately. In addition, ActiveRecord will protect the :user_id field from assignment during the course of the #create! call. Hence, attacks from the outside will not be able to modify :user_id.
In your tests, you may verify that doing a POST to :create raises an ActiveRecord::RecordInvalid exception.
I'm of the school of thought that exceptions shouldn't be used for routine conditions, so I'd say the second is better.
It depends. If you expect all of the create statements to work, use the former, because the failure to create-and-save is exceptional, and may possibly be a condition from which the program can't readily recover. Also, if you use relational integrity (foreign_key_migrations by RedHill Consulting), this will throw exceptions on foreign key violations, so you probably want to catch them whenever creating or updating.
The second is workable, and good if the query not succeeding is something you expect as part of the day-to-day operation of that particular action.
Also, your code comment about session being insecure -- the session is the place to put the user_id. As long as you're checking to verify that the user has been authenticated before doing anything else, you'll be okay.
I totally agree with Don's comment. But I would even go one step further with the user_id part and set it as a before filter on the model.

Resources