Rails 7.0 Branca and Caching

Organizing Rails Apps with Packages

Organizing Code

Gems and Engines have long been used to organize Ruby and Rails code into workable small units.

Shopify has introduced a new system called ‘packages’ - they use the packwerk gem to help us. In fact, it is designed to make it easy to take large (and likely highly coupled) large codebase and move toward ‘packages’ self-contained (or have explicit dependencies). Ideally the code is in small enough units to help us keep the context in mind as we work on it.

I found it initially difficult to understand packwerk in the context of a complex codebase. So instead I built a new ‘play’ app and then moved each piece into a package. Hopefully, this will inspire you to use Gem, Engines or Packages to clarify dependencies and make the code a logical until that is easy to reason about.

Environment

First you will need libsodium installed;

brew install libsodium

Using Rails 7 & Ruby 3.1.2 - I found that it is important to update my ruby environment - so before we start this is what I didn’t remove errors:

# I've had the error several times without updating:
# /Users/btihen/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/bundler-2.3.8/lib/bundler/rubygems_ext.rb:18:in `source': uninitialized constant Gem::Source (NameError)
#
#       (defined?(@source) && @source) || Gem::Source::Installed.new
#                                            ^^^^^^^^
# Did you mean?  Gem::SourceList
# this seems to fix it:
# https://bundler.io/guides/bundler_2_upgrade.html
# https://stackoverflow.com/questions/4859600/bundler-throws-uninitialized-constant-gemsilentui-nameerror-error-after-upgr
rbenv local 3.1.2
gem update --system
gem install bundler
gem install rails
rbenv rehash

Rails Project - Simple Blog

Since my other projects are using esbuild I use that here too

rails new rails_branca -T --database=postgresql --css=bootstrap --javascript=esbuild
cd rails_branca
bin/rails db:create

# add the packwerk (packages) gem
bundle add branca-ruby

Quick Test

Let’s try this library in the console:

bin/rails c

require 'branca'

# key must be at least 33 Characters long!
Branca.secret_key = 'supersecretkeyyoushouldnotcommit'.b
Branca.ttl = 30 # in seconds

token = Branca.encode '[email protected]'
decoded = Branca.decode token
message = decoded.message
> '[email protected]'

# now wait 20 Seconds and you should get the error
decoded = Branca.decode token
> Token is expired (Branca::ExpiredTokenError)
# now the token is encrypted and no longer usable


# Branca encodes strings - but we can convert to json and encrypt complex data
token = Branca.encode({email: '[email protected]'}.to_json)
decoded = Branca.decode token
message = JSON.parse decoded.message
> {"email"=>"[email protected]"}

Configure Rails

Let’s setup rails to use Branca (and expire tokens after 15 Mins)

Let’s get rails to read the env file (append dotenv-rails to the Gemfile):

# append gem to the GEMFILE with the >>
cat <<EOF>>Gemfile

gem 'dotenv-rails', groups: [:development, :test]
EOF
bundle

Now add the needed config files:

# create the environmental variables
cat <<EOF> .env
BRANCA_SECRET='SuperSecretKeyHiddenInEnvFile'
BRANCA_TTL=900
EOF

# create the rails initializer for branca
touch config/initializers/branca.rb
cat <<EOF> config/initializers/branca.rb
# require is needed since the gem name is branca-ruby, but needs to load: branca
require 'branca'

Branca.configure do |config|
  # .b ensures 8 bit String Encoding
  config.secret_key = ENV['BRANCA_SECRET'].b
  config.ttl = ENV['BRANCA_TTL']
end
EOF

Lets be sure Rails loads Branca properly:

bin/rails c
Branca.ttl
> "900" # hopefully :)

token = Branca.encode({email: '[email protected]'}.to_json)
decoded = Branca.decode token
message = JSON.parse decoded.message
> {"email"=>"[email protected]"}

Using Branca

Resources

Token Technologies

Rails Caching

Intersting Article

Bill Tihen
Bill Tihen
Developer, Data Enthusiast, Educator and Nature’s Friend

very curious – known to explore knownledge and nature