how to show other attribute in active record validation messsage - ruby

I was using ActiveRecord validations, with custom error messages.The problem I came across is I want to show one more attribute in the error message. For example following code only shows value on which validation is running.
class Coffee < ActiveRecord::Base
validates :size, inclusion: { in: %w(small medium large),
message: "%{value} is not a valid size" }
end
Can I also show type(assuming type is a field in Coffee table), following both attempts doesn't work:
class Coffee < ActiveRecord::Base
validates :size, inclusion: { in: %w(small medium large),
message: "%{value} is not a valid size for type: %{type}" } #`method_missing': undefined local variable or method `type'
message: "%{value} is not a valid size for type: #{type}" } #Error: i18n::MissingInterpolationArgument
end
Versions:
ActiveRecord: 3.1.6
Ruby: ruby-1.9.3-p429

You can use lambda like this
class Coffee < ActiveRecord::Base
validates :size, inclusion: { in: %w(small medium large), :message=> lambda { |e| "#{e.size} is not a valid size for type #{e.type}"}
end

You can do this with a custom validation
class Coffee < ActiveRecord::Base
validate :size_for_type
def size_for_type
unless %w(small medium large).include?(size)
errors.add(:size, "%{value} is not a valid size for type: #{type}")
end
end
end

Related

Geocoder doesn't get lat lon on model

I am using the Sinatra ruby framework.I have a delivery model(see below). I am using the geocoder gem with ActiveRecord.
I have the fields latitude and longitude in my schema.
When I use the console to get the Geocode:
Geocoder.search delivery.address
I get the response from the google API.
But it doesn't populate the lat\lon fields. I can't imagine why.
I am using an API key in app.rb like so:
Geocoder.configure(
api_key: ENV['GEOCODER_API_KEY']
)
And I know the key works since I am getting responses for relatively high number of API calls per second.(Without the api key it's a call every 10 sec or so, or it returns an quota error)
This seems like a simple issue, but I can't figure it out. Would appreciate the help.
Delivery.rb
require 'sinatra/shopify-sinatra-app'
require 'geocoder'
# This is the delivery model. It holds all of the data
# associated with the delivery such as the orrder and shop it belongs to .
class Delivery < ActiveRecord::Base
extend Geocoder::Model::ActiveRecord
has_many :delivery_states, dependent: :destroy
belongs_to :shop
belongs_to :fulfillment_service
validates :order_id, uniqueness: true, presence: true
has_one :courier, through: :fulfillment_service
#after_create :add_delivery_state
attr_accessor :latitude, :longitude
#geocoder setup
geocoded_by :address
after_validation :geocode#, :if => lambda{ |obj| obj.address1_changed? || obj.city_changed? || obj.province_changed? || obj.country_changed? }
def address
#check address1 is not a variation of POB
addr = address1 unless address1.match(/(?:P(?:ost(?:al)?)?[\.\-\s]*(?:(?:O(?:ffice)?[\.\-\s]*)?B(?:ox|in|\b|\d)|o(?:ffice|\b)(?:[-\s]*\d)|code)|box[-\s\b]*\d)/i)
[addr, city, province, country].join(',')
end
def add_delivery_state(status=0,ref_number=nil)
if self.delivery_states.count>0
ref_number = self.delivery_states.last.courier_reference unless ref_number
else
ref_number = 0 unless ref_number
end
self.delivery_states<<DeliveryState.new(delivery_status:status,courier_reference:ref_number)
end
def delivery_state
self.delivery_states.last.delivery_status
end
def courier_reference
self.delivery_states.count>0 ? self.delivery_states.last.courier_reference : "0"
end
end

How to conduct Rails model validation witih or condition?

I’m using Rails 4.2.3. I have three fields in my model — name, first_name, and last_name. would like to have a validation rule in my model that causes a save to fail if the “name” field is empty unless either the first_name or last_name field is not empty. SOoI tried
validates_presence_of :name, :unless => !:first_name.empty? or !:last_name.empty?
but this doesn’t work. I get the error below
undefined method `validate' for true:TrueClass
What is the proper way to write the validation rule above?
Everything you need to know is here.
You can write the rule by defining a separate method for it:
class Whatever < ActiveRecord::Base
validates :name, presence: true, unless: :firstname_or_surname?
def firstname_or_surname?
firstname.present? || surname.present?
end
end
Or you can use a Proc to define it inline:
class Whatever < ActiveRecord::Base
validates :name, presence: true,
unless: Proc.new { |a| a.firstname.present? || a.surname.present? }
end

nil value reaching ActiveRecord validation despite correct value passed to constructor

Validation on a model object is failing despite what I think is the correct parameter value being whitelisted in the controller and passed to the model's constructor. What am I doing wrong?
OuterModel has_one Location via locatable. The latter is created using accepts_nested_attributes_for and validates only the :country attribute:
(EDIT: I found the error, it was hidden by code that I initially left out of the code here for simplification. See my answer below)
class OuterModel < Parent
has_one :location, as: locatable
accepts_nested_attributes_for :location
end
class Parent < ActiveRecord::Base
after_create :create_location
end
class Location < ActiveRecord::Base
belongs_to :locatable, polymorphic: true
validates :country, inclusion: {in: ["US", "CA"]}
end
Controller:
class OuterModelsController < ApplicationController
def create
#outer = OuterModel.new(outer_params)
if #outer.save
byebug #debug here
redirect_to outer_path(#outer)
end
end
def outer_params
params.require(:outer).permit(:name, :type,
location_attributes: [:country, :state, :city])
end
end
Using byebug I see the #outer.save call is satisfied, but the nested location object is not persisted because of a validation error:
(byebug) #outer.persisted? #true
(byebug) #outer.location.persisted? #false
(byebug) #outer.location.valid? #false
(byebug) #outer.location.country #nil
(byebug) #outer.id #6372
(byebug) #outer.location.errors
<ActiveModel::Errors:0x007f1f33c1eae0
#base=#<Location id: nil, city: nil, country: nil, state: nil, locatable_id: 6732, locatable_type: "OuterModel", created_at: nil, updated_at: nil>,
#messages={:country=>["is not included in the list"]}>
However, the controller outer_params method appears to be sending the correct hash to OuterModel.new:
{"name"=>"A name",
"type"=>"OuterModel",
"location_attributes"=>{
"city"=>"South Deionview", "country"=>"US", "state"=>"IL"
}
}
Why then is the Location.country value nil after the call to save, and why is validation failing?
EDIT: logfile (much simplified) pastebin here. It seems like the correct values are being sent as part of the SQL
The answer lay in a parent of OuterModel that had an after_create hook to create a Location. Added the parent class to the source above.
The Location object was initially created correctly by accepts_nested_attributes_for (as per all evidence from logging) but then the after_create hook replaced it with an empty Location object that failed validation.

Using validates_with with ruby and mongoid

I'm new to ruby and mongoid. I need to use validates_with and below is the code I have
class ValidatorClass < ActiveModel::Validator
def validate(record)
if record.name == ""
record.errors.add(:name, "An error occurred")
end
end
end
class Person
include Mongoid::Document
include Mongoid::Timestamps::Created
include Mongoid::Timestamps::Updated
include Mongoid::Versioning
include ActiveModel::Validations
field :id, type: Integer
field :name, type: String
field :age, type: Integer
validates_with ValidatorClass, :on => :create
end
But when I create the model with following code:
Person.create(id: 5, name: "", age: 50)
I don't get the error thrown. I'm not using Rails. I'm using just ruby with mongodb. Could anybody out there help me? Thanks in advance.
From the documentation, can you try adding this line in class Person:
include ActiveModel::Validations
http://api.rubyonrails.org/classes/ActiveModel/Validator.html
You dont have to include ActiveModel::Validations on your class
Try changing your validation class to use the code bellow:
class ValidatorClass < ActiveModel::Validator
def validate(record)
if record.name.blank?
record.errors.add(:name, "An error occurred")
end
end
end
Hope it helps!
Please try this:
class ValidatorClass < ActiveModel::Validator
def validate(record)
if !record.name.present?
record.errors.add(:name, "An error occurred")
end
end
end

Rails3: Nested model - child validates_with method results in "NameError - uninitialized constant [parent]::[child]"

Consider the following parent/child relationship where Parent is 1..n with Kids (only the relevant stuff here)...
class Parent < ActiveRecord::Base
# !EDIT! - was missing this require originally -- was the root cause!
require "Kid"
has_many :kids, :dependent => :destroy, :validate => true
accepts_nested_attributes_for :kids
validates_associated :kids
end
class Kid < ActiveRecord::Base
belongs_to :parent
# for simplicity, assume a single field: #item
validates_presence_of :item, :message => "is expected"
end
The validates_presence_of methods on the Kid model works as expected on validation failure, generating a final string of Item is expected per the custom message attribute supplied.
But if try validates_with, instead...
class Kid < ActiveRecord::Base
belongs_to :parent
validates_with TrivialValidator
end
class TrivialValidator
def validate
if record.item != "good"
record.errors[:base] << "Bad item!"
end
end
end
...Rails returns a NameError - uninitialized constant Parent::Kid error following not only an attempt to create (initial persist) user data, but also when even attempting to build the initial form. Relevant bits from the controller:
def new
#parent = Parent.new
#parent.kids.new # NameError, validates_* methods called within
end
def create
#parent = Parent.new(params[:parent])
#parent.save # NameError, validates_* methods called within
end
The error suggests that somewhere during model name (and perhaps field name?) resolution for error message construction, something has run afoul. But why would it happen for some validates_* methods and not others?
Anybody else hit a wall with this? Is there some ceremony needed here that I've left out in order to make this work, particularly regarding model names?
After a few hours away, and returning fresh -- Was missing require "Kid" in Parent class. Will edit.

Resources