Rob Lacey

Brighton, UK - contact@robl.me

Senior Software Engineer working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it. Currently looking for new opportunities


Upgrading to Rails 5 hell

It’s that time that you have to “upgrade to Rails 5”. I have completed this process at least 8 times with different projects.

Bundler / geems

This suggests to me that that Rails 5.0.7 should be installed but nothing higher. Well it appears that ActionPack and Railties are installing 5.1.0 which is annoying. I want to make the jump to 5.0 first not straight to 5.1, that’s 5.0.7 at the point of writing.

<pre> gem 'rails', '~ 5.1.0' </pre>

Middleware

Middleware that depends on ActionDispatch::ParamsParser. Well ActionDispatch::ParamsParser is removed in 5.1 apparently. That’s a bit weird because it’s not doing anything Middleware-y, it’s just setting config. I’ve never looked at it before but I assumed it was doing the actual Parsing at that point, perhaps it did in the past. It appears the next thing in the stack after ParamsParser in Rails 4 is Rack::Head, so I’ve replaced all middle use statements to use Rack::Head to find it’s order in the stack.

<pre>

  1. File actionpack/lib/action_dispatch/middleware/params_parser.rb, line 39
    def self.new(app, parsers = {})
    ActiveSupport::Deprecation.warn(‘ActionDispatch::ParamsParser is deprecated and will be removed in Rails 5.1. Configure the parameter parsing in ActionDispatch::Request.parameter_parsers.’)
    parsers = parsers.transform_keys { |key| key.respond_to?(:symbol) ? key.symbol : key }
    ActionDispatch::Request.parameter_parsers = ActionDispatch::Request::DEFAULT_PARSERS.merge(parsers)
    app
    end

Controller and Request specs

It appears this is changing…

DEPRECATION WARNING: Using positional arguments in functional tests has been deprecated,
in favor of keyword arguments, and will be removed in Rails 5.1.

Deprecated style:
get :show, { id: 1 }, nil, { notice: “This is a flash message” }

New keyword style:
get :show, params: { id: 1 }, flash: { notice: “This is a flash message” },

My First Elixir Project

Most people’s first project in a language / framework is a simple ToDo example or a blog. I guess I’m in the same situation. However, my first Ruby project was a blog and I’ve been dumping code snippets, findings and moans on that for 10 years now. So my first Elixir project should really be to port my Rails blog to Phoenix. Here’s some things I learned along the way.

Agile Web Development with Rails

I get the distinct impression that this book, along with particular circumstances may have changed my life.

I was working as a Network / Systems Administrator for whatever particular system was broken that day at that time, trying to migrate every last website off old hardware, and trying not to spend my day desperately trying to build something meaningful in PHP (while doing the normal day job stuff) and generally being bored out of my skull at a job I had loved for years. It was partly being bought out, moving into a data centre and then in almost cubicles where we hardly spoke to colleagues we’d previously spent all day chatting and joking with for make benefit glorious internet. The love had left the building.

So then I heard about Ruby, Rails and then met John well I met him at a job interview that I was going for …erm with him. To do those things I was bored out of my skull doing but still to me it was easy and I could learn Ruby on the job for make benefit glorious brain, career advancement.

I bought this book for significantly more than the £3 it goes for on eBay now. I moaned about how the Order object was marshalled in the Session rather than store the order_id and look it up. But hey. It opened up my eyes to some kind of framework and structure rather than bumbling through making a PHP file per page on my site and boom.

Some 15 years later I am still writing Ruby and money appears in my account every month as a result of this.

My Test Phoenix App is not dead

…it’s just sleeping

Hi, You’re receiving this email because your Gigalixir app, iplay-red, is inactive and is scheduled for scale down to 0 replicas in 7 days. We define an inactive app as one that has not been deployed for over 30 days as opposed to one that does not have any network traffic. We do this so that we never have to put apps to sleep. If you want to keep your app running, just deploy or upgrade within the next 7 days.

Ok, better add some more features. Thanks for the heads up Giggles

So programming languages huh?

Before I started with Ruby, I had worked with Perl, PHP, Python, and BASIC (ok, back before I was 10). Ruby has stuck and has been my goto for everything. I feel like this has left me rather stuck and lacking any kind of contrast to other solutions, problem solving, perspective on how to create effective software. So my list of things to look at over the course of the rest of my life

--
- Ruby
- Go
- Rust
- Python
- Elixir
- Erlang
- Crystal
- Haskell
- Elm
- C++ (Unreal Engine)

With any luck exposure to all of this will make my brain explode in interesting artistic patterns.

Caught my first tube this morning, Sir.

Ok, I threw this up about a week ago. Still I’ve managed to deploy my first Phoenix application to Gigalixir. It’s attempting to be a rather splendid, better than the YouTube UI for I Play Red ’s YouTube Channel …which will allow Kat the ability to publish her videos, which are then synced here but at the same time label them with the game they are for. Which allows for better searching, SEO, OpenGraph, and generally syndicating all over the shop.

Plus I have a project to build something that needs to work and we can measure success on nicely. Not like this blog where the only person that really needs to read it is me :)

Fun with classes and constants

Ruby is somewhat versatile at times. Suppose you want to define a class dynamically, and I do….

class Thing; end

Ok, that’s not dynamic

