2020

Race Conditions on Rails

Imagine that you are implementing a payment processing system for the e-commerce system and discover that multiple customers were charged twice for exactly the same order. Ouch… Sounds like a real nightmare to deal with! And the next day, you see that something is not right with the credits system in which users were able to pay using special credits instead of using credit card - somehow instead of getting charged $100 in total for two orders of $25 and $75, they were charged just 25$! And to make it even more epic, it turned out that the uniqueness validation you added didn’t work at all, and now you have three users with the same email address!

Read on →

2018

The Problems With Validating ActiveRecord Models And Why State Validation Is a Bad Idea

In the typical Rails application, you can find the most of the validations in the ActiveRecord models, which is nothing surprising - ActiveRecord models are used for multiple things. Whether it is a good thing, or a bad thing (in most cases it’s the latter) deserves a separate book or at least blog post-series as it’s not a simple problem, there is one specific thing that can cause a lot of issues that are difficult to solve and go beyond design decisions and ease of maintenance of the application, something that impacts the behavior of the model - the validations.

Read on →

Rails And Conditional Validations In Models

Adding consents for accepting Terms of Service/Privacy Policies must have been a top popular feature in the majority of the applications due to enforcement of GDPR in May ;). From the technical aspects that GDPR requires, there is a proof of consent for processing the personal information. In that case, you need to have some actual attributes in the database that would confirm the fact that some user has indeed accepted Terms of Service/Privacy Policy.

Read on →

The Case for before_validation callback: complex state normalization

Few months ago I wrote a blog post about ActiveRecord before_validation callback and how it is used for wrong reasons and concluded that in most cases this is not something we should be using routinely. However, I missed one appropriate use case for it which might be quite common in Rails apps, so this might be an excellent opportunity to get back to before_validation callback and show its other side.

Read on →

2017

The Case Against Exotic Usage of :before_validate Callbacks

It’s nothing new that ActiveRecord callbacks are abused in many projects and used for the wrong reasons for many use cases where they can be easily avoided in favor of a much better alternative, like service objects. There is one callback though that is special and quite often used for pretty exotic reasons that have nothing to do with the process when it gets executed - it’s the before_validate callback.

Read on →

2016

Introduction to ActiveRecord and ActiveModel Attributes API

Rails 5.0 is without a doubt a great release with plenty of useful changes and additions. The most notable change was probably ActionCable - the layer responsible for integrating your app with websockets. However, there were also other additions that could bring some substantial improvements to your Rails apps, but were a bit outshined by bigger changes. One of such features is Attributes API.

Read on →

Keeping Data Integrity In Check: Conditional Unique Indexes For Soft Delete

Soft delete is a pretty common feature in most of the applications. It may increase complexity of the queries, nevertheless, not deleting anything might be a right default as the data might prove to be useful in the future: for restoring if a record was removed by mistake, to derive some conclusions based on statistics and plenty of other purposes. It may seem like it's a pretty trivial thing: just adding a column like deleted_at and filtering out records that have this value present. But what happens when you need to do some proper uniqueness validation on both model layer and database level? Let's take a look what kind of problem can easily be overlooked and how it can be solved with a conditional index.

Read on →

When validation is not enough: PostgreSQL triggers for data integrity

Is validation in your models or form objects enough to ensure integrity of the data? Well, seems like you can't really persist a record when the data is not valid unless you intentionally try to bypass validation using save: false option when calling save or using update_column. What about uniqueness validation? A classic example would be a unique email per user. To make sure the email is truly unique we could add a unique index in database - not only would it prevent saving non-unique users when bypassing validation, but also it would raise extra error when 2 concurrent requests would attempt to save user with the same email. However, some validations are more complex that ensuring a value is unique and index won't really help much. Fortunately, PostgreSQL is powerful enough to provide a perfect solution to such problem. Time to meet your new friend: PostgreSQL triggers.

Read on →

PostgreSQL In Action: Sorting With NULLIF Expression

Ordering with ActiveRecord and PostgreSQL may seem like an obvious and simple thing: in most cases you just specify one or several criteria with direction of ordering like order(name: :asc) and that's all, maybe in more complex scenarios you would need to use CASE statement to provide some more customized conditions. But how could we approach sorting with forcing blank values to be the last ones, regardless of the direction of the sort? You might be thinking now about NULLS LAST statement for this purpose, but that's not going to handle empty string. For this case you need something special: time to meet NULLIF conditional expression.

Read on →