Rails 4 validation message: removes "_id" from message - validation

# model.rb
validates :employee_id, presence: true, uniqueness: true
When left empty, the error message says "Employee can't be blank" when I want it to say "Employee ID can't be blank".
I resolved this by:
# model.rb
validates :employee_id, presence: { message: " ID can't be blank" }, uniqueness: true
which outputs "Employee ID can' be blank".
However, this isn't a really good solution IMO. I would like some means of customizing the entire message, including the attribute prefix.
Is there a simple way to do this?

There are several "correct" ways to go about this, but you definitely shouldn't do it via the validation itself, or by defining your own validation method.
On a model-by-model level, this is controlled by the class-level human_attribute_name method.
If you want your model's employee_id field to be a special case where the _id postfix isn't truncated, define that special case by overridding human_attribute_name:
class MyModel
validates :employee_id, presence: true
def self.human_attribute_name(attr, options = {})
attr == :employee_id ? 'Employee ID' : super
end
end
In broader terms, you can redefine human_attribute_name on ActiveRecord::Base to override handling of all _id attributes, but I doubt you want to do this. Generally, it's a good thing that Rails drops the _id postfix.
The second (and probably better) mechanism is to simply rely on localization. ActiveRecord ties into your locale YAML files for just about everything. If you want your employee_id field to humanize to Employee ID regardless of language, you'll need to edit your YAML files.
# config/locales/en.yml
en:
activerecord:
attributes:
employee_id: "Employee ID"

You can override human_attribute_name and always send default value with id
class MyModel
def self.human_attribute_name(attribute, options = {})
super(attribute, { default: attribute.to_s.humanize(keep_id_suffix: true) } )
end
end

You can write a custom validation. By doing it that way, you get to define the error message inside the validation method.
The relevant section from Rails Guides is here: Performing Custom Validations
Something like:
Class Paystub
validate :employee_id_is_not_blank
def employee_id_is_not_blank
errors[:base] << "Employee must be a part of the record.") if id.blank?
end
end
p = Paystub.create
p.errors.full_messages #=> ["Employee must be a part of the record."]
Section 7.4 in the Rails Guides specified using errors[:base]. Error messages shoveled into :base don't require an attribute to be tied to them.
Update: This is not the right answer. See #meagars answer above.

Related

How to check if value exists in params.permit?

I can't seem to figure out how to accomplish what I am trying to do here on my create method.
What I have right now works if there are no values, the item is deleted. However, if 1 or more param values exist, it passes and is saved. Not what I needed. I need an all or nothing scenario. I want to save only if all the permitted keys have their value. params.permit(:name, :description, :copyright)
Before an entry is saved using organizations.save!, I need to make sure none of the params that are permitted are nil or empty.
I search all over and can't seem to narrow down on an answer to my exact issue.
Here is my code:
class OrganizationsController < ApplicationController
def index
query_params = params.permit(:id, :name,)
if query_params.blank?
organizations = Organization.all
else
organizations = Organization.where(query_params)
end
render json: organizations, root: "organizations"
end
def create
organizations = Organization.new(organization_params)
if organization_params.present?
organizations.delete
else
organizations.save!
render json: organizations
end
end
private
def organization_params
params.permit(:name, :description, :copyright)
end
end
You should add validations to your model.
From your question i understand that you want to save details only if you get values in all the field, if not you don't want to save, right?. If yes, then adding validations to your model will give you what you wanted.
Add the following to your organization model
validates_presence_of :name
validates_presence_of :description
validates_presence_of :copyright
by doing so, the user won't be allowed to save the details unless and until all three fields have some value in it.
There is no need to use delete as the incomplete information will not be saved.
for more and advanced info click here
To check none of the values of organization_params hash is empty, you can do something like this:
organization_params.values.all? { |x| !x.empty? }
or, this:
organization_params.all? { |k,v| !v.empty? }
You can also check if any param value is empty:
organization_params.any? { |k,v| v.empty? }
So, your create method can be re-written as:
def create
organizations = Organization.new(organization_params)
if organization_params.any? { |k,v| v.empty? }
# at least one param is empty, so delete the record
organizations.delete
else
# all the params values are present, so save the record
organizations.save!
render json: organizations
end
end

Why isn't my inclusion validation passing?

This should be a no brainer. I have a Sinatra application with RSpec and, for some reason, my validations are failing with the inclusion validation.
This is my code:
class Employee < ActiveRecord::Base
validates :department, inclusion: { in: w%(Sales, Finance, Marketing) }
end
This is the spec file:
it 'should save a valid employee' do
employee = Employee.new(name: 'Employee One',
email: 'example#gmail.com',
title: 'Software Engineer',
department: 'Sales')
expect(employee).to be_valid
end
This test fails because the department field is not 'included in the list'. This is aggravating because it fails no matter what field I put. Errors like these are usually from something simple.
What am I missing?
%w is a short-cut for building array of strings. I think you are trying to build an array of strings like this:
["Sales", "Finance", "Marketing"]
In that case the correct form of using %w would be:
%w(Sales Finance Marketing)
See this post for more information on %w syntax in Ruby.
Also, look at the Rails Documentation for inclusion where %w is used correctly.
So, to solve your problem, change your Employee class to look like this:
class Employee < ActiveRecord::Base
validates :department, inclusion: { in: %w(Sales Finance Marketing) }
end
It seems that you have a syntax error, I believe w% should be %w.
Your %w syntax is conflicting with your actual list. The %w makes commas not necessary and actually adds them to your list (which is not what you want). Remove them.
%w(Sales, Finance, Marketing)
=> ["Sales,", "Finance,", "Marketing"]
vs
%w(Sales Finance Marketing)
=> ["Sales", "Finance", "Marketing"]

