Rails – skip validation in inherited classes.

Doing refactor in one of my applications I had to change behavior of single model. Since that was not total rewrite but just workflow change and I wanted to do A/B tests I needed both versions working.

Instead of writing completely new model I opted for using class inherited from old version. New class should have some additional behavior compared to previous version, so that approach made sense for me.

I ran on problem with validations. On old model validation was done in single step – object was in state ‘not ready’ and until it was completed part of validations was not run. When it was in ‘ready state’ then validations were enabled. Problem was that in new behavior, object building should be done in two steps. Normally that is not problem, since part of validations can be run from one stage and part can be run when other condition is present.

Since I have chosen inheritance, old, one-step validation was present in child model. I had to remove this one-step validation and add new. So there is how it can be done (Rails 4.2):

First, You need to know what kind of validator it is. In my case it was attribute presence validator for :address. Such validator is ActiveRecord::Validations::PresenceValidator. In case You don’t know exactly where to find it, You can always check all validators in given object. Just create object instance in console, and pretty print object._validate_callbacks. Then find “Your” validator and it’s attributes. Having that info (class and attributes) add to Your model:

old_validator = _validate_callbacks.find do |c|
    c.filter.is_a?(ActiveRecord::Validations::PresenceValidator) &&
        c.filter.instance_variable_get(:@attributes) == [:address]
  end.filter
  skip_callback :validate, old_validator

Replace validator class and attribute name in check to matching Your case.

Sentry Ruby client and silence…

Sentry is great tool for monitoring Rails applications, we use it on Nettigo. But… when Raven, Sentry Ruby client starts it writes something like Raven ready to catch errors. It is a bit annoying. Every log file is full of this crap. There is no documentation of it, but if You look inside code, You will find report_status function, responsible for this mess. First line is:

return if configuration.silence_ready

Hallelujah! Just add to Your Raven.configure do |config| block this line:

  config.silence_ready = true

To silence that message.

BTW – long time no word from me. Maybe, just maybe it will be more posts in future.

Shell rules

Recently in Nettigo I’m busy with learning Chef. Oh, we are small company (in terms of number of servers), so, when finally I had some practice witch Chef I stated I don’t need it :) At least, as full-blown tool, with knife, Chef server (both self hosted and as service).

What I find useful is Chef in local mode, Capistrano and Kitchen. At least this is what I found interesting for me. My goal is not to get fully automated server provisioning, deployment and configuration. I need reliable way to do deployments in repeatable way. I’m moving my application to new server and planning for some microservices inside. This is meant for me to be more reliable deployment way than old – write down all steps when I did created production environment.

Ok, this only a background for this one liner in shell:

tm=30;a=`du -sk|cut -f 1`;sleep $tm;b=`du -sk|cut -f 1`;let c=\(b-a\)/tm;echo $c

I’m deploying my web application once to VirtualBox and sometimes to real server. When creating my Rails application, I need to restore all downaloadable content like images, datasheets, etc. If I do deploy to VirutalBox instance fastest way is to copy it from backup on my laptop. When I do deploy to host in Internet to use data from backup stored on other server. To speed up downloading I have tested different network options (doesn’t matter what one). I needed way to compare how fast are data downloaded. Data downloaded are different files copied from different locations in background. So I did simple ‘oneliner’ shown above to calculate how much data was downloaded and saved to disk in given time and calculate speed in kB/s. Looks ugly, but anybody who remember Perl can not say that ;)

When will_paginate renders strange URLs after Rails upgrade to 3.2

To be honest I didn’t expect I will write again here at this blog. But good news I did manage to find some time to write!

Since 2011 I’m not freelancing anymore, but all the time I use Rails in Nettigo. Codebase used there has it’s roots in Rails 1.2 or even earlier release – first migrations have not timestamps at beginning of filename but numbers, this change was introduced at Rails 2.1. In other words there was a few upgrades in live of this application, and there will be some in future ;) Some upgrades were easy but sometimes You can encounter problems which looks strange and after few hours debugging You have still no idea what is going on :)

Right now I’m in upgrade process from Rails 3.1 to 3.2. It went quite smooth (or at least I think so, since I have not deployed to production environment :) it yet) with one exception – will_paginate have started generating wrong URLs. For example on main page instead of just adding page parameter it have changed path to /about?page=2&controller=Public/products. It looked strange since root was defined, links with link_to were generated for it, page was displayed, but when will_paginate called url_for, it returned garbage – redirecting to About page instead of keeping original URL.

To keep long story short (as usual best solution is to leave code, get some sleep and see at problem again with fresh mind), this diff illustrates what was a cause:

Root was served from controller in namespace (module Public), and with change in routing engine (Rails 3.2 introduced new one) capital letter did the difference.

Passing current user id to Rails models

Long time since last post, isn’t it? Well, I’m completely busy with my work in Nettigo, selling Arduinos and other nice gears :) I do not do gigs anymore, so there is a lot less reasons to write about Rails.

But I still use this framework, since my backend software is written in Rails, so here is one thing which I think can be useful for You.

Often we want to pass ID of current user to Rails model internals. Most answers are don’t do that, this is controller work to do authorization stuff, MVC is to prevent such thins, etc.

here was not related picture (as usual on this blog). Some readers were complaining it was not only unrelated but even offending. Well, maybe they were right, so, I have removed that picture.

Yeah, right, but what if we want to keep some kind of audit trail what is happening with given model? This is not authorization, just who done what.

Since in my application case audit records are created in observers simple passing user id as some additional parameter is no go for me – I don’t want to change interface just to pass user info, that breaks too much things.

So, I have chosen this approach:

def with_user user, &block
  if user.blank?
    yield
  else
    Thread.current[:user] = user.id
    yield
    Thread.current[:user] = nil
  end
end

And each operation I want to track I invoke:

with_user(current_user) do
 model.do_some_stuff
end

Thread.current acts as a hash accessible in current thread and allow us to pass some info skipping MVC isolation (You wanted that, right? :) )

In observers I can access user ID and store it with record. If it is not present, audit trails is being marked as created by System. That means probably cron job, or console action (well on console I can run code inside with_user block when needed).

This is safe as long each request is being processed in single thread and we make sure that user ID will be cleared after our operation. When ID will stay in Thread.current, next request being processed by this Rails app instance will have access to that value and wrong audit records will be created.

Code has to be updated, since any exception will occur inside block, code after yield will be skipped and user ID won’t be erased from Thread.current. Here it is, final version:

def with_user user, &block
  if user.blank?
    yield
  else
    Thread.current[:user] = user.id

    begin
      yield
    ensure
      Thread.current[:user] = nil
    end
  end
end

Code inside ensure will be executed each time – both when exception was raised and when execution was clean.