
Being at RailsConf 5 has given us the opportunity to finalize a lot of the work we’ve done to prepare our plugins and gems for Rails 3. Thankfully, for many of the most popular gems, we’ve been able to maintain both Rails 3 and Rails 2.3.x compatibility in one gem. However, we’re taking this opportunity to say goodbye to some of our less widely used plugins, and some we plan on dropping Rails 2 support for altogether.
Obviously, Rails 3 isn’t actually out yet, so what we’re talking about here is Rails 3 beta 4. We’ll continue to keep things up to date and tested as we all move toward the release of Rails 3. Your help and patches are more than welcome.
So here is a comprehensive overview of the current status of the projects for both Rails 3 beta 4 and Rails 2.
We released Paperclip 2.3.3 a few days ago. This new version of Paperclip will work with Rails 3. Thanks to the investigation of nragaz and help from isaac and joeljunstrom on github, we worked out the kinks and it should be working with the Rails 2.3.x line, and Rails 3-beta 4. For the latest version of Paperclip, we’re no longer officially supporting Rails 2.0.x. The earliest version that will work is Rails 2.1.0. If you need support for an older version of Rails than that, you can use Paperclip 2.3.1.1.
A few days ago we released hoptoad_notifier 2.2.6 with includes support for Rails 3-beta 4 as well as all versions of Rails 2.x and Rails 1.2.6.
We just released shoulda 2.11. Along with Rails 3 support, we’re maintaining support for Rails 2.3.x in this latest release. However, the latest version of shoulda will not support versions of Rails less than 2.3. If you need support for a version of Rails older than that, you can use a previously released version.
In addition to the Rails 3 support, shoulda 2.11 introduces some dramatic changes to shoulda, including a new way of interacting with all shoulda macros. The previous way has been deprecated and will be removed in shoulda 3.0. We’ll make a separate blog post detailing many of the very cool changes to shoulda and more details about the future of shoulda soon, but for now, take a look at the README for the latest information on setting up and using shoulda.
We just pushed factory_girl 1.3 and factory_girl_rails 1.0. This new version adds Rails 3 support. Because of the way that Rails 3 loading has changed, we’ve decided to make a separate factory_girl_rails gem that will be used for when you want to use factory_girl with Rails. The existing factory_girl gem is used by factory_girl_rails and would be used if you’re using factory_girl outside of Rails. If you want to use factory_girl with Rails 2 you can continue to use the base factory_girl gem.
We just released Clearance 0.9.0.rc1. This is a release candidate for Clearance 0.9.0. This new version adds support for Rails 3 but drops support for Rails 2. Don’t fret, if you won’t be upgrading to Rails 3, you can use a previously released version of the gem (0.8.8). We’re doing this one as a release candidate because of the dropping of backwards compatibility and the fact that we haven’t had a chance to test the new version in a variety of Rails 3 apps using clearance.
Please flex this release candidate with your Rails 3 apps and let us know how it goes.
Suspenders is currently at 2.3.5 (we haven’t been able to upgrade to 2.3.8 because of bugs we’ve seen with mongrel, webrat, and rack). We anticipate that Suspenders will be upgraded to Rails 3 a little after Rails 3 final comes out. But to be honest, we’re actually not sure yet what the upgrade path will look like for applications that are currently tracking Suspenders. It may be impossible to do without so many conflicts that its not worthwhile. We’re going to have to work on this more and keep you posted. Additionally, we’re in the process of making some fairly dramatic changes to Suspenders. Watch it on github and stay tuned here for more.
Fire in the Disco! We’ve also released High Voltage 0.9.0 which supports Rails 3 and is now a gem (it was previously just a plugin). The new version also drops support for Rails 2. If you need the previous, Rails 2 plugin there is a rails2 branch you can retrieve it from.
We also just released Pacecar 1.3 which supports Rails 3 and drops support for Rails 2. As in the other cases where we’ve done this, you can use the previous version of the gem, version 1.2.0 with Rails 2, or track the rails2 branch.
Squirrel was born out of a desire to make a new query syntax that was dynamic while being clean and simple. With Rails 3’s introduction of the New Active Record chainable query language, that goal has now been achieved in Rails. As a result, we’ll no longer be maintaining Squirrel. It was a fun ride.
Over time, our workflow slightly changed for how we built applications and we haven’t used Mile Marker ourselves for some time now. As a result, we’re taking this opportunity to cease maintenance of this plugin and bid it farewell.
We’ve gotten more and more familiar with Rails 3 during moving all these gems to it. Many of the new features it offers are great, and existing features have been improved and cleaned up. We’re looking forward to Rails 3 finally being released in the coming weeks. Now that our plugins are up and running it should help us all to transition smoothly and quickly.
Thanks to the core team and various other railsconf attendees for spending time with us this week working on some of this - we’re looking forward to the final version of rails3!
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.
This is probably something that should have been done sooner, but I didn’t get around to it and it wasn’t immediately important to us. Since it now is, I changed Squirrel’s call to ActiveRecord::Base#find to include all parameters passed in, even the extra hash variables find normally uses. While this isn’t terribly amazing on its own (although it does mean you can use :limit even though it doesn’t have Squirrel-specific syntax yet), it allows the usage of the terribly lovely paginating_find plugin.
posts = Post.find(:all, :limit => 10) do
created_on > 7.days.ago
end
orders = Order.find(:all, :page => { :size => 5, :current => 2 } ) do
customer.id == params[:customer_id]
end
Both of these will work as expected now. Well, the second one needs paginating_find installed, but you know what I mean.
As always, the repo is at https://svn.thoughtbot.com/plugins/squirrel
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.
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)