Rails 5.2, Ruby 2.5.9, serialization and unknown keywords: permitted_classes, aliases

I wrote here few times here about quirks working with older Rails application. For example, upgrading old app to some more up-to-date toolset can be challenging. In my opinion it is best done step by step, so having 4.0 Rails app it is much more challenging to upgrade right to 6.1 will be very hard. So I suggest going step by step. Read release notes for Rails versions and do try to guess what steps are safe for Your application.

Recently I did 4.0 -> 4.2 -> 5.0 -> 5.2 and probably will be 6.1 next in order, but… We are now on 5.2. With Ruby upgraded to 2.5.9 (BTW good table with info which Ruby and Rails are compatible) and Rails in 5.2 I have experienced errors unknown keywords: permitted_classes, aliases. It is related to serialization (some data was stored in ActiveRecord that way using Psych gem. But You can not find Psych on gems list. It is bundled with Ruby and used if not provided with alternative.

So, just add Psych to Your gem file with correct version. Bundled version with 2.5.9 is Psych 3.0.6, using Psych 5.x or 4.x resulted in other problems/errors so I have finally settled with gem 'psych', '~> 3.3'which ended with 3.3.4 installed. Now everything works, I can move with updating app further.

In case you are storing hash with symbols as key, then doing deserialization you may encounter Tried to load unspecified class: Symbol. In that case add to initializers: config.active_record.yaml_column_permitted_classes = [Symbol]

Working with old Rails 2.4 on Ubuntu 20.04

Installing old Rails 2.4 (well, somebody need to maintain that legacy code…) on Ubuntu with Ruby 2.4.10 You can get failure during Nokogirii installation. Log ends with:

compiling xslt_stylesheet.c
 xslt_stylesheet.c:112:13: warning: ‘swallow_superfluous_xml_errors’ defined but not used [-Wunused-function]
   112 | static void swallow_superfluous_xml_errors(void * userdata, xmlErrorPtr error, …)
       |             ^~~~~~~~~~
 cc1: warning: unrecognized command line option ‘-Wno-self-assign’
 cc1: warning: unrecognized command line option ‘-Wno-constant-logical-operand’
 cc1: warning: unrecognized command line option ‘-Wno-parentheses-equality’
 linking shared-object nokogiri/nokogiri.so
 Cleaning files only used during build.
 rm -rf /home/viciu/.rvm/gems/ruby-2.4.10@rails42/gems/nokogiri-1.10.10/ext/nokogiri/tmp/x86_64-pc-linux-gnu/ports
 rm -rf /home/viciu/.rvm/gems/ruby-2.4.10@rails42/gems/nokogiri-1.10.10/ports
 current directory: /home/viciu/.rvm/gems/ruby-2.4.10@rails42/gems/nokogiri-1.10.10/ext/nokogiri
 make "DESTDIR=" install
 make: /usr/bin/mkdir: Command not found
 make: *** [Makefile:200: .sitearchdir.-.nokogiri.time] Error 127
 make install failed, exit code 2

Simplest fix is to link mkdir in place where make expects to find it (on Ubuntu make is in /bin not /usr/bin):

sudo ln -s /bin/mkdir /usr/bin/mkdir

After that You will could install gem and bundle install will work.

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 ;)