Using Variants in Rails 4

I’ve been using Variants in Rails 4 to change my layouts for one controller action. It’s really straightforward – just set the variant name as a symbol, for example:

request.variant = :popup

Then name the template file with the variant name in it, e.g.

new.html+popup.haml

Another neat trick I discovered is that you can also use the variant to control the layout file. I wanted to have a different layout for my popup content, one that didn’t include all of the usual bumph like headers and menus. Turns out I didn’t need any other code, just create a template in my layout folder with the variant:

website.html+popup.haml

In addition to that, I can also use it with partials. Inside my haml file, I reference a partial as I would normally, and when the variant is set, it automatically chooses the partial with the variant if there is one.

...
= render partial: 'customer' 
...

Now I can use the popup variant across multiple controllers with this same simple layout.

I also discovered that setting variant to nil causes a problem. I wanted to do this:

request.variant = find_my_variant
...
...
...
def find_my_variant
  return nil if some_logic_determining_no_variant
  :variant_name
end

Instead I have to do this:

request.variant = find_my_variant unless find_my_variant.nil?
...
...
...
def find_my_variant
  return nil if some_logic_determining_no_variant
  :variant_name
end

I’m interested to know if there is a way to set a “blank” or default variant so that I can remove that extra check …

Try and Fetch

One of my colleagues showed me this awesome little method in Rails called try.

How many times have you written code to check for nil like this?

def get_value
  if @my_object.nil?
    ""
  else
    @my_object.value
  end
end

(well I have, many times!)

If you call try on an object if you’re not sure whether or not it will respond to that method. If it doesn’t, then you just get back nil:

def get_value
  @my_object.try(:value)
end

Particularly useful if you want to call a method on something you get back from a hash that may not be there:

@my_object[:my_key].try(:method)

While reading up on this, I also discovered the fetch method for Hashes, which allows me to specify a default value to return if the key is missing.

This means I can clean up stuff like this:

my_array = @my_hash[:my_key]
my_array.each {|array_item| ... some code ... } unless my_array.nil?

To this:

@my_hash.fetch(:my_key, []).each {|array_item| ... some code ... }

Less if statements, less branching, and so hopefully fewer bugs to write!

Upgrading to RSpec 3

I recently upgraded our Rails application to use RSpec 3, which is currently in its second beta, from 2.99. I was expecting it to be nice and straightforward, but sadly it was not! This was partly because we have been using RR for mocking and stubbing, and the syntax was not compatible with RSpec 3.

In the process of upgrading I learned a bunch about the new RSpec “allow” syntax, which in my opinion is far nicer than the RR one we were using.

Here’s how to stub:

allow(thing).to receive(:method).with(args).and_return(other_thing)

Mocking can be done in the same way by substituting “allow” for “expect” – although in most cases the tests read better if you test that the stub received the method using the following matcher:

expect(thing).to have_received(:method).with(args)

That this is different to the previous RR syntax, which was expect(thing).to have_received.method(args)
You can also use argument matchers, for example:

expect(thing).to have_received(:method).with(a_kind_of(Class))

And you can verify how many times a method was called:

expect(object).to have_received(method).at_least(:once)
expect(object).to have_received(method).exactly(3).times

The .with(args) and .and_return(other_thing) methods are optional. You can also invoke a different function:

allow(thing).to receive(:method) { |args| block }

Or call the original function:

allow(thing).to receive(:method).and_call_original

Another thing we used fairly often was any_instance_of. This is now cleaner (RR used to take a block):

allow_any_instance_of(Class).to receive(:method).and_return
allow_any_instance_of(Class).to receive(:method) { |instance, args| block}

If you pass a block, the first argument when it gets called is the instance it is called on.
In RSpec 3, be_false and be_true are deprecated. Instead, use eq false or eq true. You can use be in place of eq, but when the test fails you get a longer error message, pointing out that the error may be due to incorrect object reference, which is irrelevant and kind of annoying.

Using RSpec mocks means that we can create new mock or stub objects using double(Class_or_name) rather than Object.new, which results in tidier error messages and clearer test code.