Updating a property set as the key in DataMapper

Is it possible to update a property in DataMapper if :key is set to true?
Say, for example, I have a model set up like this:
class Post
include DataMapper::Resource
property :slug, Text, :unique => true, :key => true
# ...
end
and I made a new instance of this with :slug => "example-post-title".
I tried to update it by accessing the stored
#post = Post.get("example-post-title")
#=> #<Post #slug="example-post-title" ...>
#post.slug = "example-post-title-2"
#=> "example-post-title-2"
#post.save
#=> true
#post = Post.get("example-post-title-2")
#=> nil
but as you can see the slug was never updated. I also tried using the Post#update method:
#post = Post.get("example-post-title")
#=> #<Post #slug="example-post-title" ...>
#post.update(:slug => "example-post-title-2")
#=> true
#post = Post.get("example-post-title-2")
#=> nil
Looking in the database, the index column is not changed by either of these examples. It remains as example-post-title rather than example-post-title-2.
According to the docs, the Post#update method, similar to the Post#save method, should return true if the operation was successful, and false if it was not. It is returning true here, but it's not actually updating the record.
I've searched and searched and can't find anything about it on the Internet. Neither StackOverflow nor the DataMapper rdoc had anything about updating the key.
I know that I can have a unique Serial property and just get instances of Post using the slug (as in, make the Serial property the key instead of the slug), but I'm looking for a way to do it without that, if at all possible.
My hunch is that you can't update a key. According to the doc, they are protected against mass assignment:
Natural Keys are protected against mass-assignment, so their setter= will need to be called individually if you're looking to set them.
They don't talk about updating them but usually in "key => value" stores it is impossible or deprecated to update the key. I'd assume that's the case here as well, even though I can't find any hard evidence to give to you : /

Validate on inclusion within array of options OR be nil

I have a model where I'd like to restrict input for a field to either be nil or fall within a specified array of values. I can get the inclusion part working, but the allow_nil: true bit doesn't seem to work for me:
class Mock::Patient < ActiveRecord::Base
LANGUAGE_OPTIONS = %w[English Spanish French German Chinese Hindi Punjabi]
validates :preferred_language, inclusion: { in: LANGUAGE_OPTIONS }
end
I've tried modifying that last line to things like:
validates :preferred_language, inclusion: { in: LANGUAGE_OPTIONS }, allow_nil: true
But to no avail. What's the simplest way to express this combination of simple inclusion or nil?
the correct form to allow nil to validate while still allowing a limited array of values is the following:
validates :preferred_language, inclusion: { in: LANGUAGE_OPTIONS, allow_nil: true }
notice how the allow_nil option is inside the inclusion option hash
I solved this by making the validates line look like this:
validates :preferred_language, inclusion: { in: LANGUAGE_OPTIONS + [nil] }
This way, I allow nil, but I don't change the constant I use in my view for feeding the collection of select options. I've since also prepended the array with an element '' so I don't have to explicitly include blank in my form input helper.

Best practices for status addition in Rails

I need to add status for an object, and need a hint about the Rails way to do this. Somewhere I've seen status was added into the model, but already lost where it was.
By status, I mean something that tracks about the item state. Like {0: :ORDERED, 1: :CHANGED, 2: :SHIPPED, 3: :ARCHIVED} for order in store. Looks like it needs id that stored in DB, constant or symbol that I could use in code instead of integer id, and one or two human readable messages for UI
There's a couple simple ways to do this. If the names of the statuses are short, I'd do basically what Samy suggested and store them directly in the model. So, in your migration, you'd do
add_column :orders, :status, :string
Then, in your model, you can use the status method to retrieve the status. You'll want to make sure you only store valid statuses, so you the :inclusion validator something like this:
class Order
validates :status, inclusion: { in: %w(ordered changed shipped archived) },
presence: true
end
If the statuses are longer, you can do something very much like the above with a short name for each status, then add an additional method to give you the full status message
class Order
STATUSES = { 'ordered' => 'Order placed',
'changed' => 'A change has been made to the order',
'shipped' => 'The order has been shipped',
'archived' => 'The order has been archived' }
def self.valid_statuses
STATUSES.keys
end
validates :status, inclusion: { in: valid_statuses },
presence: true
def extended_status
STATUSES[status]
end
end
If the problem has some complexity (f.e: lots of states, the object changes its behavior when changing its state...), you could use the gem StateMachine.
MagicFieldNames might be what you are looking for, it has a discriminator type column that you can use for Single Table Inheritance.
If you want simpler, you can use a status column which value can equal ordered, changed, or shipped. You don't even need to create constants in Rails or such a thing.

Resources