Avoiding Instance Variable Pain in Rails Controllers and Views

metal letters

Some Rails patterns are so ingrained in us that we don’t think about them anymore. That’s sort of the point of the whole “convention over configuration” thing and it’s great. I don’t want to think about unnecessary things if I don’t have to so I can focus building the best application I can.

All that said, it’s important to step back every so often and reevaluate all of these second nature tendencies and see where we can improve. To that end, I think it’s time we reconsider our use of raw instance variables in Rails controllers and templates.

Ever since I started writing Rails, the pattern has always been the same: Assign an instance variable in the controller, use that instance variable in the view. It’s all over the Rails guides. Here’s a quick example.

Did you see the problem(s)? They’re subtle, even in this small example.

…Okay, spoiler alert: The instance variables are misspelled. 😭

Each of the templates will end up raising NoMethodError for calling each/description on nil. Not the worst problem given that our templates are so small, but what if we just didn’t have that problem? Let’s rewrite this to use attr_accessor to avoid instance variables in our controller and helper_method so we can avoid them in our templates:

Now our typos still raise NoMethodError, but now the error tells use that prodcut and prdoucts aren’t methods on our view and gives us the line number of our typo. It even gives us the handy did-you-mean-style error! 🎊

Now let’s fix our typos…

Now we have a few pros here:

  • Better errors when we make mistakes
  • We can also see what the templates use at the top of our controller (assuming we don’t also sprinkle in instance variables in the other controller actions)
  • We can also limit what our views can get at by just omitting a getter from the helper_method list. This is handy when you just want to avoid instance variables for information that’s only used by actions and/or their  hooks (before_action, after_action)

A couple cons:

  • Less conventional
  • Between self. and the declarations at the top we have to type more
  • We could make a mistake and mix up our product and products methods, but instance variables have this same problem 🙃

At the end of the day, it’s a small change to help avoid a small problem. If you don’t mind being a little less conventional, give it a shot. If not, that’s a fair tradeoff. As always, the important thing is that you follow your ❤.

Michael is a member of DevMynd’s software engineering team focusing on mobile apps and web development. He has been with the company since 2013.