Rails - Customize model validation error messages but without a database - ruby-on-rails

I have a model that validates a form but it does not inherit from ActiveRecord....it does not have a database
I am validating certain fields in the model but i want to have custom validation messages.....in the past I've went into the
en.yml
en:
activerecord:
models:
mymodel: "CHANGE TO SOMETHING ELSE"
and could easily change it to whatever i want but it is not working for this model....i think its because its not inheriting from ActiveRecord.....
how can i customize my validation errors?

try including translations like this:
include ActiveModel::Translation
EDIT:
if your model had an email attribute and the blank validation didnt pass you can format you locale like this
locale:
en:
activemodel:
attributes:
mymodel:
email: "foo"
errors:
models:
mymodel:
blank: "bar"
here are other errors you can add a locale
https://github.com/rails/rails/blob/3-2-stable/activemodel/lib/active_model/locale/en.yml

You want to use ActiveModel support for validations, as added in Rails 3.
class MyModel
include ActiveModel::Validations
attr_accessor :name
validates :name, presence: true
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
end
Please see these references:
http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/
http://www.rubyinside.com/rails-3-0s-activemodel-how-to-give-ruby-classes-some-activerecord-magic-2937.html
The first link even includes use of an i18n file for errors, as you referenced.

Related

Rails: Form Object not finding I18n on activemodel (namespacing issue)

I have a form object (rails 3) and I am trying to get use config/locales/en.yml for the error messages.
My form object looks like this:
class Users::PasswordAndLoginUpdatingForm
include Virtus.model
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
attribute :requested_email_address, String
validates :requested_email_address, allow_blank: true, format: { with: User::VALID_EMAIL_REGEX }
In my form I have the usual
form_for #form_object ... do |f|
If I pry in and find out what the f.object_name is I get users_password_and_login_updating_form
Finally, my config/locales/en.yml looks like this:
en:
activemodel:
errors:
models:
users_password_and_login_updating_form:
attributes:
requested_email_address:
invalid: "bar"
The issue I'm having is, I cannot get it to use the internationalization.
Well I found out the answer by digging into the source code. The issue I was having that my form object was in a Users::PasswordAndLoginUpdatingForm namespace.
The trick is to use activemodel: as your namespace, but, if you have further namespaces in your models, they're separated with /s.
So, the correct yml looks like this:
en:
activemodel:
errors:
models:
users/password_and_login_updating_form:
attributes:
requested_email_address:
invalid: "foo"
Should it be activerecord: not activemodel: in your config/locales/en.yml file?

Creating a table-less model with validation for registration, don't want to jam multiple models

I have a registration form that has fields from 3 models.
I know you can somehow create a form based on multiple models, but I was thinking of just creating another model for this form and then if validation passes just create the other models by myself.
How can I create a table-less model, I am using Rails 4.1 (latest).
Is this a common practise or should I just learn how to create a form that has 3 models in it?
Rails casts has a sample like:
class Message
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :email, :content
validates_presence_of :name
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_length_of :content, :maximum => 500
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
So what would be a clean way of using this approach? This is what I am thinking so far:
write tests on this tabless model to ensure the validations are how I want them.
when the form posts, verify .valid? is true.
if it is valid, then use the fields to initialize my other models and verify they are all valid.
save all the models
write tests to make sure the tabless-model can correctly initialize the other models so they can be saved correctly.
Any best practises or comments on this approach?
you could look into reform.
using ActiveModel is even easier, make sure to pass the ActiveModel::Lint tests.
other than that, what you described is the way to go.

Localisation of attributes in Rails virtual models

