Validations that need to access an associated object may lead to some trouble. Let's exemplify that using this example:
class Project < ActiveRecord::Base
has_one :note
end
class Note < ActiveRecord::Base
belongs_to :project
end
Now say we need a validation that ensures that a description is set (validates_presence_of :description) within Note
but only if the Project
has a flag called external
set to true. The following code will lead to some problems as the associated object is not present when creating a new Project
.
class Note < ActiveRecord::Base
validates_presence_of :description, :if => Proc.new { |note| note.project.description.present? }
...
This does not work when creating a new Project
as the project is not yet associated to the note.
The solution is to use the trait attached and use it for Note
the way
our traits in Ruby
Show archive.org snapshot
are used:
class Note < ActiveRecord::Base
does 'sticky_errors'
...
Additionally you add the conditions for the validation to the parent class like this:
class Project < ActiveRecord::Base
before_validation :ensure_description_present_for_external_notes
def ensure_description_present_for_external_notes
if note && note.description.blank? && external?
note.add_sticky_error_on(:description, '^You need some description, honey!')
end
end
The trait will evaluate the error added by using add_sticky_error_on()
.