Search code examples
ruby-on-railsrubyserializationrails-upgrade

Serialise hash with dates as YAML rails


TL;DR: Rails 5.1, Ruby 2.4.0 is serialising a hash including Time objects with quotes around the string representation of the time. These quotes weren't there in Rails 2.3, Ruby 1.8.7 and break my app; how do I get rid of them?

Context and details

I'm upgrading an app from Rails 2.3, Ruby 1.8.7 to Rails 5.1, Ruby 2.4.0. I have a ReportService class, which has a report_params constructor argument which takes a hash. Upon creation of these objects, this hash gets serialised in YAML format.

class ReportService < ApplicationRecord
  # irrelevant AR associations omitted
   serialize :report_params
   serialize :output_urls
end

A user submits a form containing details of a report they want to be run, including a string that gets parsed using Time.parse(), which gets passed as a constructor argument; so the code (in procedural form to strip out irrelevant details, with lots of extraneous stuff ommitted) looks like

offset = customer.timezone.nil? ? '+0000' : customer.timezone.formatted_offset(:time => start_date)
params[:date_from] = Time.parse("#{start_date} #{params[:hour_from]}:{params[:min_from]} #{offset}").utc.strftime('%Y-%m-%d %H:%M:%S')
report_args = {...
                report_params: { ...
                                 date: params[:date_from]
                               }
               }
ReportService.create(report_args)

When I look in my MYSQL database, I find that my report_params field looks like ... date_from: '2017-12-27 00:00:00' .... The corresponding code in the old version produces a result that looks like ... date_from: 2017-12-27 00:00:00 .... This is a bad thing, because the YAML in that field is getting parsed by a (legacy) Java app that polls the database to check for new entries, and the quotes seem to break that deserialisation (throwing java.lang.Exception: BaseProperties.getdate()); if I manually edit the field to remove the quotes, the app works as expected. How can I prevent these quotation marks from being added?


Solution

  • Rails5.1/Ruby2.4 do it correct, since 2017-12-27 00:00:00 is not a valid yaml value.

    The good thing is serialize accepts two parameters, the second one being a serializer class.

    So, all you need to do is:

    class ReportService < ApplicationRecord
      # irrelevant AR associations omitted
       serialize :report_params, MyYaml
       serialize :output_urls, MyYaml
    end
    

    and implement MyYaml, delegating everything, save for date/time to YAML and producing whatever you need for them.

    The above is valid for any format of serialized data, it’s completely format-agnostic. Examples.