I've created a virtual (non-persistent) model in Rails 3 (see below)
I now need to apply translations to the model but the standard translations locations don't seem to work. e.g.
en:
activerecord:
attributes:
media_upload:
title: "My Title"
I know I can apply this directly to the label with an optional string parameter eg. f.label :title, t('activerecord.attributes.media_upload') but that doesn't work for error messages resulting from validations. Similarly, I could add a key to the translations file for the label helper as suggested in Localise nested virtual attribute in Rails but this also fails to work for the validations.
helpers:
label:
media_upload:
title: "My Title"
Apart from redefining all of the relevant validation messages, is there any other way I can do localisation of attributes in non-persistent models??
A sample model is shown below,
class MediaUpload
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :media_file, :title
validates_presence_of :media_file
validates_presence_of :title
def initialize(attributes = {})
unless attributes.nil?
attributes.each do |name, value|
send("#{name}=", value)
end
end
end
def persisted?
false
end
end
You need write like this:
en:
activemodel:
attributes:
media_upload:
title: "My Title"
not activerecord replace it with activemodel
It seems like you are using simple_form gem for generation of forms.
So following i18n chapter from github your internationalization file should look like this
en:
simple_form:
labels:
media_upload:
media_file: My File
title: My Title
If you are using Rails 4 than there is an easier way to make ActiveModel Form Objects. You can just include ActiveModel::Model like so
class MediaUpload
include ActiveModel::Model
attr_accessor :media_file, :title
validates_presence_of :media_file
validates_presence_of :title
end

Rails Custom Validation Errors using en.yml file

I have a model user_input.rb
class UserInput
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
# attributes
attr_accessor :patientNum, :recordLimit
validates_presence_of :patientNum
validates :patientNum, :numericality => { :only_integer => true, :greater_than_or_equal_to => 0}
def initialize(attributes={})
attributes.each do |name, value|
send("#{name}=",value)
end
end
def persisted?
false
end
end
When I receive error messages I get messages like
"Patientnum is not a number"
I want to change Patientnum to "Patient Number"
My current en.yml file is
en:
hello: "Hello world"
errors:
format: "%{message}"
user_input:
attributes:
patientNum: "Patient Number"
This is tricky for me because my model is not an ActiveRecord::Base
attributes:
patientNum: "Patient ID"
The ActiveModel::Validations uses ActiveModel::Translation to generate the human readable attribute name that is used in the error message.
For your class and attribute names, it will look for the following I18n keys, in this order:
activemodel.attributes.user_input.patientNum
attributes.patientNum
If those aren't found, it will fall back to the default value, which is 'patientNum'.humanize.
See the implementation of ActiveModel::Translation#human_attribute_name for details.

Rails 3: Display validation errors for a form (not saving an ActiveRecord model)

Apologies if this is a really common and/or ridiculous question; I swear I've read over the documentation multiple times and everything seems so focused on ActiveRecord to the point they've wandered off the path of forms that do something other than create or edit model data.
Take for example a form with inputs to control the extraction and display of some statistics. What does rails provide me with for validating the user input of this form, which won't be invoking save on any records? Things like:
:email must be an email address
:num_products must be a positive whole number
:gender must be one of "M" or "F"
:temperature must be between -10 and 120
Etc etc (the sort of stuff that comes standard in most web frameworks)...
Is there something in Rails for me to perform this arbitrary validation and some view helper to display a list of errors, or is everything coupled with ActiveRecord?
Apologies if I've overlooked this in the documentation, but this and this don't really cover it, at least as far as mt weary eyes can tell.
scratches head
Thanks to Rob's answer, here's what I've come up with. I created a utility class (aptly named Validator) which is just embedded into my controllers for anything that needs it.
module MyApp
class Validator
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
def initialize(attributes = {})
super
attributes.each { |n, v| send("#{n}=", v) if respond_to?("#{n}=") }
end
end
end
Now in the controller, for example, just define a little inline-class:
class LoginController < ApplicationController
class AuthenticationValidator < MyApp::Validator
attr_accessor :email
attr_accessor :password
validates_presence_of :email, :message => "E-mail is a required field"
validates_presence_of :password, :message => "Password cannot be blank"
end
def authenticate
if request.post?
#validator = AuthenticationValidator.new(params)
if #validator.valid?
# Do something meaningful
end
end
end
It feels a bit unnecessary to stick every single set of validation rules in their own .rb when the logic is more controller-oriented IMHO. There is probably a more succinct way to write this, but I'm pretty new to Ruby and Rails.
Yes, it can be done fairly easily.
You can use the validations API for it.
As an example, here is a contact us model that I use for an application that is not using ActiveRecord.
class ContactUs
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :email, :subject, :message
validates_presence_of :name, :email, :message, :subject
validates_format_of :email, :with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}\z/
def initialize(attributes=nil)
attributes.each do |name, value|
send("#{name}=", value)
end unless attributes.nil?
end
def persisted?
false
end
end
There is a valid method on model, which triggers validation.
so instead model.save, try model.valid?

Resources