Rails 5... is ALIVE!!!
While Skylight itself supports Rails 5 automatically, we had not yet upgraded the Rails portion of the app on our end until last week. I optimistically volunteered to make the upgrade, thinking it would not take more than a day, maybe two, tops.
Not so much.
For context, although I've been working with Rails for about two years, I have never upgraded a Rails app--only Ember apps. Before I was aware of the rails app:update
command, I tried just updating our version of Rails in the Skylight Gemfile and bundling, which then led me through a series of errors each time I bundle
'd and updated the version of another dependency.
Not long after that, Godfrey told me about rails app:update
and we decided to pair on it so we could go through all the various files that would be updated. After a bit of a Git fail that erased much of my previous work, we were able to get the app back to a pretty good place! If I had known about rails app:update
from the start I think it would have helped a lot - next time I will use it right away for sure!
Even with that, I still had to go through our app as well as a little Rails engine we use for billing and repeatedly upgrade various dependencies by hand, bundle, get an error, upgrade another one, etc. Not the worst thing ever but definitely not fun.
Once everything was seemingly upgraded, we still had to deal with the various and sundry errors that began popping up. One of the first was our use of only
in the context of controllers, like so:
module BlingBling
class CustomersController < BlingBling::ApplicationController
rescue_from ::Stripe::CardError, with: :invalid_card, only: [:update, :update_card]
def show
# stuff
end
def update
# other stuff
end
def update_card
# yet moar stuff
end
private
def invalid_card
render_errors card: "is invalid"
end
end
end
I kept seeing an error telling me that I couldn't use only
there. I couldn't find any documentation or blog posts on the topic but all errors pointed at only
being for filters and nothing else (i.e. before
, after
, around
). After much tweaking and experimentation I went with:
module BlingBling
class CustomersController < BlingBling::ApplicationController
def show
# stuff
end
def update
handle_invalid_card {
# other stuff
}
end
def update_card
handle_invalid_card {
# yet more stuff
}
end
private
def handle_invalid_card
begin
yield
rescue ::Stripe::CardError => error
render_errors card: "is invalid"
end
end
end
end
Update 8/1/2016: After we posted this blog, an intrepid Skylight user/blog-reader posted about this error and brought more information to our attention. It turns out that the original code was broken, the only
keyword never should have worked with rescue_from
, but it failed silently until we upgraded to Rails 5, which started throwing an error where previous Rails versions had not. So previously, rescue_from
was being called on every controller action (ignoring the only
), and I unintentionally fixed a bug by explicitly calling it on the correct controller actions.
Another error I encountered was calling fetch
on an ActiveRecord::Relation (which users.with_inactive
is)... now it needs to be transformed into an array beforehand. For some reason, users.with_inactive
used to respond to fetch
and no longer does.
Previous code:
def owner
users.with_inactive.fetch(0)
end
Now looks like:
def owner
# `user.with_inactive` is an ActiveRecord::Relation so needs
# to be an Array to use `fetch`
users.with_inactive.to_a.fetch(0)
end
Again, couldn't find much on why this changed, but it apparently did, because all of a sudden we were getting an error that we weren't getting before the upgrade. Maybe it was somehow due to a dependency upgrade and not Rails 5, but it's hard to say since it all happened at the same time.
We also discovered that strong params appear to no longer be optional, but required! I couldn't find any documentation on this, but we found that our contact page (one of the few spots where we had not yet moved over to strong params) was suddenly throwing a big error when we tried to send an email using the form.
So we had to move it over from this:
def create
@contact = Contact.new(params[:contact])
end
to this:
def create
@contact = Contact.new(contact_params)
end
private
def contact_params
params.require(:contact).permit(:name, :email, :message)
end
Problem solved!
Our final, and most annoying issue, was related to updating the Intercom gem from 2.4.3 to 3.5.2. This occurred at some point during the initial upgrade process so it took some time for us to recognize that the upgrade was the origin of the issue. We kept seeing crazy errors around our Intercom service that were difficult to understand, until we realized that their API had changed significantly after 3.0 and one of the methods we were using in a pretty integral part of our Intercom service had been removed.
There were enough breaking changes that we ended up going back to the old version that we had before the upgrade (2.4.3). In retrospect, we should have locked down the version of the Intercom gem in our Gemfile, but now we know!
We'll have to deal with this eventually, but it took me long enough to play whack-a-mole with all the sudden errors after the Rails 5 upgrade that it didn't seem like a good use of my time to try and rewrite our Intercom service.
Once the Intercom issue was figured out, the app began running smoothly and we all moved on with our lives! Except for the issue of those pesky deprecation warnings. They're everywhere! Every time we run our test suite or Rails servers we are absolutely flooded with deprecation warnings. We've started tackling them in earnest so that we'll be able to upgrade easily to 5.1, but it's not been totally smooth sailing for us.
But, that's a story for another time! Hopefully your Rails 5 upgrades have been smoother than ours. If I come across any useful tips or tricks during the process of dealing with the deprecation warnings, I'll be sure and share them here!