giant robots smashing into other giant robots

We are thoughtbot. We make web & mobile apps.

Tagged:

Comments (View)

A smattering of t-bot news

So, we just got word that the last chapter for our book has made it through the copy editing stages and has been delivered to ‘production’. We’ve got the proof of the cover, and we’re on our way to release it in September.

You can preorder it now from Amazon.com

Also, we’re almost up and running with our new New York City office. Located at 407 Broome St., we’re sharing space with the great folks at thehappycorp

Finally, we’d like to welcome our newest member to the thoughtbot team, Dan Croak. We met Dan while working with (for) him on National Gazette and we’re very happy to have him join us.

We’re continuing to look for excellent programmers and web designers (or people who want to be) for both our Boston and NYC offices, for more information go here.

Tagged:

Comments (View)

Paginated Squirrel

Latest and greatest…

001 >> posts = Post.find(:all) do
         updated_on > 1.year.ago
         paginate :page => 4, :per_page => 10
       end
    => [...]
005 >> posts.total_results
    => 46
006 >> posts.pages.current
    => 4
007 >> posts.pages.current_range
    => 31..40
008 >> posts.pages.next
    => 5
009 >> posts.pages.previous
    => 3

The new paginate squirrel method takes a hash with :page (1-indexed) and :per_page (which default to 1 and 20, respectively). When you use it, your results array is automatically extended with a helpful pages method that gives you all you need to know to paginate your views. It also puts a total_results method on there, so you know how big the whole search is.

And before you ask, yes, I know some of you asked for this to work with paginating_find, and it does. But we found that paginating_find was conflicting with other plugins, leading to some really weird errors. Plus, it’d always been my intention to add pagination (among other things) anyway.

Please Note: The repo has changed. It’s now at https://svn.thoughtbot.com/plugins/squirrel/trunk for the trunk and https://svn.thoughtbot.com/plugins/squirrel/tags/rel-1.0.0 for this release.

Tagged:

Comments (View)

Squirrel - Once More, with Feeling!

I admit, the first iteration of Squirrel wasn’t really as super fabulous as I thought it would be. Because of how I was using the blocks, you couldn’t do a simple thing like access params. And since half the fun of it was being able to make good looking, flexible queries, not being able to use params was a giant pain.

Now, however, I’ve managed to mix the clean, functional look of instance_eval with the husky utilitarianism of params to come up with a happier, shinier Squirrel:

users = User.find(:all) do
  blog.title == params[:blog_name]
end

And what’s that in the trees, gracefully swinging from vine to vine? It’s our friends any and all here to give us grouping blocks!

site = Site.find(:first) do
  any {
    domains.hostname == params[:hostname]
    domains.hostname == "www.#{params[:hostname]}"
  }
end

All the functions you’d expect to be able to use in your controller are available (well, as long as you actually are in your controller, anyway; squirrels aren’t miracle workers)—params, session, etc.

You can use the unary minus to negate any condition or block, and you can also use it to do a descending order_by

Post.find(:all) do
  -any {
    title =~ /^OMG/
    id == 4
  }
  order_by -created_on
end

This is a major rewrite from the original code and cleaned up things in a very good way. And what’s more, we’re using it in real code now, so I have a fire under my ass to keep it in fighting shape.

The SVN repo is https://svn.thoughtbot.com/plugins/squirrel/trunk for all of you itching to try it out.

Tagged:

Comments (View)

Squirrel - Natural Looking Queries for Rails

I’ve never liked how you query the database in ActiveRecord. Sure it works, but so does writing straight SQL. Neither seem very integrated into the framework. So after thinking about it, I figured I’d do it one better and make something a little more Rubyish looking. So I made Squirrel.

posts = Post.find do
    user.email =~ "%thoughtbot%"
    tags.name === %w( ruby rails )
    created_on <=> [ 2.weeks.ago, 1.week.ago ]
end

I’ve seen various plugins for making queries nicer, but none looked like Ruby, because even in the best of them, they still used what I consider to be overly-awkward nested hashes to get relationships. Squirrel automatically gets the relationships and builds them as you use them. It supports all the normal associations, and it does it in a much friendlier way.

You reference associations by whatever name you gave to it in the has_many, belongs_to, etc. You can then access all the columns and relationships on that model. It is rather specific, though, and will raise errors if you misspell your relationships or don’t pluralize right.

And you simply reference columns by their normal names and use any of ==, ===, <=>, =~, >=, <=, >, and < on them pretty much like you’d expect to be able to (before you ask, yes, I cribbed the syntax from ez_where, since it makes sense). It handles nil values in == with a quick trip to IS NULL and it handles negation of conditions through the unary -.

It doesn’t yet do all the fancy stuff I’d like it to, like adding aggregation columns, limiting, or even OR joins and grouping, but it’s still much better looking than normal ActiveRecord::Base#find queries, I think. It does have some fancy stuff like order_by and placeholders, though. Here’s an example with both:

query = User.find do
    company.name = cname?
    order_by created_on
end

When you do that, instead of an array of results, it hands you back Squirrel’s Query object, which is the base of all its querying (imagine that). From there, you call find on it and pass a hash of the names of the placeholders you specified. No surprises there. (Also, you can get a query object for inspecting the SQL by passing :query to find, like so: query = User.find(:query) {id == 2})

users = query.find(:cname => "thoughtbot")

Now, what’s tricky is that you could pass any syntax-changing value to that and you’d get the right SQL in the executed query.

query.find :cname => "thoughtbot"              # =>   company.name = "thoughtbot"
query.find :cname => nil                       # =>   company.name IS NULL
query.find :cname => ["Google", "37 Signals"]  # =>   company.name IN ("Google", "37 Signals")

So there you have it. I think it makes queries much more readable and easier to maintain.

You can obtain it with a simple piston init https://svn.thoughtbot.com/plugins/squirrel/trunk vendor/plugins/squirrel

(Updated to reflect correct URL)