Is there something like .NET's data annotations in rails? - ruby-on-rails

I was looking for something similar to .net's data annotations in rails, something like this.
What I want to achieve by this is: I have some fields (they could be nil also) for which I want to check the length and if the length exceeds I want to display an error message.
I want to club all the error messages related to, say all blog posts (which again have many separate fields) and then display them at once.

Rails uses ActiveRecord validations. In many cases the default validations are easy to set up. But if you want/or need customized validations that can all be done as well. Read the documentation here:
http://guides.rubyonrails.org/active_record_validations.html
In your case this type of validation is built in to rails so it's simple as adding 1 line to your model:
class MyModel
validates :my_field_name, length: { maximum: 3 }, allow_blank: true
end
This will validate the maximum length of your field. You can also customize the validation error message:
class MyModel
validates :name, presence: {message: "Title can't be blank." }, uniqueness: {message: "Title already exists."}, length: { maximum: 5, message: "Must be less than 5 characters"}
end

Related

Rails validators: Only show certain messages based on hierarchy

For an email attribute, I have two validator helpers like so:
validates :email,
presence: true,
format: { with: /some_regex/, message: "Bad email error message"}
Is there a way to set this up (without using custom validator methods) so if presence: true fails, it will not display the format message?
I don't want to display a format message when the field is blank...it doesn't present a nice user experience "of course it's a bad format... there's nothing there!"
Use the unless option and remove the presence option.
validates :email,
format: { with: /some_regex/, message: "Bad email error message"},
unless: "email.nil?"
This way, the email will be validated unless the email is nil
Learn more about :if and :unless in the Rails Validation Docs
Alternatively, you can use allow_blank which will ensure that the validation only occurs if the field is not blank.
validates :email,
format: { with: /some_regex/, message: "Bad email error message"},
allow_blank: true
Both do pretty much the same thing. The first option, however, is a little more flexible.

Rails range validation with data from another model

I have a Ticket and Event model in which the relationship is that an Event has many Tickets. The Ticket model has columns serial starting value and serial ending value which denotes the range of the valid serial nubers for that event.
I want to validate the Ticket on creation so that if a Ticket is created with a serial number beyond that range, the system will spew out errors saying that the range in invalid.
What I currently have in my ticket model validation is another validation to show a valid serial number for all events which is between 140000 and 149999
validates :serial_number,
presence: true,
numericality: {
only_integer: true,
:greater_than_or_equal_to => 140000,
:less_than => 149999,
:message => "is invalid" },
:uniqueness => { :message => "%{value} has already been taken" }
I need to get data from the Event model and place it into the Ticket validation. Does Rails allow something like this in the model? Should I do it in the controller?
Definitely do this in your model. Use custom validations for it:
validate :serial_number_valid
def serial_number_valid
unless event.serial_number_range.include?(serial_number)
errors.add(:serial_number, "must be within range")
end
end
One way to do this is by using rails validation helper of inclusion. This helper validates that the attributes' values are included in a given set. For this particular case you can use:
validates :serial_number, inclusion: { in: 140000..149999 }, presence: true, uniqueness: true
If you want to use the same method in rails 4 way here's a link to that.

Rails, DRY default validator for string length?

