Economy of Effort

Twitter LinkedIn GitHub Mail RSS

ActiveRecord Save Not Updating Hstore Fields in Rails 4.0-4.1

Here’s some behavior you might not expect when using Postgres’s hstore with ActiveRecord.

ActiveRecord::Base#update_attributes does what you’d think:

1
2
3
4
5
[0] pry(main)> thing = Thing.new
[1] pry(main)> thing.update_attributes({data: {'mykey' => 'myval'}})
[2] pry(main)> thing.reload
[3] pry(main)> thing.data['mykey']
=> "myval"

However, ActiveRecord::Base#save might not:

1
2
3
4
5
6
7
8
9
10
11
[0] pry(main)> thing = Thing.new
[1] pry(main)> thing.data['mykey'] = 'myval'
=> "myval"
[2] pry(main)> thing.save
   (0.3ms)  BEGIN
  SQL (0.4ms)  INSERT INTO "things" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"  [["created_at", "2014-12-17 04:02:03.119354"], ["updated_at", "2014-12-17 04:02:03.119354"]]
   (0.9ms)  COMMIT
=> true
[3] pry(main)> thing.reload
[4] pry(main)> thing.data['mykey']
=> nil

Huh? I left the SQL log line in the output here so we can see that our hstore field is indeed left out of the SQL INSERT statement entirely, which explains why the field is nil once we re-fetch the object from the database.

But why is it doing this? It turns out that, in Rails 4.0 and 4.1, this operation doesn’t mark the field as “dirty” in ActiveRecord, so the change is not detected and included in the save operation.

We can mark it manually with ActiveModel::Dirty’s attr_name_will_change!, eg.

1
2
3
4
5
6
7
8
9
10
11
12
[0] pry(main)> thing = Thing.new
[1] pry(main)> thing.data_will_change!
[2] pry(main)> thing.data['mykey'] = 'myval'
=> "myval"
[3] pry(main)> thing.save
   (0.3ms)  BEGIN
  SQL (0.3ms)  INSERT INTO "things" ("created_at", "data", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", "2014-12-17 04:08:32.066027"], ["data", "\"mykey\"=>\"myval\""], ["updated_at", "2014-12-17 04:08:32.066027"]]
   (1.0ms)  COMMIT
=> true
[4] pry(main)> thing.reload
[5] pry(main)> thing.data['mykey']
=> "myval"

The documentation states that attr_name_will_change! should be called before changes to the attribute, as seen in the example above.

Doesn’t this seem like a pain? Well, as discussed in Rails issue #6127, it was expected behavior for Rails 4.0 and 4.1, but improvements to serialized attributes have been merged into Rails and will appear in Rails 4.2. Setting values and calling save will just work.

So, in the meantime, the workaround is manually marking properties as dirty with attr_data_will_change! before making and saving changes to those fields.

PostgreSQL Hstore Default Value in Rails 4

Having used activerecord-postgres-hstore before native hstore support was added to Rails 4, I was used to the behavior of empty hstore fields returning an empty hash {} when a row with such a field was instantiated into an ActiveRecord object, as was discussed and added in the gem’s issue #22.

This behavior changed in Rails 4’s hstore support. An ActiveRecord object with an empty hstore field will return nil for that field rather than an empty hash. (When someone opened a bug in the Rails repo to suggest implementing the same behavior in the new native hstore support, it was brushed off.)

By default, that leaves us to have to nil-check every hstore property in our objects before accessing any keys (eg. @myobj.data && @myobj.data['mykey']). However, we can get our “empty” hstore fields instantiating as empty hashes instead of nil with a tweak of our migration.

Simply add default: '', null: false to the migration, eg.

1
2
3
4
5
class AddDataToThings < ActiveRecord::Migration
  def change
    add_column :things, :data, :hstore, default: '', null: false
  end
end

With that default in place, our empty hstore fields will instantiate as empty hashes, and we can avoid the nil check:

1
2
3
4
[1] pry(main)> thing = Thing.new
=> #<Thing id: nil, ... >
[2] pry(main)> Thing.data
=> {}

