Tag Archives: rails

Updating web app from Rails 4 to Rails 7

A few months ago, certbot gave me the warning “Your system is not supported by certbot-auto anymore.”. With my Rails 4 app running on old Ubuntu 14.04, it was time to update the app & environment.

Since I’m using Digital Ocean’s droplets, it was easy to spin up a new droplet, setup the new droplet, and then destroy the old droplet. This is way better than operating in situ.

This blog post will provide a high level overview of update steps & pitfalls encountered.

  1. Spin up a Ruby on Rails (v7.0.4.2, OS Ubuntu 22.04) droplet https://marketplace.digitalocean.com/apps/ruby-on-rails This also involved setting up a SSH key to access the new droplet server.

  2. Exfiltrate the example Rails 7 app from the server to my local machine scp -r root@{SERVER_IP}:/home/rails/example .

  3. Create a new private GitHub repo for this example Rails 7 app

  4. Run the new example Rails 7 app locally This step should be super simple, but it was not. Getting RVM to run Ruby 3.2.0 with OpenSSL was not trivial on my Intel Mac. Here’s what I ran to setup Ruby 3.2.0 locally:

    sudo -i
    cd /usr/local/src
    curl -O https://www.openssl.org/source/openssl-1.0.2t.tar.gz
    tar xzf openssl-1.0.2t.tar.gz
    cd openssl-1.0.2t
    ./Configure darwin64-x86_64-cc
    make
    make install

    rvm reinstall 3.2.0 --with-openssl-dir=/usr/local/ssl

  5. In the new Rails 7 app, I moved my psql DB migrations over by hand. I copied the files and had to update the ActiveRecord::Migration with ActiveRecord::Migration[7.0].

  6. Draw the rest of the owl. I had to port lots of Rails files over from my Rails 4 to the target Rails 7 app.

    I ran into an issue with a model validation callback. To fix my issue, I created a migration to add uniqueness validation at the postgres layer and removed the uniqueness check in my model.

    This also include various site fixes. Such as Open Street Map tiles, using 3rd party APIs, and Font Awesome icons.

  7. Setup deployment to the server using Capistrano.

    Setting up Capistrano with Puma on Digital Ocean was not trivial at all. I followed this guide by Matthew Hoelter https://www.matthewhoelter.com/2020/11/10/deploying-ruby-on-rails-for-ubuntu-2004.html

    In my config/deploy.rb file, I had to add this set :branch, :main

    In my root Capfile, I had to use install_plugin Capistrano::Puma::Systemd due to using Puma 5.6.5.

    After a ton of trial and error, I had setup my nginx config at /etc/nginx/sites-available/rails.

    There was a ton of issues with the .sock file from Puma not getting generated.

    Setting up the secret_key_base is a newer Rails convention. Luckily Matthew’s blog post goes into detail on how to set it up in /etc/environment

    Using systemctl, I got puma setup to run the command bundle exec puma -C /home/rails/apps/[APP_NAME]/shared/puma.rb.

    Also, due to running on Digital Ocean, I had to update permissions for the rails user. cd /home; chmod o=rx rails. See Stack Overflow for details https://stackoverflow.com/questions/70028324/nginx-permission-denied-accessing-puma-socket-that-does-exist-in-the-correct-loc Without running this, I was getting a 502 (Bad Gateway) error, even though everything else was setup. I can see traffic in my nginx.access.log, but I was still getting the 502 (before running this command).

  8. Move psql data over. This step is going to vary a lot on your setup. I was able to run pg_dump to export my data and import data using psql APP_NAME_production < latest_pg_dump.sql.

  9. Update A record. In order to point my domain to my new droplet, I went into Digital Ocean and updated the A record from my old IP to my new IP. This is going to vary depending who you’re using for domain names.

  10. Run certbot. Running certbot for SSL was super easy. https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal

  11. Destroy old droplet. When you’ve verified everything is working with your new Rails 7 app, you can destroy the old droplet in Digital Ocean.

My app, GeoGraph, is now running on Rails 7 and lets anyone bookmark their location.

Optimizing for stable tools that don’t create perpetual work

Time is an incredibly important asset.

I come from a Ruby on Rails background. The progress of Rails updates & JS frameworks has been amazing & constant. Each new Rails patch brings with it some work to stay current. It’s not Rails’s fault since there are always new features or security issues that arise. Having a well maintained framework, such as Rails, is a huge boon for the community.

With any programmer tool, you generally want to be on the current stable release (for a variety of reasons including security & bug fixes). The issue is that upgrading to the latest stable version creates a never ending stream of (hopefully small) work.

Even if you went without a framework (Rails, Django, etc.), your server is running on a suite of tools. You’ll need to keep your OS (even LTS) and most likely nginx up to date.

Perhaps you want to outsource server maintenance, so you’re using Heroku. You’ll have to keep your configs compliant with the Heroku deployment framework & best practices.

What I’m getting at is that there are so many incredible tools available to developers today. Oftentimes, these tools are free and constantly get better & faster over time.

I’m wondering if there is, or if it would be possible to create developer tools that are optimized for API stability. No more figuring how to do things the framework-way every several months. Setup once, use forever. When you’re able to minimize the present value amount of time spent maintaining a tool, you’re freeing your future self to work on higher value tasks.

Misc Rails Integration Test Tips

I attended an Automated Testing meetup yesterday. In my experience, integration tests turn your speedy test suite into a slowpoke. Here are some different tips and gems to consider using in your tests:

  • rack_session_access Gem
    Instead of making a user log in with capybara, why not set the user_id in the session. This gem sounds amazing.
  • fuubar Gem
    Another way to format your test results. Perhaps you’d like to use a progress slider.
  • rspec-retry Gem
    If a test does not pass on the first try, you can run it again until it passes. This feels like a code smell. In the meetup, the speaker mentioned that they were running their tests against live web requests (instead of pre-recorded requests).
  • Page Objects
    Capybara syntax seems procedural since you are telling it to visit a path and click on things. With page objects, you can have DRY code that abstracts away all the step by step page interactions with something like [cci]ProjectPageObject.create[/cci]
  • View Tests
    Instead of doing full blown integration (feature) testing that uses a browser, you can try view tests that assert things are found on your page.

Hopefully you can use some of these tips to improve your test suite.