ValidationErrors 😱
Because shit happens
This gem helps you keep track of the ActiveRecord validation errors that have been triggered on a model.
It persists them on a validation_errors
database table the following information:
- time of the error
- model name
- model id (if available)
- action (create/update)
- errors.details (hash)
Why?
Validation errors happen. In some applications it might be interesting to keep track of them. This gem has been extracted from various Ruby On Rails apps where I had this need.
If you have a validation error, you want to keep track of it...but how?
- You can use a logger, but then you have to parse the logs to get the information you need. i.e. is not structured.
- You can use an error tracker, like Sentry, but this isn't really an error, is it? If you have many, it might pollute your errors tracker.
- You can use a database table, and that's what this gem does.
This gem will keep track of the errors, and give you all the freedom to query it and extract statistics and make analysis. By analysing from time to time these data, you might found out the following:
- Your UI sucks
- Your validations are too strict
- Your validations are too loose
- Your client-side validations are not working
- Your client-side validations are too loose
- This bullet point list has been generated by copilot
Installation
Install the gem and add it to the application's Gemfile by executing:
$ bundle add validation_errors
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install validation_errors
Usage
Run bin/rails g validation_errors:install
to create the migration.
Stop evil spring, if the generator is not found: spring stop
.
Run bin/rails db:migrate
to create the tables.
The migration will create a validation_errors
table. Check the migration for details.
If you use Scenic it will also generate some useful views.
Manual
You can now manually track errors by calling ValidationErrors.track
:
ValidationErrors.track(your_invalid_model)
An example could be the following:
def create
@user = User.new(user_params)
if @user.save
redirect_to @user
else
ValidationError.track(@user)
render :new
end
end
Yes, this will execute an additional INSERT into your database. Keep it in mind.
ValidationError.track(@model)
will automatically detect if the action is create
or update
.
You can also use a custom action name by calling ValidationError.track(@model, action: 'custom_action')
.
Automatic
You can also track validation errors automatically by adding track_validation_errors
in your model.
class User < ApplicationRecord
track_validation_errors
end
by doing so, validation errors are tracked automatically on each save
, save!
, update
, or update!
call on your model.
Global
You can of course enable it on all you models by specifying it in ApplicationRecord directly:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
track_validation_errors
end
We currently don't support (PR welcome):
- enable globally and disable on a specific model
skip_track_validation_errors
- enable only for specific actions
track_validation_errors only: [:create]
- disable only for specific actions
track_validation_errors except: [:create]
- enable only for bang or non-bang methods
track_validation_errors only_bang: true
,track_validation_errors only_non_bang: true
Query your data
Now that you have installed the gem and started tracking, let's take a look at how the data are persisted and how you can query them.
We store the errors in exactly the same format returned by ActiveRecord errors.details
.
Given a book, that failed to save because of validation errors, you'll get the following:
id | invalid_model_name | invalid_model_id | action | details |
---|---|---|---|---|
1 | Book | 1 | create | { "base" => [{ "error" => "invalid" }], "title" => [{ "error" => "blank" }, {"error" => "invalid"}] } |
The following SQL (Postgres only!) can be used to obtain a flattened view. You can use it in your queries, or create a database view:
select validation_errors.invalid_model_name,
validation_errors.invalid_model_id,
validation_errors.action,
validation_errors.created_at,
json_data.key as error_column,
json_array_elements(json_data.value)->>'error' as error_type
from validation_errors, json_each(validation_errors.details) as json_data
The gem will already create this view for you, if you use Scenic.
The result is the following:
invalid_model_name | invalid_model_id | action | error_column | error_type |
---|---|---|---|---|
Book | 1 | create | base | invalid |
Book | 1 | create | title | blank |
Book | 1 | create | title | invalid |
Let's now check some useful queries:
Count the number of errors per day
select count(*), date(created_at)
from validation_errors
group by date(created_at)
order by date(created_at) desc;
Please use groupdate for more reliable results when grouping by date.
ValidationError.group_by_day(:created_at).count
Count the number of errors per model and attribute
select validation_errors.invalid_model_name,
json_data.key as error_column,
json_array_elements(json_data.value)->>'error' as error_type,
count(*)
from validation_errors,
json_each(validation_errors.details) as json_data
group by 1, 2, 3
order by 4 desc
or, if you have the view above:
select invalid_model_name, error_column, count(*)
from flat_validation_errors
group by 1, 2
FlatValidationError.group(:invalid_model_name, :error_column).count
RailsAdmin integration
We provide here some code samples to integrate the models in RailsAdmin.
This configuration will give you a basic configuration to work with the validation errors efficiently.
config.model "ValidationError" do
list do
include_fields :invalid_model_name, :invalid_model_id, :action, :created_at
field :details, :string do
visible false
searchable true
filterable true
end
end
show do
include_fields :invalid_model_name, :invalid_model_id, :action
field(:created_at)
field(:details) do
formatted_value { "<pre>#{JSON.pretty_generate(bindings[:object].details)}</pre>".html_safe }
end
end
end
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake test
to run the tests.
You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
.
To release a new version, update the version number in version.rb
, and then run bundle exec rake release
,
which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/coorasse/validation_errors. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the ValidationErrors project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.