ActiveRecord Create (not !) Throwing Exception on Validation - ruby-on-rails

So I'm using ActiveRecord model validations to validate a form in a RESTful application.
I have a create action that does:
#association = Association.new
and the receiving end of the form creates a data hash of attributes from the form parameters to save to the database using:
#association = user.associations.create(data)
I want to simply render the create action if validation fails. The problem is that the .create (not !) method is throwing an exception in cases where the model validation fails. Example:
validates_format_of :url, :with => /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$)/ix, :message => "Your url doesn't seem valid."
in the model produces:
ActiveRecord::RecordInvalid Exception: Validation failed: Url Your url doesn't seem valid.
I thought .create! is supposed throw an exception whereas .create is not.
Am I missing something here?
Ruby 1.8.7 patchlevel 173 & rails 2.3.3

Read the documentation of create and create! carefully.
Both create and create! check the callbacks (in your case validations).
create method return false if exception is raised and true if not while,
create! method raised exception if the record is invalid.
However, create can throw an ActiveRecord::RecordNotUnique if you have a unique index in the database and no validation set on the model. In this case, you should add validates :fieldname, uniqueness: true onto the model.

Related

Validations for api build with rails

I have a model Person.
One controller Api::V1::PersonsController
In my controller:
def index
#persons = Person.new(user_id: #current_user.id, type_id: params[:type_id]).method
render json: #persons, status: :ok
end
In my model:
attr_accessor :user_id, :type_id
validates_presence_of :type_id
Also tried:
validates :type_id, :presence => true
When I create my Person with no type_id, I don't get any error, what else do I need to do, or is there a better way of doing this?
From the Rails guide validation section:
The following methods trigger validations, and will save the object to
the database only if the object is valid:
create
create!
save
save!
update
update!
The bang versions (e.g. save!) raise an exception if the record is
invalid. The non-bang versions don't, save and update return false,
create just returns the object.
When you create an object using the new method, the validation rules do not fire as the object is not persisted to the database.
You can call Person.save or Person.save! after Person.new or create a Person object using create or create!. Both of these methods persist the object to the database so a validation error will be raised.
Also, in your case, you can do something like this:
Person.new(user_id: #current_user.id, type_id: params[:type_id]).valid? # => false
This way, you can check if the object is a valid object and then proceed with the rest of your code.
.new is not going to persist your Person to the database.
Validation will not be carried out unless using .save after .new or in a .create or .create! method.
Check out point 1.2 here in Rails validation guides ›

How to handle ActiveRecord::RecordNotUnique in Rails properly

I am trying to enforce uniqueness with unique index in my Rails project. And I found something confusing.
Like registering a user at my site, you need to provide an email address and a nickname, both need to be unique. I add unique index to both email and nickname. And when duplications come, I rescue exception ActiveRecord::RecordNotUnique, now here's the question, how could I know which field cause the exception?
Thanks a lot for the help.
IMHO you should also add uniqueness validators to your model. That allows you to use Rails' validations and error messages.
# add to model
validates :email, uniqueness: true
validates :nickname, uniqueness: true
Note that to ensure uniqueness on a database level a unique index is still needed.
In ActiveRecord, you can use the valid? method to run validations on your object. If it returns false, then you can view the error messages to determine which field(s) raised an error.
Example:
user = User.new(email: 'unique_email#google.com', nickname: 'non_unique_nickname')
user.valid? #This will run validations
# => false
user.errors.messages
# => {:nickname=>["has already been taken"]}

Is there a better way of validating a non model field in rails

I have a form field in ROR 4 app called as 'measure'. It is not a database column, but its values will help model create child entries of its own via acts_as_tree : https://github.com/rails/acts_as_tree
I have to throw a validation when 'measure' is invalid. So I have created a virtual attribute known as measure and check for its validations only on a certain condition.
model someModel
attr_accessor :measure
validates_presence_of :measure, :if => condition?
Problem is when I am saving the code, I am thrown a validation which is fine. I am also thrown the same validation when I am trying to update the record in some other method of the model. The only way to surpass that is by writing this code:
# I do not want to do this, is there a better way?
self.measure = "someRandomvalue"
self.save
I am making this as virtual attribute only for throwing validations. Is there a better way of throwing validations? The form has other validations, I do not want the error for this validations to be shown differently just because it is not an attribute.
I want it to validated only when active record is saved via create and update action of the controller and not when it is being updated by some random method of model.
I have seen other developers in my team doing similar thing and was always curious about one thing - "What are you trying to achieve doing things the way you are doing?". You see, I am not sure if validators should be used for values that will not be serialized.
Anyways, you may try using format validator instead of presence, which worked in my team's case:
# Rails 3/4
validates :measure, format: { with: /^.+$/, allow_nil: true }
# Rails 2
validates_format_of :measure, :with => /^.+$/, :allow_nil => true
You may also try using allow_blank instead of allow_nil.
I would rather create a custom validator along the lines of validates_accessor_of for values that I know will never be serialized.
HTH

Rails simple validations not working

class User < ActiveRecord::Base
attr_accessible :email, :name
validates :name,:presence=>true,
:length=>{:maximum=>15}
validates :email,:presence=>true,
:length=>{:maximum=>15}
end
I am new to rails and the simplest of the validators are not working. I think I may be making a very silly mistake . I have a User model with 2 attributes only and when I create a new user in ruby console with wrong validations like no name or a longer name than 15 characters it gets added happily Please suggest.I am using rails version:3.2.13 and ruby version:1.9.3
If you are on rails console, be sure to type reload! after making changes to models. In this way, all changes will be reloaded in the console instance.
Moreover, are you sure you are saving these models? You should try something like this:
user = User.new(email: "john.doe#gmail.com")
user.save
If the result of the last line is false, you can view the validation errors with
p user.errors

Why doesn't my custom validation run in Rails?

This is my model:
class Goal < ActiveRecord::Base
belongs_to :user
validate :progress_is_less_than_max
private
def progress_is_less_than_max
if progress > max
errors.add(:progress, "should be less than max")
end
end
end
If I go into the console and do
some_user.goals.create! :name => 'test', :max => 10, :progress => 15, :unit => 'stuff'
it saves just fine, without any errors. What am I not doing right?
Well, that's not how you write a custom validator: your custom validator should inherit from ActiveModel::EachValidator.
See the bottom of this rails cast for an example of a customer validator: http://railscasts.com/episodes/211-validations-in-rails-3?view=asciicast
#jaydel is correct in that .create will return an instance of the model (regardless of if it is saved in the database or not).
Creates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.
However, calling .save! on the .create'd model or calling .create! to begin with will raise an exception if validations fail.
Creates an object just like ActiveRecord::Base.create but calls save! instead of save so an exception is raised if the record is invalid.
.save will run validations but returns false if they fail.
By default, save always run validations. If any of them fail the action is cancelled and save returns false. However, if you supply :validate => false, validations are bypassed altogether. See ActiveRecord::Validations for more information.

Resources