Notes on upgrading Rails from 3.2 to 4.0
Posted on January 7th, 2015
The upgrade itself is not that hard. The main thing is the change from models protected from mass-assignment to strong parameters in the controllers. The rest is fairly quick and simple.
Here are more detailed notes:
- Strong parameters: Use the gem in 3.2 and move any attr_accessible out of your models. Ensure you added the
config.active_record.whitelist_attributes = false
to your application.rb. The work is mostly moving whatever was attr_accessible in a model to the appropriate controller that creates that model using thepermit
syntax.
All of your mass assignment tests and code disappears. Hopefully your controllers were already doing some checking on valid params. Otherwise, make sure you write loads of tests to transfer your mass assignment restrictions to your controllers. - Tests now have to respect strong parameters requirements so
post :create
andput :update
will no longer work. You’ll have to add valid params in your tests. I recommend just using alet :valid_params { whatever }
with RSpec. - Scopes need lambdas instead of plain where clauses. So look for any
scope :symbol, where(…)
and replace it withscope :symbol, lambda{ where(...) }
. - Regular expressions with $ and ^ now show warnings to be replaced by \z and \A respectively.
- Old
link_to ... :confirm
now have to becomelink_to ..., data: {confirm: …}
- Model queries that ended with
.all
or.sum
have to become either.load
or, mostly, just.to_a
to force loading and use arrays instead of the lazy query. - Many application config changes. Going through
rake rails:upgrade
helps a long way but don’t just let it override your stuff. Ensure you choose diff and verify what should and shouldn’t be overwritten. - Gems that were in an assets group have to move out of it and just be in the main list. You can add
:require => false
after the gem in your Gemfile if you are worried about memory usage in production (as most assets will be precompiled before production). - Parameter filters have their own initializers now (out of application.rb). The rake task should show you that.
- Routes no longer can use
match
. Replace byget
,post
,patch
ordelete
. - The validation options
:presence => true
and:allow_blank => true
don’t really play well together anymore. If you require presence, it cannot be blank. Otherwise change your require presence to be conditional (and your allow blank too). Something along the lines ofvalidate :name, :presence => { :if => lambda {|m| model.condition? } }, :allow_blank => { :if => lambda {|m| m.condition?} }
.