Tips and tricks for developing Rails applications on Apple Silicon

At Discourse we have been experimenting recently with getting our whole stack running natively on Apple’s new M1 machines. In the last few weeks things have come together and there are now a few of us using this setup for day-to-day development, with great results!

The vast majority of credit here goes to the Homebrew and Ruby teams - most stuff now ‘just works’ :heart_eyes:. The only changes we had to make at Discourse were to a few of our gems which had bundled binaries.

To summarise, in case anyone else would like to try it out:

  1. Install Homebrew using their default configuration. If you already installed Homebrew under Rosetta, you’ll need to uninstall and reinstall the arm64 version

  2. brew install redis, brew install postgres

  3. brew services start redis, brew services start postgres

  4. brew install ruby@2.7

    (follow the provided instructions to add it to your PATH, and restart the shell)

  5. ruby --version should now show the architecture as arm64-darwin20

  6. git clone https://github.com/discourse/discourse

  7. Update mini_racer line in Discourse’s Gemfile to point to this experimental branch

    gem 'mini_racer', github: 'rubyjs/mini_racer', branch: 'refs/pull/186/head'
    
  8. bundle install

  9. bin/rake db:create db:migrate

  10. bin/rails s

  11. Visit localhost:3000 :tada:

I’m sure that general idea will apply to most Rails apps.

In terms of performance, developing on M1 machines feels a lot faster than previous Intel MacBooks. We have some benchmarks which we use to compare development performance for Discourse. In most of the single-core CPU-bound tests, the M1 sits right up amongst latest-gen-cpu Linux desktops.

For multi-core workloads it’s respectable, although not quite matching those high-end desktops. Unfortunately for filesystem-based tasks we still seem to be plagued by the issues described in this topic, but the other performance gains do help to mitigate that.

As for ‘tips and tricks’, here are a few things that have been helpful to me:

  • If you’re ever unsure whether things are running natively, or under Rosetta, you can check the ‘Architecture’ column in Activity Monitor:

  • If you test/deploy your Rails applications in Docker, then they have a tech preview for M1 which has worked great for me. The only gotcha is that it will default to arm64 architecture, which might not be what you want, especially if you’re building an image to be deployed in production.

    This default can be changed using the --platform flag on a docker command, or via an environment variable DOCKER_DEFAULT_PLATFORM=linux/amd64

I’d be interested to know how many other people are developing Rails apps on M1. Have you seen performance gains? Any tips / tricks / gotchas to add?

24 Likes

Which editor(s) are you using?

1 Like

I’ve been using the VSCode Insiders Build, which has ARM64 support.

3 Likes

I’ve also been using M1 for about a month. I’m quite impressed how almost everything is already working. Rbenv’s build requires minor tweaks to compile.

A few caveats I found was that if you’re using the regular VS Code (not the insiders version), it’s better to run your system tests from macOS’ Terminal, rather than the VS Code Terminal or the Test Explorer UI. The reason is that VS Code doesn’t run natively and as a consequence macOS would spawn each sub process as Intel, even if it provides native binaries - i.e. using Firefox in system tests would start the Intel version which takes 20 seconds to start.

A weird issue I’ve seen is that sometimes my tests would run twice as slow, but more often than not - as fast or faster than on a 2018 Intel MacBook Pro.

4 Likes

In the largest Rails app I’m working on I just had to update the libfii gem as I was getting a strange error:

-    ffi (1.13.1)
+    ffi (1.14.2)

I also installed a second version of Homebrew using iTerm running in Rosetta mode and then doing a git clone inside /usr/local, and finally aliasing to ibrew:

❯ which ibrew                                                                                                                                 
ibrew: aliased to arch -x86_64 /usr/local/Homebrew/bin/brew

so that I could install formulae such as mosh and terraform, which don’t yet natively install through the “ARM” homebrew. I had to add the path to these homebrew binaries after the path to the “ARM” binaries so they have the ARM ones have the chance to be picked up first.

Mostly everything else: browsers, redis, postgres, ruby, node; run natively… it’s incredible how smooth it’s been.

My only problem now is Docker. The technical preview can “build” the containers in amd64, but there’s no DNS resolution between them as far as I could tell, so I moved temporarily to running docker in a VPS.

2 Likes

Got most of our stack running last night on M1. For libffi support, ensure you have the library installed native with brew. I also had to link the homebrew lib to /opt/local/. And finally install the gem specifying the ruby platform.

  sudo mkdir /opt/local
  sudo ln -s /opt/homebrew/lib /opt/local/lib
  gem install ffi --platform=ruby

I still need to update sidkiq to v6 for the last piece of the puzzle.

PS. I also ran into some issues with google-protobuf. Had to uninstall/reinstall a time or two with:

  gem install google-protobuf --platform=ruby -v '3.14.0'
4 Likes

Hello, I am getting this error:

Traceback (most recent call last):
	2: from bin/rake:11:in `<main>'
	1: from bin/rake:11:in `require_relative'
/Users/bradleebarnes/discourse/config/boot.rb:23:in `<top (required)>': undefined method `setup' for Bootsnap:Module (NoMethodError)

when running bin/rake db:create db:migrate. I am on an M1 MacBook Pro :slight_smile:

Sorry for replying after 3mo :confused:

1 Like

Leaving a small note here to mention that the guide still works great for Discourse :ok_hand:

OptimizedImage Load (0.8ms)  SELECT "optimized_images".* FROM "optimized_images" WHERE .....
#<Thread:0x000000010d054458 lib/discourse.rb:1013 run> terminated with exception (report_on_exception is true):
discourse/lib/letter_avatar.rb:105:in ``': No such file or directory - convert (Errno::ENOENT)
	from discourse/lib/letter_avatar.rb:105:in `image_magick_version'

For anyone else running into the above error, the only missing piece is to run brew install imagemagick. For Discourse development, you’d also need to run brew install yarn for ember-cli to work.

3 Likes

gem mini_racer command did not work on m1 chip for Mac book, it gave me gem unknown command error and when tried bin/rake db:create db:migrate gave me connection to server on socket “/tmp/.s.PGSQL.5432” failed: fe_sendauth: no password supplied

Couldn’t create ‘discourse_development’ database. Please check your configuration.

rake aborted!

ActiveRecord::ConnectionNotEstablished: connection to server on socket “/tmp/.s.PGSQL.5432” failed: fe_sendauth: no password supplied

Caused by:

PG::ConnectionBad: connection to server on socket “/tmp/.s.PGSQL.5432” failed: fe_sendauth: no password supplied

Quick follow-up on my install experience:

Followed the original instructions, but I got a “Symbol not found” error. After some brief Googling, discovered that the experimental branch is no longer required, so reverted to the original mini_racer configuration and that went away.

I next encountered the “No such file or directory” error as described by @rishabhnambiar, installed imagemagick as suggested and then everything worked perfectly. :partying_face:

2 Likes