Beyond Ctrl: Make That Caps Lock Key Useful

tl;dr: Supercharge your Caps Lock key by making it Esc when tapped, and Ctrl when held

Caps Lock. A useless key sitting in prime keyboard real estate. Many software developers and power users repurpose the key by remapping it to Control.

After all, on old UNIX terminals, that’s exactly what the key to the left of “A” was:

Replacing the Caps Lock key with Ctrl makes a lot of keyboard shortcuts more convenient. But we need not stop there. Some true Men and Women of Genius came to the realization that, since Ctrl’s behavior is based around behind held down (a modifier key) and doesn’t do anything when pressed and released, it is possible to make Caps Lock do something else when tapped instead of held. For Vim users, the obvious choice is the Esc key.

We can do this in both Mac OS X and Linux.

OS X

If you want all Ctrl keys to behave like Esc when tapped

This is the easiest way, and the option I use. (I rarely find myself hitting the normal Ctrl keys anyway.)

First, open System Preferences –> Keyboard, and click Modifier Keys button. Click the Caps Lock drop-down and set it to Control:

Now, install Karabiner (formerly known as KeyRemap4MacBook). If you are a Homebrew user, you should check out Homebrew Cask and install Karabiner with $ brew cask install karabiner

Open Karabiner. Enable the first setting from the screenshot below:

The other option I have there, “Disable Escape Key”, is something I’ve done just to get myself in the habit of using the Caps Lock key for Esc. It is not required, it is just an option if you want to help train yourself to use the new key.

If you only want the Caps Lock key to behave like Esc when tapped

To do this, we’re going to take a slightly different approach. Instead of using OS X’s native Caps Lock remapping, we need to use another app, called Seil (from the same developer as Karabiner) to remap the Esc key to F19, and then use Karabiner to map F19 to our cool Ctrl/Esc hybrid key.

Install both Karabiner and Seil. (Here again, if you use Homebrew Cask, you can do this with $ brew cask install karabiner and $ brew cask install seil)

Open Seil. First, enable the “Change Caps Lock” option, and set the keycode to 80:

Next, in Karabiner, enable the “F19 for Escape and Control” option:

Linux

To accomplish the same setup in Linux, we need to use a tool called xcape.

Build and install xcape per the instructions on the project’s Wiki page. One additional step I take after building the app is copying the xcape executable to /usr/local/bin.

If you only want the Caps Lock key to behave like Esc when tapped

Add the following lines to your ~/.profile:

1
2
setxkbmap -option 'caps:ctrl_modifier'
xcape -e 'Caps_Lock=Escape'

If you want all Ctrl keys to behave like Esc when tapped

Same as above, except we add more arguments to the xcape line:

1
2
setxkbmap -option 'caps:ctrl_modifier'
xcape -e 'Caps_Lock=Escape;Control_L=Escape;Control_R=Escape'

Note: If you use some other method of remapping the Caps Lock key to Ctrl (some desktop environments have it as an option in their Keyboard settings, much like OS X), then the Caps_Lock=Escape mapping may not do anything, and you will need to use the Control_L one.

One last little tidbit: Ubuntu 14.10 (“Utopic”) has xcape in the universe repos, at least as of the time of this writing. Hopefully it will be included in Ubuntu releases from here on out.

Now Your Caps Lock Key Rules

The most useless key on the keyboard (except maybe for Pause, when’s the last time you used that?) is now your Swiss Army knife. Vim’s keybindings will make a lot more sense now that you can use your pinky the way Bill Joy did on his old ADM3A terminal:

Convert HTML to Haml (and Back Again) Within a Vim Buffer

Haml is great. Haml is the JSON to HTML’s XML: all of the garbage and noise stripped away, with only the data and minimal amount of ceremony left.

I use Haml on all Rails projects now, but when dealing with legacy projects, I still encounter HTML/ERb templates.

Using the html2haml command-line tool, I can easily convert HTML/ERb in my Vim buffer into Haml.

The project distributes as a Ruby gem, so installing is accomplished with:

1
$ gem install html2haml

Then, the magic is done with some Vim bindings to feed a buffer or visually-selected chunk of text to the application, and paste its output back into the buffer, replacing the original text.

1
2
nmap <leader>h :%!html2haml --erb 2> /dev/null<CR>:set ft=haml<CR>
vmap <leader>h :!html2haml --erb 2> /dev/null<CR>

When changing the entire file, I’ve also added the command to change the filetype in the Vim buffer, for convenience.

That takes us from HTML/ERb to Haml, but what if we need to go back in the other direction? This is possible with the haml2erb tool. Unfortunately, this tool is not actively maintained the way html2haml is. For me, on Ruby 2.1.1, it was necessary to install the 0.3.0 prerelease version, as the last official version would not build. Once installed, though, it worked as expected.

We must explicitly indicate which version to install in order to install prerelease gems:

1
$ gem install haml2erb -v '0.3.0.pre.3'

The Vim bindings are much the same as the html2haml ones:

1
2
nmap <leader>e :%!haml2erb 2> /dev/null<CR>:set ft=eruby<CR>
vmap <leader>e :!haml2erb 2> /dev/null<CR>

I have not used this nearly as much as html2haml, as I’m rarely changing layout code from Haml back into HTML. However, the couple of times I have needed to do it, it has worked exactly as expected..

Fixed the Archive Page

Finally got around to fixing the Archive page on this site.

If I recall correctly, what happened originally is that I was attempting to get rid of the “/blog/” part of the archive path, but got distracted halfway through and left it incomplete.

For reference: this part of the archive path is not a user-configurable part of Octopress per se. It is a default location for a file in Jekyll, which is in source/blog/archive in an Octopress site repository. Simply moving the archive/ folder out of blog/ and into the top level of source/ will make the archive page generate without the “/blog/” part of the page. (For further reference, see the workaround post on the issue on Github)

Vim Tricks for Ruby Hashes

I have a couple of functions in my .vimrc for manipulating Ruby hashes.

The first one is to convert hashes from Ruby 1.8 style into Ruby 1.9+ style, eg.

1
2
3
4
5
# before
:symbol_key => 'value'

# after
symbol_key: 'value'

I create this function for both Normal and Visual modes to allow updating either a selected hash, or the entire file.

1
2
3
4
5
6
7
8
9
10
function! RubyHashesAll()
  :%s/:\([^ ]*\)\(\s*\)=>/\1:/ge
endfunction

function! RubyHashesSelected()
  :'<,'>s/:\([^ ]*\)\(\s*\)=>/\1:/ge
endfunction

nmap <Leader>rhh :call RubyHashesAll()<CR>
vmap <Leader>rhh :call RubyHashesSelected()<CR>

Next, I have one for taking a hash and extracting an array of the hash keys.

1
2
3
4
5
# before
{ 'one' => two, :three => 'four', five: 6 }

# after
['one', :three, :five]

Here, I have the command bound only in Visual mode, as I don’t see a case where I’d want to do this globally.

1
2
3
4
5
6
7
8
function! RubyExtractHashKeys()
  :'<,'>s/\([:'"]\?[a-zA-Z]\+['"]\?\)\s*=>[^,}]\+\([,}]\)/\1\2/ge
  :'<,'>s/\([a-zA-Z]\+\)[:]\s*[^,}]\+\([,}]\)/:\1\2/ge
  :'<,'>s/{\s*/\[/ge
  :'<,'>s/\s*}/\]/ge
endfunction

vmap <Leader>rhe :call RubyExtractHashKeys()<CR>

The regexes can probably be improved to fix some edge cases, and I’m certain there’s a way in Vim to make it so that I don’t have to define the All and Selected versions of RubyHashes as separate functions. But these do the job for me now, until I reach a higher plane of Vim mastery.

Zsh, Tmux, Vim, and 256 Color Madness

tl;dr: You want $TERM to be screen-256color when tmux is running, and you want it to be xterm-256color when tmux is not running. Also, launch tmux with -2 argument.

