Pass Validation on Form Fields Before Friendly ID Creation - Custom - validation

I currently have two models
Location and Product
I have it configured that when a record is created in my production model, it creates a custom url based on the information it has gather from the location selected during the product creation
extend FriendlyId
friendly_id :slug_candidates, use: :slugged
def should_generate_new_friendly_id?
name_changed? or location_id_changed?
end
def slug_candidates
[
[location.media_type, location.state, location.name, :name, :sku]
]
end
What I am currently testing is when a user decides NOT to fill out those very important fields, for it to throw an error message before creating
validates :name, presence: true
validates :sku, presence: true
validates :location_id, presence: true
What is happening in my case, is that it overlooks that validator and first tries to create the slug. If I remove the custom attributes to the url creation and list as
def slug_candidates
[
[:name, :sku]
]
end
it will work fine, running the field validators first. Assuming because those two are attributes on the given model directly.
Does anyone know why this is happening? I need for the validators to be picked up first since it contains all the relevant information for the url.

Solved
def slug_candidates
if self.location_id.nil?
self.errors.add(:location_id)
else
[
[location.media_type, location.state, location.name, :name, :sku]
]
end
end

Related

RoR: Validation of field through model-level validation

In Ruby on Rails, I have a table called Person. It has a field name. The table already has many rows. Some of them also have name as nil. I am fine with the records that already have nil in the name field but moving forward I want to mandate filling of name field when someone creates a new Person entry. I am using Active Record Validation to implement this:
in app/models/person.rb
class Person < ActiveRecord::Base
validates :name, :presence => true
end
Will this mess up my Person table, since I already have some entries with nil in the name field.
Validate only while creating new entry
validates :name, :presence => true, on::create

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

How to verify if an embedded field changed on before_save?

I am running Ruby 2.1 and Mongoid 5.0 (no Rails).
I want to track on a before_save callback whether or not an embedded field has changed.
I can use the document.attribute_changed? or document.changed methods to check normal fields, but somehow these don't work on relations (embed_one, has_one, etc).
Is there a way of detecting these changes before saving the document?
My model is something like this
class Company
include Mongoid::Document
include Mongoid::Attributes::Dynamic
field :name, type: String
#...
embeds_one :address, class_name: 'Address', inverse_of: :address
#...
before_save :activate_flags
def activate_flags
if self.changes.include? 'address'
#self.changes never includes "address"
end
if self.address_changed?
#This throws an exception
end
end
One example of how I save my document is:
#...
company.address = AddressUtilities.parse address
company.save
#After this, the callback is triggered, but self.changes is empty...
#...
I have read the documentation and Google the hell out of it, but I can't find a solution?
I have found this gem, but it's old and doesn't work with the newer versions of Mongoid. I want to check if there is another way of doing it before considering on trying to fix/pull request the gem...
Adding these two methods to your Model and calling get_embedded_document_changes should provide you an hash with the changes to all its embedded documents:
def get_embedded_document_changes
data = {}
relations.each do |name, relation|
next unless [:embeds_one, :embeds_many].include? relation.macro.to_sym
# only if changes are present
child = send(name.to_sym)
next unless child
next if child.previous_changes.empty?
child_data = get_previous_changes_for_model(child)
data[name] = child_data
end
data
end
def get_previous_changes_for_model(model)
data = {}
model.previous_changes.each do |key, change|
data[key] = {:from => change[0], :to => change[1]}
end
data
end
[ source: https://gist.github.com/derickbailey/1049304 ]

Rails 4: validate a model only on specific action

I want to validate an email object only when I'm actually sending the email and not everytime I'm updating it:
class Email < ActiveRecord::Base
# Runs on every update/save method
validates :body, presence: true
def send_email
# Only run when this method is called
if body.blank?
errors.add :body, "can't be blank"
raise ActiveRecord::InvalidRecord.new(self)
end
update_column(:sent_at, Time.zone.now)
EmailMailer.new_email(self).deliver
end
end
Currently, this code will validate the body on every update, but I only want to validate when the send_email method is called. The reasoning is I want to allow users to save the email without actually sending, and this validation forces them to have a value.
I can manually check the validation in my method, but was wondering if there was a "cleaner" approach to this, something like:
validates :body, presence: true, action: :send_email # does not work, but what I want
Update 2015-08-13 15:30
I have some semi-working code, but would prefer a cleaner solution than what I have:
class Email < ActiveRecord::Base
# remove validate methods
def send_email
errors.add :body, "can't be blank" if body.blank?
# My application has some higher level controller code that handles exceptions.
raise ActiveRecord::InvalidRecord.new(self) if errors.any?
# code execution should be stopped by exception...
end
end

Change priority of Custom validations in rails model

I have implemented validations in a dependent manner, like if start_date format is invalid so i don't want to run other validation on start_date.
validates_format_of :available_start_date, :with => /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}((((\-|\+){1}\d{2}:\d{2}){1})|(z{1}|Z{1}))$/, :message => "must be in the following format: 2011-08-25T00:00:00-04:00"
This checks for a specific format and then i have custom validation methods called from which should run later.
def validate
super
check_offer_dates
end
I have used self.errors["start_date"] to check if the error object contains errors, it should skip the other validations on same parameter if it's not empty.
But the problem is def validate is called first and then the validates_format_of. How can i change this so that the flow can be achieved.
I just ran into a similar problem; this is how I fixed it using a before_save callout:
Not working (validates in wrong order - I want custom validation last):
class Entry < ActiveRecord::Base
validates_uniqueness_of :event_id, :within => :student_id
validate :validate_max_entries_for_discipline
def validate_max_entries_for_discipline
# set validation_failed based on my criteria - you'd have your regex test here
if validation_failed
errors.add(:maximum_entries, "Too many entries here")
end
end
end
Working (using before_save callout):
class Entry < ActiveRecord::Base
before_save :validate_max_entries_for_discipline!
validates_uniqueness_of :event_id, :within => :student_id
def validate_max_entries_for_discipline!
# set validation_failed based on my criteria - you'd have your regex test here
if validation_failed
errors.add(:maximum_entries, "Too many entries here")
return false
end
end
end
Note the changes:
validate_max_entries_for_discipline becomes validate_max_entries_for_discipline!
validation method now returns false on failure
validate validate_max_entries_for_discipline becomes before_save validate_max_entries_for_discipline!

Resources