So I am having an issue where length errors are rails exception because the model doesn't have a length validation on it.
I understand I can put a length validator on my string by using
validates :blah, length: { maximum: 255 }
However most of my strings are using the default size of 255, so I would have to repeat this validation in a lot of places.
Is there a DRY way to put a default validator on all strings to validate to the default database length of 255?
The gem schema_validations (https://github.com/SchemaPlus/schema_validations) does what you want.
Automatically creates validations basing on the database schema.
It inspect the database and automatically creates validations basing on the schema. After installing it your model is as simple as it can be.
class User < ActiveRecord::Base
end
Validations are there but they are created by schema_validations under the hood.
This probably isn't exactly the answer you are looking for but if you add multiple fields to the validator then you aren't really repeating the validator and seems fairly DRY to me.
validates :foo, :bar, :baz, length: { maximum: 255 }
class ModelName < ActiveRecord::Base
validates :name, length: { maximum: 255 }
end
Then use it by typing
ModelName.validators

Validating presence with rspec

This is my first time testing in rails and I'm having trouble with what I think should be a pretty simple validation.
In group_spec.rb
it { should validate_presence_of(:enc_key) }
it { should validate_uniqueness_of(:enc_key).case_insensitive }
In my model
validates :enc_key, :presence => true, uniqueness: {:case_sensitive => false}
When I run rspec I'm getting
2) Group should require enc_key to be set
Failure/Error: it { should validate_presence_of(:enc_key) }
Expected errors to include "can't be blank" when enc_key is set to nil, got errors: ["owner There is no owner associated with this group. (nil)", "name can't be blank (nil)", "name is
too short (minimum is 4 characters) (nil)", "stripped_name can't be blank (nil)"]
The list of errors are generated from other validations and I've tried writing a custom validation but that didn't work either.
I'm guessing you are using shoulda matchers here and I can't see anything wrong with your test.
I think you should be using the validates method rather than the validate method in you model. validates is used to declare the kind of validation rules that you are specifying here. validate is used to declare custom validations.
So try this in your model:
validates :enc_key, presence: true, uniqueness: {case_sensitive: false}
See http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates
and http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate
The shoulda matchers are designed to work with otherwise valid records. They change various aspects of the record and test that the validation reports the appropriate error. If there are already errors in the record, this approach generally doesn't work.
You haven't shown the rest of your spec, but I gather than subject is nil. You need to set subject to be a valid instance of your record.
See https://github.com/thoughtbot/shoulda-matchers/issues/365 for a related discussion of this.

Ruby on Rails: Why do I include allow_blank in my validation if I test for presence already?

I'm learning rails with the book Agile Web development with Rails 4e. It uses the following so far as our product model (adapted from a scaffold):
class Product < ActiveRecord::Base
attr_accessible :description, :image_url, :price, :title
validates :description, :title, :image_url, presence: true
validates :price, numericality: {greater_than_or_equal_to: 0.01}
validates :title, uniqueness: true
validates :image_url, allow_blank: true, format: {
with: %r{\.(gif|jpg|png)$}i,
message: 'Must be a valid URL for a gif, png, or jpg..'
}
end
I'm wondering why it tests first for the presence of :image_url, but then in the tertiary validation to make sure the image url is valid, it allows for blank responses which contradicts the first validation. I don't understand why this is supposed to work as is.
As an additional question, if the image_url is empty, how can I test if it is empty in my code? (e.g. in the product view to display a default image.)
Model validations are tested in isolation. A model is valid if and only if it passes validation for each validates statement independently.
It's probably bad-form, and evidently confusing for that allow_blank: true to be in the 4th validation, but that only applies to that single statement. The model must pass all validations to be considered valid, so the 1st statement merely imposes a tighter restriction than the 4th.
A final point, note that presence tests for non-nilness, whereas blank is defined as nil or the empty string. It is therefore possible to be both present and blank; e.g. image_url = ''. However, it remains the case that validations are tested separately in isolation.
I think maybe you are confused about the validation code? I'm a noob, and this is probably not entirely accurate: the validates keyword doesn't test for presence, it starts a block that you use to specify your validations.
As is, your code will validate the :image_url according to your specifications if it exists. If you took out allow_blank: true, then a nonexistent or blank :image_url would fail the validations.
I'm new to Rails as well and am using the same book. My understanding is that in order to stop the validation returning two errors immediately against validation (i.e. one if the field is blank and one if it doesn't have a correct file extension) it must allow_blank for the file format.
The best way I can explain it is to suggest removing the allow_blank: true code and trying to submit the description form again.
You should then see that you get both the validation errors for the field being blank and the file format being wrong.
The allow_blank therefore tells the validation to only error on the file format once the field is no longer blank.
Confused me as well which is why I ended up here!

Resources