As we already know, in Rails 3 all dependencies will be bundled. This means you will be able to use latest I18n version which includes several improvements by itself.
Besides that, a couple things changed on Rails 3 I18n, some features were added and others were deprecated. This post is a quick walkthrough it:
1) Error messages defaults
With the addition of ActiveModel, it’s easy to add I18n behavior to any object by simply including ActiveModel::Translation and ActiveModel::Validations. As side effect, if we followed the same translation pattern as in Rails 2.3, each ORM would have to specify its default error messages at #{ORM.name}.errors.messages. This means that if you are using two ORMs in your app, you would have to translate the same messages twice.
To handle this situation, error messages now has errors.attributes and errors.messages as fallbacks in case a message cannot be found for an specific ORM. Notice that this also allows you to customize a message for an specific attribute used by models in different ORMs. So if you have several models with title attribute, you can customize the blank message for them all by simply placing it at errors.attributes.title.blank.
2) Attributes default
In the same line as above, you can now specify default attributes across different models and ORMs as well. For example, if you are exposing created_at and updated_at in your views, until Rails 2.3 you needed to specify the same translation for each model. In Rails 3, you can simply do:
en:
attributes:
created_at: "Created at"
updated_at: "Updated at"3) f.submit
f.submit in forms now can be called without arguments and it will inspect the form object to set the proper label. Imagine the following form:
<% form_for @post do |f| %> <%= f.submit %> <% end %>
If @post is a new record, it will use “Create Post” as submit button label, otherwise, it uses “Update Post”. You can customize those labels with I18n under the following keys:
en:
helpers:
submit:
create: "Create a {{model}}"
update: "Confirm changes to {{model}}"Nonetheless, it also searches for keys under the object name key as well:
en:
helpers:
submit:
post:
create: "Add {{model}}"4) Labels with I18n
Labels were also updated to use I18n. Imagine the following form:
<% form_for @post do |f| %> <%= f.label :title %> <%= f.text_field :title %> <%= f.submit %> <% end %>
It will search for a label value at helpers.label.post.title, falling back to the value returned by Post.human_attribute_name(:title). This is useful in case you want more personalized labels instead of just “Title”.
5) Deprecation
Besides those improvements, I18n has two deprecations: the first is the key support.select should now be helpers.select and the other is that AV error messages are now agnostic, so activerecord.errors.template should now be errors.template.
That’s all, enjoy!
Tags: deprecations, i18n, improvements, rails 3
Posted in English | 7 Comments »
This weekend during Rails Bugmash I stumbled across some nice posts about Rails 3 generators which motivated me to share them and add some comments!
First, David Trasbo wrote a nice guide about how to make your first Rails 3 generator, it covers up all the basic steps including setting it up in a gem. He also puts the deserved attention into Thor::Actions, which contains most helpers you need in a generator, like copy_file, template, create_file, empty_directory and so on.
On another post, Ben Scofield talks about apply method, which is also in Thor::Actions, and how to use it to dry your application templates.
Wait… so Thor::Actions is used both in generators and in Rails application templates? Exactly, Rails’ new generators unifies both application templates and generators API into one. While Thor::Actions holds basic methods, all Rails specific methods like environment, rakefile, generator are in Rails::Generators::Actions. If you already wrote an application template, you will feel more at home when writing a Rails 3 generator.
Paul Barry talks how easy it’s to customize your scaffold to use Rspec, Haml and Factory Girl instead of Test::Unit, Erb and Fixtures. This all works because scaffold is just a meta generator which provides hooks for template engine, test framework, ORM and so forth. A good way to see the hooks system working is by running script/generate scaffold --help before and after Paul changes, so you can see exactly how generators options update depending on the configuration values you set. While I wrote Rspec generators used in the example, he implemented himself Haml and Factory Girl generators and they can all be used as example if you plan to build your own.
Finally, Zigzag Chen wrote about templates customization and how you can change your scaffold controller to use json instead of the xml format. New generators have source paths, so you can customize them simply by copying files to RAILS_ROOT/lib/templates.
Rails Bugmash was excellent to gather feedback and we also got some tickets on Lighthouse, mainly about how generators help can be improved for people starting with Rails. Many thanks to Rails Bridge and besides the posts linked above, there is a generator guide, which may help you get started and maybe write your own post as well.
Tags: gems, generators, plugins, rails, ruby, thor
Posted in English | 8 Comments »
2009 se foi. Foram 10 meses muito agitados para nós. Aprendizado intenso, momentos de cansaço físico, desafios constantes e dúvidas sobre o futuro são fatores que estão presentes no nosso dia-a-dia.
Antes de iniciar as operações da Plataforma Tecnologia (fev/09), nos questionávamos duas perguntas que davam frio na barriga:
Como fazer uma empresa de serviços dar certo?!
Como sair da inércia e conquistar os primeiros clientes?!
Não sabíamos as respostas. Mas estávamos lá.
Cada um com suas habilidades e todos com um sentimento que se equilibrava entre arrogância e inocência. Sem motivos muito claros, nós simplesmente acreditávamos que poderia dar certo. Então, por que não tentar?
Aqui estamos: tentando.
É difícil dizer se a Plataforma Tecnologia será bem sucedida ou não. Só o futuro dirá.
O que podemos dizer é que avançamos muito mais do que imaginávamos e acreditamos estar na direção certa. Sabemos onde queremos chegar, mas há inúmeros caminhos para escolher. Uns melhores, outros piores.
Fato é que durante 2009 descobrimos algumas coisas que consideramos valiosas e queremos compartilhar nossa opinião. Seguem abaixo.
- Contrate pessoas cujo trabalho você confia (e vice-versa): se você precisa micro-gerenciar sua equipe, então algo está errado. Micro-gerenciar times de desenvolvimento de software é uma tentativa (ruim) de assegurar a qualidade durante o processo produtivo. É preciso entender que o processo em si não é tão importante. O importante é o resultado final. Dê autonomia a sua equipe. Parta do pressuposto que sua equipe é capaz de atingir os objetivos até que seja provado o contrário (e se o “contrário” ocorrer, há diversas ações que podem ser tomadas, mas isso rende assunto para um outro post inteiro).
- A maioria dos clientes descrevem soluções ao invés de descrever as reais necessidades: é natural que isso ocorra. E ao invés de culpá-los por não saberem descrever corretamente as necessidades, ajude-os a esclarecer qual o problema a ser resolvido. Em seguida, construa com ele uma solução (software).
Não se esqueça que é o seu cliente que tem o conhecimento sobre o segmento/negócio e uma boa solução será resultado de um trabalho conjunto. Se um cliente não se dispuser a trabalhar em conjunto para desenhar uma solução, então caia fora. Este projeto terá grandes chances de ter problemas. - 6 meses é muito tempo para empresas recém-nascidas e pequenas: É importante saber onde se quer chegar, mas nesta fase da empresa, não faz muito sentido realizar planejamentos com horizontes longos. Muita coisa muda e muito rápido.
Descobrimos que vale a pena fazer planejamentos com maior freqüência e com horizontes mais curtos. É como se a cada 6 meses a empresa estivesse realizando um “release”. Faça “retrospectivas”, “release plannings”, “sprint plannings” relativos à empresa e priorize a execução do que trará mais valor durante os próximos 6 meses. A grande vantagem de uma empresa de pequeno porte é sua capacidade de responder à mudanças (agilidade). Aproveite-a! - Nunca haverá momento ideal para implementar algo: já nos pegamos dizendo “assim que der uma sossegada, a gente começa a re-estruturar bla-bla-bla”. A verdade é que este momento de sossego dificilmente chegará, ainda mais se a empresa estiver em crescimento. Se há necessidade em implementar ou mudar algo na empresa, faça-o o quanto antes (ou de acordo com a prioridade). Esperar só vai piorar os sintomas que este problema estiver causando. Quanto mais você esperar, pior será.
- Saiba claramente qual o seu DNA: isso pode soar um pouco filosófico, e de fato é. Mas é algo que se mostrou muito importante para nós. Todo o time deve saber e compartilhar dos valores que moldam as decisões de negócio e refletem na maneira de operar o dia-a-dia da empresa. Pode ocorrer momentos em que fechar um novo contrato significará deixar o DNA de lado e isso será um pouco doloroso.
Mas da nossa experiência, posso afirmar que valeu a pena não se desviar do DNA. Quando olhamos para trás, fica muito claro que tomamos boas decisões. Warren Buffet já dizia… “In the business world, the rear view mirror is always clearer than the windshield“.
É a mais pura verdade!
Espero que estes tópicos possam ajudar startups e outras empresas iniciantes.
Gostaria de pedir que ajudem a enriquecer o post e comentem. Compartilhem suas experiências!
Tags: empreendedorismo, negócios, the plataforma way
Posted in Português | 4 Comments »
A couple days ago DHH twitted that they were getting Basecamp running on Ruby on Rails 3.0.
This means Basecamp migrated from the first Rails release up to the edge one. So how come people say so frequently how hard is to update their applications from Rails 2.1 to Rails 2.2? And the answer is simple: plugins.
Every time you are adding a plugin to your application, you are inserting some hundreds or even thousands of lines of code in your application, without knowing what it does exactly. And sometimes this becomes technical debt, mostly noticeable when you have to update to a new Rails version. And why is that? Because a lot of plugins are monkey patching Rails, so whenever Rails changes its internal API between releases, the plugin breaks.
However, they are two simple actions you could do to improve your application maintainability, your ruby fu and also give a little back to the community.
The first one is easy: check the source code of the plugin you are installing. Does it needs to monkey patch Rails code? Or even worse, Ruby classes? If so, how much? If too much, turn it down. Search for simpler solutions or even start one from scratch with just what you need, it will take more time, but you will learn a lot through the process.
Another very compelling reason is that reading other people’s code is one of the best ways to learn. You will learn new things and probably see a few things which could be done better. And when it happens, write a patch!
Besides, whenever something is going wrong in your application, you will know better where to start searching and you will eventually help plugins authors to track bugs down. And, in the worst scenario, if you have to update the plugin after a Rails release on your own because the plugin creator is no longer interested, you will be more capable to do so.
Some people often choose plugin A because of features X, Y and Z. But whenever they have to add feature W, they are stuck, because the plugin code is a complete spaghetti. And all this time, they could have chosen plugin B, which just has feature X, but adding Y, Z and W would be quite easy. Reading the plugin’s source code is one way to ensure you are prioritizing code quality instead of features count.
And the second step, guess what, is easy too: run the plugin test suite. Really, it will take just a couple minutes. You definitely don’t want to use a plugin where the test suite fails (or which does not have a test suite at all). Imagine that for some reason you need to add features to a plugin, how you will ensure you did not break other thing while doing so? Or even worse, imagine you have to update the plugin for a new Rails release. How can you ensure the plugin works on 3.0 if you cannot even ensure it works on 2.3?!
Some already noted that I have patches applied in different plugins around GitHub. And this is the very reason: I check their code, send simple suggestions whenever it’s possible and most important of all, I choose well which plugins to use. So whenever I need to write a new feature because the application I’m working on needs it, I know it will be easy, since the plugin code is quite well written and test suite is green.
It’s really two small efforts, which gives everyone, including you, a lot back.
Tags: plugins, rails, source code
Posted in English | 1 Comment »
Pratik lately is doing a great work refactoring ActiveRecord to make a full use of relations. Speaking in code language, this means that in Rails 3 you will be able to do:
User.where(:name => "Jose").order("birthday")
And it will return a relation. The relation can be further manipulated and the query is only triggered when you call all, first, to_a or some Enumerator method.
Besides that, he’s also doing some crazy experiments, which will probably become a plugin later. While discussing with Pratik some ways to implement equality and inequality, I discovered a neat ruby trick. Open up an irb session and do:
~2 #=> -3 ~42 #=> -43
And this method is actually documented.
The nice thing though, is that you can define this method in other classes as well. In the querying scenario for example, we could add this behavior:
class Symbol def ~ :"LOWER(#{self})" end end
And now we could actually do:
User.where(~:email => "jose@plataformatec.com.br") #=> SELECT * WHERE LOWER(email) = "jose@plataformatec.com.br"
Unary operators
Yehuda Katz later pointed to me that this can actually be done with any of the three unary operators in Ruby: +, – and ~.
So we could also do:
class String def +@ upcase end def -@ downcase end end
And now:
+"jose" #=> "JOSE" -"JOSE" #=> "jose"
You could even “go crazy” and append several unary operators:
+-+"jose" #=> "JOSE"
And you? Did you know such behavior in Ruby? Do you have any good use case for it?
Tags: operators, ruby, unary
Posted in English | 5 Comments »
A new I18n gem just got released and it comes with two new backends extensions: Fast and InterpolationCompiler.
First, what is a backend?
I18n.t, I18n.translate, I18n.l and I18n.localize methods are actually just wrappers to I18n.backend, which is actually who does all the heavy lifting. This means that you can change your backend to other stuff, as long as it respects the required API.
By default, I18n comes with the Simple backend, but others are available. For example, I18n has an ActiveRecord, which stores translations in the database. This is useful in cases someone needs to change translations through a web interface. To use it, you just need to do:
I18n.backend = I18n::Backend::ActiveRecord
There are a couple other backends, like a backend which implements fallbacks, so if something cannot be found in a specified language, like german (:de), it can fallback to english (:en). You can check the whole list, but for this while, we are going to focus on the two new backends extensions.
Fast
Fast, means fast. And oh, boy, this one is fast. This extension flattens translations to speed up the look up. For example, the following hash { :a => { :b => { :c => :foo } } }, gets flattened to { :"a.b.c" => "foo" }, so instead of recursively looking into hashes, it looks just once. The obvious expense is that whenever you are storing translations, you need to flatten the translation hash, and it takes more time than usual.
In order to measure different backend implementations, I pushed some benchmark setup to the I18n repository. The current setup measures the storage time, the time it takes to translate a key (the depth of the key means how many nested hashes it takes), the time to translate a key falling back to the default key and the time translate a key (at depth 5) and interpolate. The results comparing the Simple backend without and with Fast extension are showed below:
In other words, a simple lookup using the Fast extension is 3 to 4 times faster than the Simple one. Besides, configuring your application to use it is very simple:
I18n::Backend::Simple.send :include, I18n::Backend::Fast
Nice!
Interpolation compiler
The InterpolationCompiler is a backend extension which extracts all required interpolation keys from a string, leaving just the minimum required to runtime. Imagine the following string: "This is a custom blank message for {{model}}: {{attribute}}". This extension annotates the string so it knows that it needs to interpolate both model and attribute, and points exactly where the interpolation should happen. We can compare the Simple backend without and with the InterpolationCompiler below:
The InterpolationCompiler just changes the time taken when we have interpolation keys, without affecting to much the other translations. You can add it to your app as easy as the Fast one:
I18n::Backend::Simple.send :include, I18n::Backend::InterpolationCompiler
Run, I18n, run!
But the best is still coming! Fast and InterpolationCompiler can actually be used together, to achieve unseen performance in I18n. The benchmark speaks for itself:
While we speed up the performance in around four times in simple lookups, Fast and InterpolationCompiler improvements get combined whenever we need to use interpolation, becoming around six times faster!
As said previously, both extensions increase the time taken to store translations as side-effect. Such can be viewed below:
The yaml hash used in for the benchmark, is relatively slow, but it shows how the time taken to store translations grows with such extensions. But remember, you are constantly storing translations only in development (before each request is processed). In production, the translations are stored at startup and that is it.
Using within Rails
You should be able to use such features today in Rails 2.3.5 and it will also be possible in Rails 3. You just need to install the I18n gem and configure it in your environment.
Why care?
All the times shown are in miliseconds. In other words, why care? If you are building a simple application, using just one language, those improvements likely won’t change anything. But in an application which relies on I18n, during a request/response lifecycle, I18n is invoked many times: error messages for models, flash messages, page titles, e-mail subjects, page content, date and time localization, pluralization rules and even in many of ActionView helpers. So in such cases, it’s worth to give such extensions a try.
Running benchmarks on your own
If you want to run benchmarks on your own, it’s quite simple. You just need to do:
git clone git://github.com/svenfuchs/i18n.git cd i18n ruby benchmark/run.rb
Credits
The possibility to have backends and such extensions is due to Sven Fuchs, which leading the I18n group quite well.
Many of the backends were added by I18n community, and the Fast and InterpolationCompiler were created by thedarkone.
Guys, I owe you a beer!
Enjoy!
Tags: i18n, performance, plugins, rails
Posted in English | 8 Comments »

All
English only
Em português apenas