I love tmux. It is the primary reason why I switched from using gVim to console vim. I love having a fully terminal-based workflow. It beats switching between a GUI editor app and terminal window any day.

This switch, however, was not without some issues. Here are the solutions to two that I encountered.

Weirdness with zsh, tmux, and vim

Problems:

  • when $TERM is screen-256color but tmux is not running, zsh will echo your command into the output when you hit Enter:

Notice how the output of the “ls” and “echo” commands repeat themselves in the output stream as soon as I switched to screen-256color.

  • when $TERM is xterm-256color while tmux is running, colors will not display properly in Vim:

vim /etc/default/grub while TERM=screen-256color:

vim /etc/default/grub while TERM=xterm-256color:

Solution:

In my zsh config (~/.zshrc), I set xterm-256color to be the default TERM, but right after that, added a command that would re-export TERM as screen-256color if tmux is running:

export TERM=xterm-256color
[ -n "$TMUX" ] && export TERM=screen-256color

No Vim colorschemes when tmux is launched by terminal app in place of shell

Problem:

I ran into a specific set of circumstances where my Vim colorscheme would not display.

Terminal applications usually launch a shell by default, but some (like gnome-terminal) have the option of defining a command to be run rather instead of the shell.

If I set this command to tmux, tmux would indeed launch. However, if I then ran Vim, the colorscheme would not display correctly.

However, if I allowed gnome-terminal to launch a shell, and then ran tmux myself from that shell, Vim would display properly within that tmux session.

Solution:

I got my clue from this StackOverflow post. Basically, what is happening is that, when running tmux from within my shell, which is configured for 256 colors, tmux would launch in 256 color mode. But when I had gnome-terminal launch tmux directly, it would not.

The easy way around this was to use the “-2” argument for tmux, making the command tmux -2.

With that command in place, tmux launches whenever firing up gnome-terminal, and does so in 256 color mode.

Careful What You Name Your Rails Partials

tl;dr: Hyphens bad.

I encountered a strange bug in Rails 3.2.13 this week. I kept getting an error that traced back to the very start of a partial:

1
_example-partial-logged-in.html.haml:1: syntax error, unexpected keyword_in, expecting keyword_end

I tracked it down to this issue, which pointed out that the error was related to the hyphenated name ending with a Ruby reserved word.

By convention, Rails uses underscores for word separation in file names. Hyphens are not completely disallowed (the above works if I rename the file to end with a non-reserve word), but can lead to issues.

The issue linked above contains a pull request for a better error message, which was merged into Rails 4. But for those still on Rails 3 and earlier, if you see this vague error message, now you know why.

Reattach-to-user-namespace: The Fix for Your Tmux in OS X Woes

tl;dr: Things not behaving right in tmux on OS X? Install reattach-to-user-namespace

Are you a tmux + Mac OS X user? Have you had any of the following problems?

  • Running launchctl to start services fails with a message like launch_msg(): Socket is not connected
  • Using the OS X Pasteboard commands pbcopy and pbpaste and having them not work
  • Launching a GUI app from the terminal and getting a “ghost window”: the app window loads in the background, with no dock icon, cannot be Command-Tab’d to, and the app’s menu does not populate the top bar when the window gains focus

Why does this happen? Chris Johnsen has some details

tmux uses the daemon(3) library function when starting its server process. In Mac OS X 10.5, Apple changed daemon(3) to move the resulting process from its original bootstrap namespace to the root bootstrap namespace. This means that the tmux server, and its children, will automatically and uncontrollably lose access to what would have been their original bootstrap namespace (i.e. the one that has access to the pasteboard service).

It turns out that Apple has patched the version of GNU screen that they distribute with OS X to avoid this problem. But this is 2013, and we UNIX geeks have moved on to tmux, right? Chris goes on in that README to explain why porting Apple’s screen patch to tmux would be tricky.

So, instead, he provides the reattach-to-user-namespace wrapper program. This allows us to launch a process and have that process be attached to the per-user bootstrap namespace, which, to put it simply, makes the program behave as we are expecting.

