giant robots smashing into other giant robots

Written by thoughtbot

Episode 53: Not everything needs to be extracted

In this episode Ben Orenstein is joined by Yehuda Katz and Tom Dale from Tilde. They discuss bootstrapping a business and the model behind Tilde, their breakdown of product development and consulting, and how they all met. They also talk about designing APIs and frameworks that people actually want to use, how teaching helps them be better framework developers, how they can beat the competition, how supporting multiple languages and frameworks can ruin your app’s experience, the big surprises as they’ve launched, Ember.js’ push to 1.0 and beyond, the difference between Ember.js and Backbone.js and why JavaScript matters, and much more.

Please Rate the show on iTunes, it’s the best way for new listeners to find the show, and we’d really appreciate it.

derekprior

Seamlessly Navigate Vim and tmux Splits

My tmux session for a given project typically has two horizontal tmux panes with Vim occupying the top 80% of the screen and a shell running below that occupying the remainder. For the most part I stay in vim, splitting often, and moving amongst those splits with ease.

tmux and Vim splits

Then I’ll decide to pop down to the shell split for a moment and confidently hit <C-j>… nothing. Hmph. Let’s try again. <C-j>… nothing. Oh, right, that’s not a Vim split, it’s a tmux split. <C-a>j.

I’m constantly stumbling over the disconnect between Vim and tmux splits. There’s a little mental hurdle I have to clear each time and I fail at that more often than I’d care to admit. It’s 2013; Shouldn’t the computer be able to figure out what I meant and just do that?

As it turns out, yes.

Vim and tmux, Together in Harmony

Mislav Marohnić devised a solution that allows for using the same key strokes to switch between Vim and tmux splits. With this in place, I can use <C-h/j/k/l> to seamlessly navigate all my splits, be they from tmux or Vim. The solution has three parts:

  1. tmux configuration that binds Vim-esque pane-switching commands to the tmux-vim-select-pane shell script.
  2. The tmux-vim-select-pane shell script that sends pane-switching commands to Vim or tmux as appropriate.
  3. A vim plugin that changes Vim splits when possible before shelling out to tmux select-pane commands when Vim has no more splits in the given direction.

Installation

Mislav’s post has an installation script, but a few of us at thoughtbot have had trouble getting those exact scripts running successfully.

Chris Toomey extracted the Vim plugin into vim-tmux-navigator and updated it to gracefully fall back when Vim is not running inside tmux. I extracted the tmux-vim-select-pane shell script into its own repository and added a homebrew formula for easy installation.

To get the whole thing running, follow these three steps:

  1. Install the shell script with:

    brew install https://raw.github.com/derekprior/tmux-vim-select-pane/master/tmux-vim-select-pane.rb

    If you don’t use homebrew or aren’t on OS X, you can manually add the shell script to a location in your path and mark it as executable.

  2. Install the vim-tmux-navigator plugin in Vim. With vundle, that’s as simple as adding the following to your ~/.vimrc file:

    Bundle 'christoomey/vim-tmux-navigator'

  3. Update your ~/.tmux.conf configuration file to bind the movement keys:

    # Smart pane switching with awareness of vim splits bind -n C-k run-shell 'tmux-vim-select-pane -U' bind -n C-j run-shell 'tmux-vim-select-pane -D' bind -n C-h run-shell 'tmux-vim-select-pane -L' bind -n C-l run-shell 'tmux-vim-select-pane -R' bind -n "C-\\" run-shell 'tmux-vim-select-pane -l'

I’ve been running this setup for a while now and have really enjoyed it. Thanks to Mislav for posting the original solution.

Written by Derek Prior

pbrisbin

accepts_nested_attributes_for with Has-Many-Through Relations

If you find yourself getting validation errors when using accepts_nested_attributes_for with has-many-through relations, the answer may be to add an inverse_of option.

The inverse_of option allows you to tell Rails when two model relations describe the same relationship, but from opposite directions. For example, if a User has_many :posts and a Post belongs_to :user, you can tell Rails that the :user relation on Post is the inverse of the :posts relation on User.