Stubbing a chain of methods may also be a handy tool – I only found one place where we used it, but it is useful if we’re chaining together methods to search models.

allow(object).to receive_message_chain(:method1, :method2)

More info:

  1. https://relishapp.com/rspec/rspec-mocks/docs
  2. https://github.com/rspec/rspec-mocks

Update: it turns out I was missing a configuration option in RSpec. It should have worked with RR by doing this:

RSpec.configure do |rspec|
  rspec.mock_with :rr
end

Thanks Myron for clearing this up :)

Sydney Ruby on Rails User Group

I attended the Sydney Ruby on Rails user group last week. There was a pretty decent size crowd, and the talks were hosted in the upstairs room at the Trinity Bar and Grill in Surry Hills, with beer and food available from the upstairs bar. I was disappointed to see that there were only three girls there though, it would be lovely sometimes to not stick out so much!

The talks are short, only 15 minutes each which is perfect because there’s never time to get bored. It also means, however, that it’s difficult to get very in depth with anything.

First up was Mario Visic talking about using declarative steps with cucumber, which are far less detailed and attempt to describe the business requirement, rather than the imperative style which is more granular and contains scenario data. The arguments are that declarative steps will change less as the design of the system changes, and that business people can write them. More about declarative steps.

I have my reservations over whether it would actually reduce the overall volume of changes or just move them out of the steps. I’ve never known business people write steps (and in fact somebody asked the question whether Mario’s client had written any steps, to which he replied no!) and I would be interested to know what QAs think of this style.

It’s an interesting idea though and one I might try on my next project if I can.

Next was David Parry on CoffeeScript, something I’ve been wanting to try for a while. I learned that one of its aims is to produce perfectly JS-lintable Javascript, which is very cool. You can also convert existing Javascript into CoffeeScript to make the move across easier – I think the tool demonstrated was JS2Coffee.

I also learned that CoffeeScript puts everything inside an anonymous function, so calling functions directly doesn’t work. I must put some time aside to play more with it!

The last talk was about learning from some specific mistakes by Andrew Grimm, which included large classes and the importance of writing maintainable code. These are things that everybody should be aware of, not just Ruby developers!

Lastly there were a few five minute talks including quick tips by Scott Harvey – who mentioned the ‘grep’ method for arrays that I discovered through the Seven Languages book, and two interesting talks encouraging people to join entrepreneurial courses and start up weekends. Some of these are similar to the Launch 48 events I enjoyed in London, so maybe I’ll go meet some Aussie entrepreneurs soon!

All in all it was a fun night, I’m looking forward to the next one as well as the SydJS group next Wednesday!

Seven Languages Week 1: Ruby

Week one of the seven languages is complete!

Having the support of the study group was great – motivating but without being too much. I was amazed at the breadth of the solutions, especially to the homework for Day 1 and Day 2.

Day 3, I was a bit underwhelmed by – the final part of the chapter introduced a lot of interesting techniques with meta-programming and modules, but the problem set didn’t really seem to challenge me to think too much about them.

The book encouraged me to look at the API to try and find solutions for different problems. Having the study group made this aspect even better, because we often found different things – for example, collect and zip methods for arrays. James in particular found some very short and neat ways to solve the problems.

Overall I think I like Ruby even more after doing this. It has so much “syntactic sugar”, and I definitely have a sweet tooth! Overall I’ve learned that while you can use Ruby to write programs in a rather boring, more Java-esque style, there is almost always a much neater, Ruby-ish way of doing it. I only wish I had more time and opportunities to learn it properly.

My highlights:

  • Day 1 reminded me of the usefulness of ranges
  • Quick ways to convert between hashes and arrays in Day 2:
  • Discovering the ‘grep’ method in Enumerable from James’ day 2 solution.
  • Finally getting a better understanding of modules (still far from perfect, but I definitely get them far better than before)
  • Learning the ‘zip’ method for arrays – although still not sure I completely understand how to use it!

My solutions are here: https://gist.github.com/jocranford