Implementing a View Helper in Ruby on Rails

I keep hearing that we shouldn't have any logic in our views.

Fair enough.

Then what? Good question. I also keep hearing that we should be using helpers.

Roger that.

So...how?

Yesterday I spent quite a bit of time searching for just such a topic. But what should I search for? I won't bore you with the details, but I used several terms. I kept falling back to "view helpers rails" but didn't get much.

As always, Stack Overflow (www.stackoverflow.com) came to the rescue.

Piecing together several posts I was able to come up with some winning syntax. Got a better way? I am not being sarcastic when I say that I'm all ears. For I was really unable to find any good documentation. At all.

First a little background.

The object I'm working with is a ticket. That means I need to place this code in the tickets helper. I'm working in legacy code and so I can't be certain this file is created automatically, but it exists in app/helpers and is named "tickets_helper." I'd suspect this is all by design (naming, location).

The code I was hoping to move out of the view was a simple conditional. If a ticket's alternate phone number field had data in it, I wanted to display this.

Here's what it looked like:

  <% if @ticket.ovr_phone.present? %>
  <tr>
    <td class="panel-table-label">Alternate Site Phone</td>
    <td><%= @ticket.ovr_phone %></td>
  </tr>
  <% end %>

I copied and pasted that code into tickets_helper.rb and got to work. Here's what I came up with:

  def display_ovr_phone(ticket)
    if ticket.ovr_phone.present?
      content_tag(:tr) do
        concat content_tag(:td, "Alternate Site Phone", :class => "panel-table-label")
        concat content_tag(:td, ticket.ovr_phone)
      end
    end
  end

I then went back into the original view and replaced the previous code with:

  <%= display_ovr_phone(@ticket) %>

Mission accomplished! Hopefully you can disassemble the helper code and see how it all happens. These posts helped much and I'm sorry to say the actual Rails documentation did not.

Posts:

Documentation:

My intent was not to get down on the documentation. Being open source and all, if I don't like it then I should initiate a pull request and attempt to implement my own code.

My frustration lay in not knowing how to put the pieces together. It's still a bit sketchy, actually. But I have this one bit of code licked!

Cheers!

Compare file timestamps using RSpec

Inside an RSpec test I wanted to compare file timestamps.

Several of the examples I found were intended for people who actually needed to parse the file. That is to say they were modifying a file and then wanted to verify the new text existed in the file. Not what I needed.

But...

They did use this "File" class in ruby. So I poked around a bit and found the documentation for this class. (http://www.ruby-doc.org/core-1.9.3/File.html)

I had no idea what I was looking for so I read through all the methods until I found "mtime." It "returns the modification time for the named file as a Time object." Perfect! (http://www.ruby-doc.org/core-1.9.3/File.html#method-c-mtime)

For the sake of simplicity, let's say I'm generating "test_file.pdf."

Using rails's console I can view the file's timestamp. (The following syntax was a shot in the dark, gathered from information I'd found at several sites.)

> File.mtime("#{Rails.root}/<path to file>/test_file.pdf")

returns

 => 2012-02-28 13:34:24 -0600

Well then, how would I incorporate this into a test? What if I:

  • stored the original timestamp in a variable
  • regenerated this file
  • stored the most recent timestamp in another variable
  • compared the two

Could it be so simple? You better believe it.

original_pdf_timestamp = File.mtime("#{Rails.root}/<path to file>test_file.pdf")

latest_pdf_timestamp = File.mtime("#{Rails.root}/<path to file>/test_file.pdf")

latest_pdf_timestamp.should_not eq(original_pdf_timestamp)

Done.

 

 

Updating a gem in your rails application

Step 1: run "gem update <gem name>"

Step 2: run "bundle update <gem name>

That's it!

How to keep guard-rspec from being so damn greedy (run only one spec)

My development computer here at work is old and tired. Also, I'm probably using WAY too many fixtures in my rspec tests. Because of this, any rspec test will last at least 60 seconds.

Until I remove all unnecessary records from these fixture files I need to make good use of my time. I had installed and was using guard-rspec (https://github.com/guard/guard-rspec), a very handy gem. With no configuring it would run the spec I had modified and if this spec passed it would run all specs. When combined with libnotify, the user will be notified of test results once they've all finished. This freed up a minute (at least), which let me move to another shortish task.

However, like I said, my tests are slow. I'd like to not run all tests if I could help it.

Being unable to purchase a new computer here at work I am forced to be crafty. And by crafty, I mean I spoke with my boss about how I'd love to keep using guard but would prefer it didn't run all the specs if the most recent one passed. (Okay, I'll admit that I may have called it "greedy.")

He looked at the documentation and found there is indeed such a way to do this.

When you first run guard (using the guard-init command), a file is created at your rails application's root directory. It's called "Guardfile." Note: if you're using netbeans, don't even bother looking. It hides quite a few things on you.

Find your guardfile and open it. Change "guard 'rspec', :version => 2 do" to "guard 'rspec', :all_after_pass => false, :version => 2 do". Note that you added ":all_after_pass => false" as an option.

If everything goes well the next time you modify and save a spec file, guard-rspec will only run that file!

 

Copying your production schema into your test database - Ruby on Rails

Was attempting to run a fairly simple rspec test this morning and it was failing. Not because some assertion expected "orange" and received "apple," but because of something else.

Once I actually read the error, I found a column was missing in my test database. AHA! I have you now, tricky test error.

Or do I?

Back I went to bare mysql commands, hoping to dump the schema of the production database then use this in my test database.

Everything appeared to work (and by that I mean that when I attempted to load the schema into my test database a bunch of code went scrolling by and none of it contained errors). "I have mastered thee, mysql, even though I have Ruby on Rails."

Or...no.

Eventually, after trying exactly the same thing several times (I kid you not, I expected different results. This, it's been said, is the definition of insanity.) I resigned myself to trying something elegant. "There must be a solution for this built into Ruby on Rails. It's not unreasonable to think a developer would want to load a production schema into a test database."

And sure enough, here it is. Lifted from http://thinkingrails.blogspot.com/2007/06/rails-rake-tasks-reference.html

rake:db:test:clone

# Recreate the test database from the current environment's database schema

Testing with Capybara - a tricky little something

When last we left our fearless hero, he was deep in the entrails of the abominable capybara.

He ended up suspecting that his adventures through the cavernous recesses of this monster were too uneventful. Too...easy. Something unsettling came over him.  Something isn't right.

So he backtracked, retracing his steps.

"What happens if I purposefully set a booby trap at this point?"

He set a trap, stood back, sprang the trap, and...

Nothing happened.

He blinked.

He stared quizzically at the trap, scratching his noggin. "I must have done something wrong," he thought.

Nope. The trap appeared to be set properly.

As it turns out, using:

    page.has_xpath?('path_to_some_nonexistent_element')
    # This will pass and should not

is not the same as

    assert page.has_xpath?('path_to_some_nonexistent_element')

    # This test fails, as it should

or

    page.should have_xpath('path_to_some_nonexistent_element')

    # This test also fails, as it should

Rats!

Disclaimer: I do not mean to call Capybara a monster, quite the contrary. It's made my life as a testing developer much easier. Thanks, Jonas et al!

About