Ruby on Rails

A Few of My Favorite Things: scope and Symbol#to_proc

Wednesday, March 16th, 2011 | Ruby on Rails | No Comments

Let's say you have a User model. Let's also say that you want the ability to archive your user records.

So, you add a boolean attribute called archived that defaults to false which can be set to true in order to archive your user records. Now you can look for archived records by performing the following query throughout your app:

Well that's nifty… until you realize that you're having to write out that blasted where() statement in five billion places throughout your application. Is that DRY? Quite the opposite, I tell you! What happens if you change that attribute's name, you're bound to miss at least a few instances of it in the change. For the love of all that is holy – this has just become a horrible solution!

Four solutions to this problem spring to mind: one is outright dumb, two are common and one is simply beautiful.

The first option is to put a query like this in our views.

Seriously, if you find yourself putting ActiveRecord queries in your views, just go back to PHP, please. If you're simply new to Rails and honestly don't know any better, read on. The second option is to put this query in your controller.

While this isn't necessarily a bad solution, it tends to get repeated… a lot in some cases, which once again goes against the "Don't Repeat Yourself" mantra. Another solution is to move this logic into the model. Well, well. You're one smart cookie, you! Skinny controllers, fat models. Let's move this clunky query into the model!

This is much prettier! But this method is gonna get all kinds of lost in any respectably sized model. This used to be the best way to store a query for frequent use until Rails 2.1 was released with named_scope in its bag of tricks. Now, in Rails 3, named_scope has a new persona, and it's here to… fight crime… and stuff.

Enter scope

The scope method belongs in the list of incredibly useful model methods along with associations and validations. This method expects two arguments; either a name and a condition or a name and a block. We can easily convert our above query using the name and condition combination.

This can be used to grab all of the archived users, similar to the previous example.

Delightful! Seriously, I feel like I just ate a Hot Pocket. Oh, actually, that doesn't feel good at all. But this scope looks great! It's clean, on one line and behaves beautifully.

So, how would we use a block with scope? Think of any situation where you'd want to pass data into a query. This is where you'd use a block with scope. In our example, we want to return all users with whatever role we pass it.

Now we reference the scope, passing a role into it as an option.

Holy cow! So, basically we can take a massive query and slap a small scope name onto it and reference it whenever and wherever we need to. If this query changes, we change it on one place. Graceful, elegant and easy to update.

Now that you know how scopes work, I would be a horrible teacher if I didn't introduce you to default_scope. This beast will allow you to specify some query goodness that you want appended to *every* query you run on that model. Using our example above, what good would an archived scope be if User.all returned the archived users too! Not very much use in my book. We can use default_scope to tell the model when we search normally, we only want the users who are not archived to be returned.

Now when we do a search for users, it will only ever return users who have archived set to false. Slick! But what if we want to get around that for a query or two? Let's say we want to count ALL users, archived or not. We'd use unscoped here. Let's pretend we have 75 users, 5 of which have archived set to true

Symbol#to_proc

One more thing. You may have recognized a reoccurring bit of code throughout my examples.

We're iterating through the list of users in the @users instance variable and outputting the name attribute of each. If you only need one attribute from each record in a list, you have just encountered one use case for Symbol#to_proc. Instead of an each block, we could simply use the following:

This list of names can now be used however you like. Perhaps a nice join() method would meet the need?

Now, go call your mom and tell her all about the wonderful things you learned here. After that, go forth and use scopes and Symbol#to_proc like the mofo you know you are!

Listing Social Networks in Ruby

Friday, June 25th, 2010 | Ruby, Ruby on Rails, Sinatra | No Comments

I spent a little time tonight working on The Enclave's new member page. The site overall is the most beautiful thing in the world, but I have been using it as an excuse to plan more with Sinatra.

Tonight, I found the need to provide a way for our members to list their social networks should they choose to do so. The obvious way was to add a list of anchor tags. I found this to be rather distasteful. I mean, we are dealing with Ruby here, right? So, I started by considering what I wanted the UI code to look like. Would do I want to have to work with on a weekly basis. I came up with the following:

This would allow me to add as many usernames and networks as I desired. Perfect! So I began to work on the code that would make this function as intended. I came up with the following:

So, basically, I list all of the networks I want to use. This list not only includes the URL (and a place holder for the username), but any prefix or suffix for the displayed username for which I might find a need (i.e.: Twitter's "@" in "@slant") Next, the script iterates through my list, catching each network as it does so. Each time the script reaches a network, it proceeds through each username in the list, building an appropriate anchor tag for each one.

In the end, you have a beautiful categorized list of usernames, each linking to their respective page.

linkedin: ryanlcross | facebook: rcross | twitter: @slant, @cylenceweb

Journey to Snow Leopard

Monday, September 7th, 2009 | Mac OS X, Ruby, Ruby on Rails | No Comments

Like many, I was in my local Apple Store on August 28th to pick up their newest operating system update, Snow Leopard. Despite hearing about some compatibility issues, my inner-first-adopter got the better of me and since it was basically the beginning of a weekend, I began down the path of the upgrade.

Luckily, I walked out of the installation process unscathed for the most part with only a few minor issues to deal with.  One example would be that Phusion Passenger was no longer working – but mongrel was – so that was livable.  Realizing that I'd not yet setup a decent database for development since getting my new MacBook Pro, I set to work on basically reinstalling the entire Rails stack to ensure that everything would be ready to roll when I get back to work on Monday.

I found a few fantastic resources to guide me through the majority of what I was looking to do including Hivelogic's guide on Compiling Ruby, RubyGems, and Rails on Snow Leopard as well as another guide on Compiling Git on Snow Leopard.  I also found some great information on installing PostgreSQL on Snow Leopard. Lastly, I discovered a very short guide on compiling the PostgreSQL RubyGem for use on Snow Leopard (enabling 64bit compatibility).

Equipped with these guides, I successfully got everything upgraded and am now waiting for all of the other 10.6 bugs to pop up!

edit: A definitive guide in deed. I just found a guide for those of you who want to install things like MySQL and SQLite as well.

Tags: ,

Presentation at Refresh Denver

Monday, September 22nd, 2008 | Ruby on Rails | 2 Comments

Last week, Jay Graves and myself presented the differences between Ruby on Rails and Django at Refresh Denver.  We decided on a common database schema, functionality and design.  We then each built the same application in our respective frameworks.

During the presentation, we each explained our frameworks on a surface level followed by a brief demonstration of how each framework accomplished a few of the things that our applications did.

Jay's presentation can be found here and his Django application here.

My presentation can be found here and my Rails application here.

Overall, I absolutely believed this presentation to be a success!  I'd like to see other frameworks and languages go head to head like this in the future.  I feel like the ability to see two frameworks side by side was a real benefit, allowing a clearer look at how each works with respect to the other.

Tags: , , ,

Using Hash#values

Monday, July 28th, 2008 | Ruby on Rails | No Comments

This is minor, but I thought it was interesting nonetheless.

I needed to iterate through the values of a Hash. So I called .values on the Hash in question. What was interesting about this had nothing to do with the results of calling this method, but instead what it was actually doing to the Hash.

>> myhash = { :first => "one", :second => "two", :third => "three" }
=> {:second=>"two", :first=>"one", :third=>"three"}

The myhash how has a class of Hash, which is to be expected, since that's what I gave it.

>> myhash.class
=> Hash

When .values is called, it returns all of the values in the Hash.

>> myhash.values
=> ["one", "two", "three"]

You may have noticed this in that last example, but when .values was called on that Hash, the class of the result changed altogether. Let's examine the class of this Hash while we are calling .values on it.

>> myhash.values.class
=> Array

So calling .values on the Hash literally built an Array with the values from the preceding Hash!

Read more about Hash#values in the Ruby Documentation.

Tags: ,

Git Aliases

Monday, July 28th, 2008 | Ruby on Rails | No Comments

There has been talk about how to shorten Git commands, mostly in an effort to assist those of us who are coming from Subversion. One proposed solution has been to use the alias mechanism native to your shell environment.

Another solution does exist. This one is internal to git itself. Due to that fact, the two main benefits are a shorter load time when starting a new shell (since you're not dealing with alias entries in your .profile script) and easier git-centric configuration.

Simply add the following to ~/.gitconfig:

[alias]
  co = checkout
  st = status
  br = branch
  ba = branch -a

Now instead of typing git checkout branch you only need to type git co branch. You can customized these as much as you'd like, adding other commands as well, as long as the command after the equals sign is a valid git command.

The obvious down side to this method is that you have to type git before these aliases. Using the other method, you do not.

Tags: ,