Tag Archives: Rails

For Heaven’s Sake, At Least Test the CRUD

The very first integrated (feature) specs I setup it is to test the CRUD. If you don’t do anything else with feature specs, please, at least do these tests. You will be amazed at how much of your application is actually exercised and covered just with these simple tests.

Yes, you can and should test much more. And they don’t replace good unit and integrated tests.  But you will be surprised how many bugs these basic tests will catch. For example, my nemesis, the dreaded undefined method `blahblahblah' for nil:NilClass  in views.

These test will ensure the Adult model will:

  • Display all views (this alone is huge)
  • Data can be entered, displayed, updated, and destroyed (CRUD)
  • Model validations are respected
  • Potentially test model relations

I am going to show you how to test #index, #show, #edit, #update, #new, #create, and #destroy of a resource, an Adult model. I’ll break it down because the full spec file is long.

Here is the entire spec in it’s original project: adults_spec.rb

Setup

A little pre-knowledge would help; we are using Devise (for authentication), Rspec (for testing framework), Capybara (for integration tests). Note, we are not testing JavaScript in this test, and therefore invoke the RackTest as the Capybara driver for maximum speed.

Warden.test_mode!  gives us some nice Warden helper methods to use during testing. Notably the login_as(user, scope)  method. Warden is used under-the-hood by Devise.

seed_all_records  is just a method that will create a complete structure of records so that we have something to find and display. For example, it could create a user, company, orders, invoices, inventory, etc.

IMPORTANT: I am loading these records in a before(:all) do  block so that they are not recreated for every test. If  seed_all_records  creates a long and complex amount of records, as this real-life version does, it can dramatically speed up the test.

CAVEAT: If we need to create other new records, we need to manually keep track of them to delete them after use. See the #edit example.

For every test, the first thing we do is view the index,  visit unit_adults_path(@unit) . I like to start here and “click” the appropriate links to edit/show/delete tests.

#index

So we take a look at the index page, a table with a list of names (adults) and we check that we see some basic data (links and text).

 #show

We view the show page by clicking a link from the index page (Adult name). First, we make sure we are looking at the right show page. Then we click the “Return To List” link and make sure we go back to the index page. Finally, we try the “Edit” link of the Adult name and make sure were are taken to the edit form.

We look at the page.current_path  and test it to make sure we are on the right page. This may not work in your application as some paths may contain query values or other errata. But for simple specs with standard Rails routes, it works.

 #edit, #update

Like I noted above, we will need to create an Adult because we are going to change their data and we don’t want to affect the existing records. In an after do  block, we will delete this Adult.

We create this new Adult, then we make some changes in the edit form. But don’t submit yet! We’ll do that later.

In the first test, we submit the change, and make sure that any form changes we make are reflected on the Adult’s show page. Success! We can edit and submit Adult records. This tests a significant amount of the Adult model, validations, and potentially more (relations, counters, etc).

Lastly, we test that if the user cancels the edit, they are returned to the Adult show page and none of the entered changes are saved.

 #destroy

“I brought you into this world, I can take you out.”

Create a new Adult, then revisit the index page and click on the new Adult’s destroy link, and make sure they are gone and return to the index page. We also check that the flash notification is displayed.

Note: if you use a confirm: 'Are you sure?'  like Rails suggests as a default for destroy links, because we are using RackTest, it will not execute that JavaScript. Thus there is not confirmation dialog to click.

 #new, #update

Saved the longest for last. Also, the most important.

We are going to test two contexts: entering valid data, and entering invalid data.

Enter Valid Data

Simple, we click on the New Adult link, enter a bunch of data into the form, and save it. Then we verify that we are taken to the show page and can see all the data we entered.

This particular form has several select elements that allow the user to select from a list of options, as well as establish relations to other models. This is a good place to test this, but it could also be tested in #edit, #update. We verify that this Adult can have related Scouts, and no related Scouts. This also tests your models, validations, and relations. Good tests to have.

Enter Invalid Data

We want to see that when we enter invalid data, that model validations are respected, and that the record is not saved. When trying to submit invalid data, we return to the new form and check that the proper flash message is displayed.

In this example, I only test one field’s validation, that the Adult’s first_name can’t be blank. This is an excellent place to add more test for more validations.

 Conclusion

Put it all together, and you are testing a lot. I know they seem like simple tests, maybe too simple for some. But I think they are boilerplate for much more.

I said it before, but it bears repeating: setting up these basic CRUD integrated tests will catch a surprising amount of bugs.

Posted in Rails, Rspec. Tagged with , .

Creating Cache Keys for Rails Relations

For years I have been using the cache_key_for_*  method, as seen in Rails Guides and many other places. Here is an example.

It works. But even this venerable snippet couldn’t escape the refactoring razor.

.size vs .count

First change is using products.size  instead of products.count . A minor change, but if ActiveRecord has already executed the sql query, using the .size  method will prevent it from executing another query, as .count  may cause.

Sean Griffin has a quick say in this battle. TL;DR Rails users should always use .size .

DateTime Number

Second, the original used a long chain of trys and then converting the DateTime of updated_at to number format. You might be breaking the law… of Demeter that is.  That ‘number’ format looks like this: 20150410030422. It’s just the date and time.

Well, you can accomplish the same thing without chaining so many methods: use .to_i. Read about it at the docs. This one method uses the UTC time and gives you the number of seconds since the Unix Epoch. It looks like this: 1428635331.

Both has the same 1 second resolution, but the refactored version is shorter, which may save memcached memory if you have a lot of keys. I just think it’s cleaner, and avoids all the method chains.

Assembly

Finally, we just need to assemble it all in a string. By putting the size and time value into an array, we can use all those wonderful enumerable methods. You could just as easily use string interpolation and avoid the map and join.

Important Footnote

Rails has been using nanosecond resolution for their cache_key method for a while, assuming your backend supports factional second datetime values. My method only has 1 second resolution. If you require more granularity for your cache keys, by all means, use the original cache_keys_for_*  method and change the .to_s(:number) to .to_s(:nsec).

Posted in Rails. Tagged with .

Why Rails and Their Committers Are Awesome

I love keyword arguments when they were introduced in Ruby 2.0, and use them every chance I get. As I was hacking around with ActiveJob today, and thought it would be cool to pass keyword arguments into the ActiveJob#perform_later method.

I thought it should work. It didn’t.

You get an  ArgumentError: wrong number of arguments (1 for 0) error. The reason is the hash is converted to string keys upon serialization.

So I was thrilled when I did a bit of searching to see if anyone else had the same issue. Nope. Looked at the ActiveJob::Arguments module. Passing keyword arguments are not supported. I actually get to report a real feature request to Rails!

So here is my ActiveJob should support passing of keyword arguments to perform method.

This this is where the magic began… within a few minutes Sean Griffin (@sgrif) picked up on the issue report. I went to lunch, planning to fork ActiveJob and start hacking away when I got back. But Sean beat me to it. Sean added the ability to pass keyword arguments to ActiveJob jobs, and even backported it to Rails 4.2.1.

Within an hour, it was all done. Check out the full commit.

Want a reason to love Rails and their committers? This is one, of many.

Thank you Sean.

Posted in Rails, Ruby. Tagged with , .

SQLite3::ConstraintException: table.created_at may not be NULL

So, I’m working along in Rails today, added a new migration, when all of a sudden tests that were passing only a few minutes ago suddenly start failing. The error I in rspec is something along the lines of:

In test.log:

WTF? This was working only a few minutes ago.

If you google this, you will read endless others who experience the same error… when using HABTM relations. Well, EventSignup has no HABTM!

This has happened to me a couple of times, and each time it leaves me puzzled for far too many minutes, and there is no real solution.

Okay, well there is only one solution I have found to work: delete the SQLite database file and recreate. Yeah, that sux. Oddly enough, just a quick:

And all is good again.

If anyone has an idea why this happens, I would love to hear why.

Posted in Rails. Tagged with , .

Rails Nested Attributes with Scoped Uniqueness Validation of Association

This is going to be a long one, so grab your favorite beverage…

Problem

I have a fairly standard belongs_to  and has_many model association. And I want to save nested attributes along with the parent when creating a new parent record. But, I don’t want the user to be able to submit duplicate values for the child records.

Sounds easy. That’s what I thought when I started.

My Solution

 Models

We have an Organization and a SubUnit models, pretty standard stuff here.

Controller

The controller is simple (standard actions removed). Keep scrolling down.

View

Now it’s getting interesting.

Your form should look like this.

/organizations/new

Polluting Links with Javascript

Like everyone else who has started down the road to nested attribute bliss, you have watched Ryan Bates’ Railscast on Complex Forms. It’s superlative.

But there’s one thing I didn’t like… the heavy handed approach of using link_to_function. Especially when including a fair amount of escaped html into an onclick script. I’m not saying it’s wrong, just that I believe html should stay where it belongs… in the DOM. Heck, they even created a gem nested_form.

I think we can make it simpler, painless, elementary.

That’s where the following little ditty comes in handy. We are creating the exact same field structure that is used for entering a SubUnit, but hiding the html so that we can use JavaScript to copy-and-append to the visible entry area.

Line #1: hide the div.

Line #2: use fields_for to generate the proper field id and name attributes so that it is submitted as a child object to our Organization. Notice the SubUnit.new? That prevents this block from iterating over all the @organization.sub_units that may be built, either as a new object (controller line #5), or when re-rendered due to a validation error with @organization.

Line #2: don’t forget the child_index: ‘new_sub_unit’ option! Without it, rails will attempt to index the fields id and name attributes with numbers, which in this case would be 0 (zero), and mess up the prior sub_unit fields. IOW, you will end up with two params[:organization][:sub_units_attributes][0] elements.

If you don’t understand all the details, take a few minutes and read the ActiveRecord::NestedAttributes::ClassMethods.

Now for some JS magic:

Pretty simple, bind to the click events of the add-sub-unit-button and remove-sub-unit-button to functions.

add_sub_unit function copies the new-sub-unit-fields div, replacing the text of ‘new-sub-unit’ in the id and name attributes of the input/label elements with an integer.

remove_sub_unit function hides the input field group, and set the ‘_destroy’ hidden field to “1” (‘true’ also works) so that it will not be created when the form is submitted.

Inspiration for this JavaScript goes to Ryan Bates.

Status Check

At this point we have a parent model, Organizations, with nested attributes for children SubUnits. When creating a new Organization, you can add and remove SubUnits. The entire relationship is submitted with a single form post.

Eliminate Duplicates in the DOM

Everyone else does it in model validations, manipulation of the params hash, or some other convoluted way. But I decided to eliminate duplicates before the submission of the parent form. Pretty easy, actually.

When the Create Organization button is clicked, the above JavaScript loops through all the SubUnit form field elements, marking duplicate entries hidden ‘_destroy’ field with ‘true’, thus preventing them from being saved. Could you just remove the elements? Sure.

Inspiration for the JavaScript remove duplicates in an array to Roman Bataev in this post.

Screen Shot 2012-12-21 at 4.38.21 PM

If you watch your logs, you’ll see that all the SubUnits attributes are submitted, but only those marked with the hidden field ‘_destroy’ == ‘false’ will be created.

The astute reader will also notice that the SubUnit model is attempting to validate the uniqueness of the name attribute, scoping it to a non-existant Organization. I admit it would be best to skip this validation, but I will leave that exercise to you, humble reader.

Sample App

What? You wanted a demo app on the GitHubs? You shall be rewarded, post haste.

Synopsis

The Good

  • Submission of a parent Organization with children SubUnits utilizing nested attributes.
  • Duplicate SubUnits are removed.
  • Darn simple, easy to reproduce. Pretty darn unobtrusive, too.
  • No funky helpers to jack some html into a link element.
  • Is it better than Ryan Bates’ solution? No. Just simpler.

The Bad

  • Only works on creating a new Organization. Does not work for editing an Organization with the ability to add additional SubUnits or destroy existing SubUnits. Future post?
  • My JavaScript is not abstracted to make it easily reusable. Fork it, and submit a patch if you so desire.
  • The SubUnit validation should be skipped when creating through an Organization.
  • No fallback if JavaScript is disabled.

Additional Reading

 

Posted in Rails. Tagged with , .

Small Revelation – FactoryGirl, build_stubbed, associations, and let

Not really a problem, but something I didn’t really look out for because all my tests were passing… and hey, if tests are passing, I sleep well.

TL;DR Dumped let{}, removed FactoryGirl associations, back to before(:all) and instance variable/FG.build pattern = super speedy tests. 
TL;DR.1 And read the docs.

Background

I need to test a fairly complex permission matrix at the model level. To properly test it, I need to build out several complete company structures, with a multitude of users at various authorization levels. And 200+ actual tests.

Being a fan of rspec’s let{}, I decide to use it copiously. 40 lines worth.

In these tests, I don’t really need to have persisted records, so using FactoryGirl.build_stubbed fits the bill here.

let(:company) { FactoryGirl.build_stubbed(:company)}
… an so on, 39 times. 

What I Found

I thought one particular spec was running a little slow. So I converted the FactoryGirl.build to the shiny new FactoryGirl.build_stubbed. No difference in time. So I decided to watch the test.log. Well, I quickly saw what was happening… it was persisting thousands of records.

But wait. I was using FactoryGirl.build_stubbed. Where were all these records coming from?

Problem #1

In most of my FactoryGirl factories, I was using ‘association :area‘, ‘association :store‘, and so on. Didn’t think much about these until yesterday.

Turns out that FactoryGirl will build/create and save those associated factories, even if you are using FactoryGirl.build or FactoryGirl.build_stubbed. Learned something new there. Honestly, I didn’t expect this behavior, but I understand why. Shoulda read the docs.

Now, the easy way around this is to pass into a FactoryGirl.create/build/build_stubbed a nil for the association, if it is not needed. Ala:

FactoryGirl.build_stubbed(:store, company: fg_company, area: nil)

Now it won’t build out the associated area. Alas, I had forgotten just one of these nil associations. And at the worst possible relationship level, the bottom. So every time one factory was built, it create the entire supporting structure above. Thus, every hit to an let(:invoice) builds an entire company structure from one single FactoryGirl.build_stubbed(:invoice) call.

But it get’s worse.

Problem #2

I love the let{}. But to be honest, I never read the docs on it. Well, I did read them yesterday. Relavent line being (emphasis added):

The value will be cached across multiple calls in the same example but not across examples.

Uh-oh. Let{} is like a before(:each). Which is what most specs need. But I don’t, not for this spec. I’m never modifying the AR records, just testing some methods within models, which don’t modify AR instances.

Resulting Big Problem

Ok, not really a problem. But certainly very, very inefficient.

By forgetting to nil an association in a FactoryGirld.build_stubbed, and with let{} recreating an entire company structure, to the database, for every 200+ test. Well, you get the picture. It’s slooooow. 22 seconds worth of slow.

Solution

You know I wouldn’t drag you along this far without a solution.

  1. Just remove all the ‘association :model‘ statements from all FactoryGirl definitions. I know they are handy, but I want CONTROL over my factories. And just one small mistake can make a spec run many X-times longer.
  2. Remove the let{} and replace with the good ol’ instance variable/build pattern.
  3. Move all the instance variables into a before(:all).
before(:all) do
  @company = FactoryGirl.build_stubbed(:company)
  @store = FactoryGirl.build_stubbed(:store, company: company)
  … and so on, 38 times.
end

Note for step #1. It caused me to refactor some other specs as well. This turned out to be a good thing, as I was able to speed up several other specs, and add some clarity to those specs that required building out a company structure.

Results

2.5 seconds. Not too shabby.

After the refactoring for all tests, I dropped ~30 more seconds off the entire suite.

 

Hope this helps someone else out there improve the speed of their specs too.

Posted in Rails, Ruby. Tagged with , , .

Apache Virtual Hosts, Rails, Rack, Passenger on Local Net

This one has been bugging me for a couple of years and I just didn’t want to put in the time and testing to nail it down. But tonight was my night.

The Problem

Here in my development palace I have a couple of laptops that I use for development and an Ubuntu (hardy) server as a Rails/Rack sandbox that I run with Passenger. While I have always been able to serve up either a Rails or Sinatra project, I typically have 3 or 4 going at the same time. But I had to access them with urls like: http://192.168.0.2/project1 and http://192.168.0.2/project2.

So, what’s the problem, eh?

Well, for starters, you can’t do anything concerning subdomains. That’s a show stopper for many apps.

Second, it really messes with your environment variables like [“PATH_INFO”]. So if you do any routing and you expect the base url to be ‘/’, it won’t be. The root url will be ‘/projectx’. Bummer.

The Solution

To remedy the issues with non-tld virtual hosts (also called sub URIs?) we need to add the domains to the laptops and server, then add the virtualhosts on the server for apache. This means that I can now goto http://project1.ubuntu.remote url to get to my rails/rack app.

For reference, I am using the following:

On Each Laptop

These instructions are for Mac OS X, but should be identical for your favorite flavor of *nix. We are going to add some friendly names to our ubuntu server using it’s ip address (192.168.0.2). In this example we will be able to access the root web documents using http://ubuntu.remote, and one of our Sinatra projects using http://project1.ubuntu.remote.

Important! Don’t use a name ending in ‘.local’. While it did work for me, I read about a few instances where some systems will not resolve domain names ending in .local outside the local machine. Also, don’t change anything else in your /etc/hosts file except to add the lines at the end.

[source language=’python’]
mate /etc/hosts

# add the following line to the END of your /etc/hosts file and save
# note: there is a character between the ip address and each host name
192.168.0.2 ubuntu.remote project1.ubuntu.remote
[/source]

On The Server: Hosts File

Nothing will work until we tell the server machine that it can accept incoming traffic from our new friendly names. Similar to on the mac, we need to edit our /etc/hosts file but we will add a slightly different line. In this case we are telling the server that incoming traffic from ‘ubuntu.remote’ and ‘gems.ubuntu.remote’ are just names for the localhost (127.0.0.1).

[source lang=’shell’]sudo pico /etc/hosts

# add the following line to the end of our /etc/hosts file and save
# you can added after your existing 127.0.0.1 line if you wish
127.0.0.1 ubuntu.remote project1.ubuntu.remote
[/source]

On The Server: VirtualHosts

As a final step we will need to add or change the virtual host definitions for your rails/rack project. Depending on your Apache setup or Linux distro, the default enabled site may be slightly different and you may have to adapt your virtual host file to your default setup.

First, in my /etc/apache2/apache.conf file, I have the following line near the end of the file. This was to eliminate a warning every time apache was started/restarted. It may affect your virtual host default, but shouldn’t, so add it if you get errors.

[source lang=’shell’]
#added near end of /etc/apache2/apache.conf
ServerName localhost
[/source]

Next we need to check our default virtual host setup to see how the NameVirtualHost is defined. We will duplicate that in each new virtual host that we add. The parts we are looking is the NameVirtualHost and VirtualHost near the top. They could be ‘NameVirtualHost *’ and ‘<VirtualHost *>’ or ‘NameVirtualHost *:80’ and ‘<VirtualHost *:80>’. See the pattern? We need to use the same definition in our new virtual files.

Let’s check our default virtual host setup:

[source lang=’shell’]
cd /etc/apache2/sites-enabled
ls # your are looking for the name of your default site file

total 0

lrwxrwxrwx 1 root root 36 2009-02-27 18:49 000-default -> /etc/apache2/sites-available/default

cat /etc/apache2/sites-enabled/000-default

NameVirtualHost *

  ServerAdmin webmaster@localhost
# snipped several lines #

[/source]

On my system the NameVirtualHost is ‘*’, so that is what we need to use for the new virtual host. In this case, I am going to add a virtual host file for a rack based project. It’s a Sinatra app, but that doesn’t matter as this will work for any rack based project, even a rails/rack project (since rails 2.2.2?).

Also, I like using the Apache2 system to enable and disable sites. It’s clean, easy to use, and if any apache admin comes along they will know exactly what is going on.

It’s also work mentioning that you should disable or delete any existing virtual host files that you were using previously.

[source lang=’shell’]cd /etc/apache2/sites-available
sudo pico gems

# enter this as your virtual host setup

ServerName project1.ubuntu.remote

DocumentRoot “/path/to/your/application/project/public”

RackEnv production

Order allow,deny
Allow from all

# save the file and reload apache

sudo /etc/init.d/apache2 reload
[/source]

The Fun Part

Assuming you saw no errors when you reloaded apache, you should be able to go to your new urls see both the root files and your rack application.

http://ubuntu.remote
http://project1.ubuntu.remote

Dyn-O-Mite!

Bonus Points!

For extra credit, let’s say you have admin access to your router, and you are one of those gotta-have-control-of-everything dudes (or dudettes) so you installed a 3rd party firmware. You’re in luck! You can probably add some custom entries in your DNS and you don’t have to edit the /etc/hosts files on your laptop.

I installed Tomato firmware on my Linksys wireless router. Tomato uses Dnsmasq with allows you to set internal host names.

Maybe I’ll cover that in another post.

Posted in apache, Rails, Ruby. Tagged with , , , , .

Authlogic – Rails Authentication Done Right

Sorry to borrow the title line directly from Ben’s site, but Authlogic is the authentication system I have been looking for. Bye, bye restful authentication. Hello easy, simple, get out of my way, easily upgradeable, smartly written Authlogic.

I shouldn’t disrespect restful authentication much as she has been with me for over a year now. But every time I had to install, setup, and get the basics working in RA I couldn’t help gnashing my teeth. I jumped on the RA bandwagon like so many other Rails developers looking for an authentication system that just and move on to more important things.

Enter Authlogic by Ben Johnson of BinaryLogic. By luck, I was starting a new rails app this week, so I decided to take Authlogic out for a test drive. Following Ben’s Tutorial: Authlogic Basic Setup I had a basic login/logout/session management system up and running in a ridiculously little amount of code. The best part of Authlogic is that it truly get’s out of my way and provides me with what I need… a robust and secure methodology of authentication and session management.

The benefits of Authlogic are:

  • It’s a plugin and a gem. When Ben pushes an update, getting the latest release is super simple.
  • It’s a plugin and a gem. This keeps the authentication code separate from your codes, the way it should be.
  • Session are treated like ActiveRecord objects. This is just as cools as it sounds and is very Rails-like.
  • Better security. Authlogic uses a non-reversible token that is changed on every session initiation and password change, thus virtually eliminating session persistence and brute force session attacks.
  • Ben Johnson. Ben knows what he is doing and has been quickly releasing updates.
  • Ben Johnson. Sorry for the repetition, but Ben also has a nice series of tutorials with supporting project code you can download.
Read more on on BinaryLogic or get it at Github.
Posted in Rails. Tagged with , .

Butt Biter: Rails ‘truncate’ Method Broken in Ruby 1.8.7

This one threw me for far too many minutes. In ActionView::Helpers::TextHelper the truncate method is broken for Ruby 1.8.7. I’m not exactly sure the version of ruby that it stopped working for, but I was previously on 1.8.6, and I don’t recall it not working. But after I upgraded to the latest patchlevel of 1.8.7, truncate stopped working.

Update 12/2/08: Fixed in Rails 2.2! (read more)

The error that I received was thus:

ActionView::TemplateError (undefined method `length' for #) on line #83 of dashboard/index.html.erb:

Fortunately, someone has submitted a ticket to Rails core. I hope it’s applied in the Rails 2.2.0 release.

Continue reading

Posted in Rails. Tagged with , .

Ruby on Rails Ubuntu Server VM with VMPlayer

I had to setup a Ubuntu (8.04) Server virtual machine and get Rails up-to-speed on it this morning, so I thought I would document my steps for those who find the need to repeat. Here is what I needed:

What you need to start:

Continue reading

Posted in Rails, Ruby. Tagged with , , .