# still not dynamic but getting there.
def define_a_class
  Thing = Class.new
end

# ok then I see
def define_a_class(name)
  Object.const_set(name, Class.new)
end

define_a_class('Thing')
=> Thing

This is great but what if you wanted to define a class within a module

define_a_class('Nigel::Thing')
NameError: wrong constant name Nigel::Thing
from (pry):19:in `const_set'

Oh. That sucks. What you’re actually trying to do here is

Object.const_set('Thing', Class.new)
#=> Thing
Nigel.const_set('Thing', Class.new)
#=> Nigel::Thing

Object is for root namespace, and the module name for the nested namespace.

So today we had an issue. We normally define a Permit class if one doesn’t already exist like so.

def define_permit_class
  name = "#{self.name}Permit"
  Object.const_get(name)

rescue NameError
  Object.const_set(name, Class.new(Permit))
end

This works for

Thing.define_permit_class

But obviously not for

Nigel::Thing.define_permit_class

Well, easily fixed. A class can find it’s parent module, or if it is doesn’t have one it’s Object.

Thing.parent 
#=> Object
Nigel::Thing.parent
#=> Nigel

So we just refactor this a little and bingo

def define_permit_class
  name = "#{self.name.demodulize}Permit"
  parent.const_get(name)

rescue NameError
  parent.const_set(name, Class.new(Permit))
end

Ok, it now seems that parent is deprecated in Rails 6.1. module_parent it is.

DEPRECATION WARNING: `Module#parent` has been renamed to `module_parent`. `parent` is deprecated and will be removed in Rails 6.1.

Elixir did an explode

Just trying to boot my application after a little time away from the project. Just wondering if my my latest brew upgrade broken something here too. Node and MongoDB went foom too on the last upgrade.

Robs-MBP:i_play_red_umbrella rl$ iex -S mix
Erlang/OTP 25 [erts-13.0.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns] [dtrace]


11:17:06.689 [error] beam/beam_load.c(86): Error loading module 'Elixir.Code.Formatter':
  lambda already defined for label 744. To fix this, please recompile this module with an OTP 25 compiler.


 
11:17:06.689 [error] Loading of /Users/rl/.asdf/installs/elixir/1.13.1/bin/../lib/elixir/ebin/Elixir.Code.Formatter.beam failed: :badfile

** (UndefinedFunctionError) function Code.Formatter.locals_without_parens/0 is undefined (module Code.Formatter is not available)
    (elixir 1.13.1) Code.Formatter.locals_without_parens()
    (elixir 1.13.1) lib/code/normalizer.ex:22: Code.Normalizer.normalize/2
    (elixir 1.13.1) lib/code.ex:1107: Code.quoted_to_algebra/2
    (elixir 1.13.1) lib/macro.ex:948: Macro.to_string/1

Ok so it’s using OTP 25 but it’s compiled with OTP 22?

Robs-MBP:i_play_red_umbrella rl$ elixir -v
Erlang/OTP 25 [erts-13.0.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns] [dtrace]

Elixir 1.13.1 (compiled with Erlang/OTP 22)

Uninstalled and Re-Installed via asdf and it seems fine now.

Robs-MBP:i_play_red_umbrella rl$ asdf list elixir
  1.12.1
  1.13.1
Robs-MBP:i_play_red_umbrella rl$ asdf uninstall elixir
Robs-MBP:i_play_red_umbrella rl$ asdf list elixir
  No versions installed
Robs-MBP:i_play_red_umbrella rl$ asdf install elixir 1.13.1
==> Checking whether specified Elixir release exists...
==> Downloading 1.13.1 to /Users/rl/.asdf/downloads/elixir/1.13.1/elixir-precompiled-1.13.1.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 6068k  100 6068k    0     0  9689k      0 --:--:-- --:--:-- --:--:-- 9772k
==> Copying release into place
Robs-MBP:i_play_red_umbrella rl$ asdf list elixir
  1.13.1
Robs-MBP:i_play_red_umbrella rl$ elixir -v
Erlang/OTP 25 [erts-13.0.3] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns] [dtrace]

Elixir 1.13.1 (compiled with Erlang/OTP 23)

What version of Erlang do I have installed anyway?

Thought erl -v might do the trick but that’s only the major version.

erl -eval '{ok, Version} = file:read_file(filename:join([code:root_dir(), "releases", erlang:system_info(otp_release), "OTP_VERSION"])), io:fwrite(Version), halt().' -noshell

OK, 25.0.2 then.

Robs-MBP:i_play_red_umbrella rl$ erl -eval '{ok, Version} = file:read_file(filename:join([code:root_dir(), "releases", erlang:system_info(otp_release), "OTP_VERSION"])), io:fwrite(Version), halt().' -noshell
25.0.2

Redis::CommandError: MISCONF Redis

Ok that’s annoying

265) returns a thing
       Failure/Error: raise reply if reply.is_a?(CommandError)
       
       Redis::CommandError:
         MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.

Ok, just upgraded brew earlier, it’s probably upgraded and restarted Redis. Thanks for a find on the Googles https://gist.github.com/kapkaev/4619127

Robs-MBP:sard rl$ redis-cli
127.0.0.1:6379> config set stop-writes-on-bgsave-error no
OK
127.0.0.1:6379> quit

No more moaning from Redis.