The “trick” is to configure tmux to launch its shells with the reattach-to-user-namespace wrapper. By doing that, the shells tmux launches, as well as everything those shells launch, will be attached to the user namespace, and the problems listed at the top of this post will no longer be issues. We can use the default-command option in ~/.tmux.conf to wrap our shell launching command.

First, we need to install reattach-to-user-namespace. If you use Homebrew or MacPorts, this is as easy as:

; with Homebrew
$ brew install reattach-to-user-namespace

; with MacPorts
$ port install tmux-pasteboard

I use the same dotfiles for Linux as well as OS X, so I only want to do this in the OS X environment. I accomplish this with the following:

~/.tmux.conf
1
2
" at the end of the file
if-shell 'test "$(uname)" = "Darwin"' 'source ~/.tmux-osx.conf'
~/.tmux-osx.conf
1
set-option -g default-command "reattach-to-user-namespace -l zsh"

If you only use OS X, you can skip creating an external file, and just put the set-option line directly in your ~/.tmux.conf. Also, I am using zsh, so my command to reattach-to-user-namespace is zsh. If you’re using a different shell, change that to your shell’s name.

With this configuration in place, kill and re-launch tmux. The shells that tmux launches should now get attached to the user namespace, and namespace-related issues should be resolved.

No Numpads

My mother is an accountant. Walk by her office on any given day, and you’ll likely hear the mechanical sounds of an accounting calculator printing its results to a stream of paper.

I used to make fun of the endless crunch-crunch-crunch sound that echoed down the hallways.  These days, she tells me, the ol’ hand calculator doesn’t get quite as much use as before. More and more of the accounting business is computerized.

It comes as little surprise. Computers were invented to crunch numbers. When computers became machines that fit on a desktop, the “killer apps” were all about numbers: the first two applications named in Wikipedia’s entry for killer applications are Visicalc and Lotus 1-2-3.

Accordingly, it did not take long for personal computer manufacturers to take inspiration from those hand calculators and add the number pad to the right of the typewriter key layout.

Personal computers, however, have moved well beyond the domain of the office desktop. Indeed, for most people, the computer is no longer thought of as a device for performing calculations. They are used for communication, and for accessing and storing data. I don’t have data to back it up, but I would wager that most computer users don’t punch in long sequences of numbers regularly.

And yet, while the computer has evolved, the number pad remains. Like the wings of a flightless bird. the vestigal number pad sits unused, eating up space on millions of desktops.

Oh sure, you use the number pad, you say. And perhaps you do. But do you really use it enough to dedicate 6 inches of desk width for it? More to the point, does every computer user? People are buying laptops and netbooks for their computing devices more and more, and I don’t ever hear people complaining about how much they miss the numpad.

And yet, the vast majority of keyboards for sale include the numpad. Finding keyboards without them takes some effort.

One of the few I became aware of when starting the search was the Happy Hacking Keyboard Lite.

It’s a nice, small deck. It uses a “UNIX” keyboard layout, like the ones on the old Sun boxes in one of the computer labs back at university.

Apple has come around on the idea of ditching the numpad. New iMacs come with a wireless keyboard that has no numpad.

I considered picking up one of these. And I actually did pick up a couple of Apple’s discontinued wired USB tenkeyless keyboards.

They’re not bad as spare keyboards to have around, but they were not going to be my primary keyboard. (My wife is using one on her desktop machine, though).

One keyboard I really want is the 84-key “Space Saving” version of the IBM Model M.

Sadly, they are awfully hard to come by. I watch for them on clickykeyboards.com but it’s just an endless list of SOLD boards.

But the keyboard that ended my search was the Leopold Tenkeyless Tactile Touch from EliteKeyboards. It combined my desire for a compact no-numpad keyboard with the desire to have a mechanical keyboard.

It’s been a couple of years now since I bought this keyboard, and while the idea of spending $100 on a keyboard was a tough pill to swallow at the time, I would not hesitate to do it again. The compact size make life nicer on my desk, and the action of the mechanical key switches is so much more enjoyable than mashing the rubber dome switches on a non-mechanical keyboard.