This option is usually not required, but there are cases where it matters. One such case is when using accepts_nested_attributes_for with a has-many-through relation. This will eventually lead to a collection= assignment which is only possible if Rails knows that one relation is the inverse of another.

Example

In our case, we had the following three models:

class Notice < ActiveRecord::Base

  # attribute :title

  has_many :entity_roles
  has_many :entities, through: :entity_roles

  accepts_nested_attributes_for :entity_roles

end

class EntityRole < ActiveRecord::Base

  # attribute :name

  belongs_to :entity
  belongs_to :notice

  validates_presence_of :entity
  validates_presence_of :notice

  accepts_nested_attributes_for :entity

end

class Entity < ActiveRecord::Base

  # attribute :name
  # attribute :address

  has_many :entity_roles
  has_many :notices, through: :entity_roles

end

We wanted the form to create two related entities for the notice, each of a specific role.

The controller looks like this:

class NoticesController < ApplicationController

  def new
    @notice = Notice.new
    @notice.entity_roles.build(name: 'submitter').build_entity
    @notice.entity_roles.build(name: 'recipient').build_entity
  end

end

Using Simple Form, the view looks like this:

<%= simple_form_for(@notice) do |form| %>
  <%= form.input :title %>

  <%= form.simple_fields_for(:entity_roles) do |roles_form| %>
    <% role = roles_form.object.name.titleize %>
    <%= roles_form.input :name, as: :hidden %>
    <%= roles_form.simple_fields_for(:entity) do |entity_form| %>
      <%= entity_form.input :name, label: "#{role} Name" %>
      <%= entity_form.input :address, label: "#{role} Address" %>
    <% end %>
  <% end %>

  <%= form.submit "Submit" %>
<% end %>

The only clever bit here is that we use each role’s name to intelligently affect the entity form’s labels each time it’s rendered. Aside from that, it’s pretty standard accepts_nested_attributes stuff.

On POST, we found validation errors on the entity_role objects:

["notice", "can't be blank"]

We were confused.

The controller’s #create action is effectively doing this:

notice = Notice.new(
  title: "...",
  entity_roles_attributes: [
    { name: "submitter", entity_attributes: { ... } },
    { name: "recipient", entity_attributes: { ... } }
  ]
)

notice.save

Which, as far as we knew, should work.

It seemed Rails was not setting the notice attribute on the EntityRole before attempting to save it, triggering the validation errors. This is a bit surprising as other has_many relations (omitted in this blog post) should have the same save mechanics and were working just fine.

In an act of experimentation, we added inverse_of:

class Notice < ActiveRecordBase

  has_many :entity_roles, inverse_of: :notice

end

And suddenly, it all worked.

Only after the fact, when we knew to include “inverse_of” in our search queries, did we find some information on this issue. You can read the details here, here, and here if you’re interested.

When you use collection= assignment with a has-many-through (as accepts_nested_attributes_for does), you have to specify inverse_of for Rails to save everything correctly.

Written by .

cpytel

Send your thoughtbot books to Readmill

We’re happy to announce that you can now easily send any of your books purchased at Learn to Readmill. Readmill is a unique ebook reader for iPad and iPhone that lets you read, share and discover great books.

Readmill on Learn

On your book page, just click the “Send” button, below all the direct formats, to send your book to Readmill. Now, instead of downloading ebooks to your desktop and transferring them to your device manually, Readmill does it all in one click.

Episode 52: You look really fancy in your tuxedo

In this special episode, number 52, and our 1 year anniversary episode, recorded at RailsConf 2013, Ben Orenstein is joined by Ruby and Rails core team member Aaron Patterson, thoughtbot CTO Joe Ferris, and a live studio audience.

If you listen to and like the show, please Rate us on iTunes it’s the best way for new listeners to find the show, and we’d really appreciate it.

The trio discuss Rails 4, observers, callbacks, dubstep, namespaces, Scheme, functional programming, thread safety in Rails, what it would take to remove callbacks from Rails and why you would want to do it, what should be in our anniversary episode, dealing with Rails security issues, why Aaron likes to work on Rails, meeting people’s expectations, Vim, intuitive software, and so much more.