How we migrated from globalize to hstore_translate
May 24, 2014
As part of an international company (Leadformance), we soon had to deal with some translated contents.
At some point, we wanted to offer our clients to customize the content for several languages.
This means translations stored in the database.
Separated Translations Tables
Back in 2011, when we had to implement this feature, it was obvious that we will go with globalize (we will go with globalize-accessors as well to ease the thing).
This was working pretty fine.
Here is how the model looked like:
Create
To create a record we just had to do:
Or, if we wanted to create several languages in a row:
(Notice that this was generating 3 INSERTs for a single record)
Update
If we wanted to update the translations, the gems handled that for us as well:
includes
To avoid the n+1 queries, we had to put the includes:
Sometimes, we would also wanted to perform some queries directly tied to the translations.
For example, to retrieve all Posts having a title translated in french, we would have done this:
hstore to the rescue
Though, as we are using PostgreSQL, we thought we weren’t using the real potential of it and we could use something even clearer. I’m talking about hstore.
It makes it clearer simply because your fields are now in the same table than your other data.
As per the documentation, the hstore data type is for storing sets of key/value pairs within a single PostgreSQL value.
The great thing with hstore-translate is that it makes the thing really easy to switch from globalize + globalize-accessors to it as there are sharing the same API.
That also means that you cannot use globalize AND hstore-translate at the same time.
The model now looks like this:
We don’t need to setup the accessible locales in the model as it is part of hstore-translate itself.
Create
To create the records, it works exactly the same way than previously but:
Update
It’s now faster as it’s tied to only one table, but it’s also easier to query:
Or even (provided by the gem):
Bonus Point
We can do something like this as well:
Migration
The migration has been really painless thanks to the shared API.
I’ve issued a Pull Request to ease the migration based on what we encountered ourselves.
If you are coming from globalize, you’ll probably have to migrate your data.
If so, here is an example of what we used to make it happen.
Conclusion
We are really happy about this choice to change our translation mechanism.
It reduces the overhead of having the data related to a single record shared across several tables.
We are now able to provide to our clients more fields to translate and this is possible without impacting the performances.