Rails Context without Context & Callback / Validation Conditions

Kevin Liebholz
Nerd For Tech
Published in
3 min readJan 6, 2021

--

When you’re getting more and more into Rails or any other framework, there is a time when you think that the default is not what you need. This happened to me in that case in Ruby on Rails.

Let me raise my case:

The app I was working on had two production apps running on Heroku. Both apps automatically deploy from the same Github repo after CI was passed. Unfortunately, on one of the apps, there had to be one very small difference within one model. However, they had to still stay synchronized in the future for every code change, except for this little difference and the database, of course.

How should this one app do something different from the other when they have to have the same code behind the scene?

Quickly, I found that the difference I could use is the URL. I needed to validate a model and call a callback upon it, if the user was on a certain domain.

As an initial thought, I put out something like this:

That was too easy of course, already thinking that you cannot access the domain name while being in the model, on the server…

Rails` Validation Context

Going on search, I found Rails actually has native support for context! I just have to give the context when I save `my_model` in the controller, and I could use it like that:

Looks good, right? Okay, what happened here? Within the controller, I check if the user is on the correct URL by checking the request. If the user is, I save the model by forwarding a context. This context can then be accessed within the model so that the validation is only called when the corresponding context is given.

So far so good! But damn, this can’t be used on callbacks, and if you have different validations for different contexts, your “if-statement” when saving with a context can get quite long.

The PORO (plain old ruby object) Way

We’re still coding ruby, right? In the end, a Rails model is nothing else but a PORO with some Rails magic in it. Let’s use that!

We can simply give a non-database instance variable to the model and use that to check if the validation/callback should run. This way, of course, this variable will not be written into the database, but we don’t need it there, as it is just some context, right?

Let’s PORO it up:

What we’re doing here is quite basic in the end. After getting the permitted params from the form in the front-end, which, in the end, is just a hash, we add another key-value pair on_my_domain: on_my_domain? that resolves to either on_my_domain: true or on_my_domain: false . This will add our context instance variable using the attr_writer to the model’s instance. We can access that using @on_my_domain , or in our case via on_my_domain? . The validations, callbacks, and everything else can now use that information!

Awesome, right?!

Just keep in mind, once the instance is gone, the “context” will also be gone.

Make it more Railsy

With all the above, it is already working perfectly fine! In a bigger app, though, it might be interesting to use such a context variable in various controllers and for different models. Fortunately, we’re talking about Rails here, so relax :)

We can put our frontend check into a helper, so it can be used within several controllers like that:

Let’s finish it up and write a concern, so that every single model that needs it, can use our context variable:

That’s it!
I hope that this helps you. Have a great one :)

--

--

Kevin Liebholz
Nerd For Tech

Creator, strategist, and full stack developer. Passionate about using tech to create a sustainable future.