Archive for the ‘rubyonrails’ Category

Fixing Rails Pagination for SQL Server

Tuesday, July 31st, 2007

MS SQL Server certainly feels like the red headed step child of the Rails connection adapters. The core developers aren’t interested in it, and I’d have to guess that most Rails developers deploy to MySQL or PostgreSQL.

A good example of why the SQL Server support needs more love from the Rails community. The pagination code in the connection adapter is horribly ugly. SQL Server 2000 doesn’t support a limit or offset, which makes pagination extremely difficult. For kicks, check out the SQL that the Rails connection adapter generates for a limit and offset query in SQL Server. There’s enough sub queries and reverse sorts to make your head spin. Not to mention the awful performance killing select count(*) before every query.

SQL Server 2005 makes our life a little easier in that it added row_number() support. With this, it’s possible, however not straight forward, to perform pagination that doesn’t make you want to puke so much. Unfortunately, Rails hasn’t yet split their SQL Server adapters into a SQL Server 2000 and SQL Server 2005 adapters. I strongly encourage this move, as there are many differences between the two.

If you are running SQL Server 2005, and you want to fix many pagination problems that plague the sqlserver_adapter.rb (just look inside the Rails Trac sometime, there’s a lot), have I got the monkey patch for you. We’ve been using this for a little while now, and it seems to do the trick. YMMV but it should hopefully give you an idea of what’s possible.

module ActiveRecord
  module ConnectionAdapters
    class SQLServerAdapter

      def add_limit_offset!(sql, options)
        if options[:limit] and options[:offset]
          options[:order] ||= sql.match('FROM (.*) ')[1] + '.id'
          sql.sub!(/ORDER BY.*$/i, '')
          sql.sub!(/SELECT/i,
                  "SELECT row_number() over( order by #{options[:order]} ) as row_num, n")
          sql.replace("select top #{options[:limit]} * from (#{sql}) as tmp_table1 n" +
                "where row_num > #{options[:offset]}")
        end
      end
    end
  end
end

Not only was the built in pagination queries terribly slow (because it always executes a select count(*) before the query itself), but it had problems when doing paginations with included models. This is something that ActiveScaffold does all the time, so if you are using that and SQL Server, you’ve no doubt felt the pain when you tried to sort a column.

Restful Account Activation

Tuesday, July 17th, 2007

Nearly every web application has the concept of users or accounts. While the concept of a user or account is quite universal, when you get to implementing, you find out that the business rules and implementation details vary widely from application to application. Luckily for your Ruby on Rails applications, there’s an excellent starting point for creating the basics of accounts and logins. The restful_authentication plugin for Rails provides generators for Users and the basic framework required, such as email activations, logins, passwords, controllers, and database migrations. The extra bonus is that the plugin uses REST to model the authentication.

In the REST web application world, all you see are objects, or nouns. The verbs in the system are limited to the HTTP methods such as GET, PUT, POST, and DELETE. REST advocates that you interact with the world (your nouns) with these four methods. It forces you to think, “How would I convert an Action into a Thing?”

With restful_authentication, the action is Login, but that concept is encapsulated into a Session object. When you login, you are *creating* a new Session. When you logout, you are *deleting* that Session. (Here, the Session is a different concept from a web session.) The plugin nicely models login and logout actions into CREATE Session and DELETE Session.

We can apply this concept to account activation, which I had to do recently for one of our applications. Our business rules stated that an account can’t access the system until it was activated by an administrator.

In the old pre-REST days, we might have modeled this with an action called activate, which might have set an activated bit on the account instance. Fair enough, and it would have worked fine. But this isn’t RESTful at all, as it would require a new verb in the system (activate).

Knowing that REST is all about the nouns, we noun-ify the concept of activation into a class called Activation. We say that an Account has one Activation, and if that activation relationship exists, the account is activated. If there is no activation instance for an account, then the account is deactivated. An administrator will CREATE an activation instance in order to activate an account. The administrator can later on DELETE the activation instance if they want to deactivate the account.

Another benefit of creating a first class Activation model is we can add properties such as when the account was activated and who activated it.

In summary, I love working with REST because it forces me to think in nouns, which are classes. I find it easier to model the world with nouns than with verbs. Plus, the problem with verbs is you can’t say anything about them, so you lose the ability to add metadata to the events in the system.

RailsConf 07 Wrap Up

Monday, May 21st, 2007

I’m back in Hawaii, having just returned from RailsConf07 in Portland. All in all it was a great time. CD Baby covered the conference fee and hotel room (at the Jupiter Hotel, very cool if you want a bar and night club just foot steps away) because I was a winner in the Rails Hackfest 2007 contest. So hat’s off to CD Baby!

Some closing thoughts:

* As always, choose sessions based on the speaker, not the topic.
* The tutorial sessions, common with O’Reilly conferences, just don’t seem to be worth it. They aren’t enough like a true class to really learn anything, and four hours is quite a long time to listen to a presentation.
* The best session that I attended, was The Business of Rails. The session had a great line up, was not a technical session, had no slides, was full of great Q&A, and generally was full of interesting, candid, and honest information. (I think too many presenters rely on their slides too much.)
* The quality of the sessions was very mixed. I hope next time, the conference organizers choose sessions based on the speaker more than topic itself. A great speaker can easily make up for a less than relevant topic. But an inexperienced speaker will crash and burn even the more interesting of material.
* I found the keynotes all very interesting, for two reasons. First, the keynotes usually are the creme of the crop when it comes to speakers. Second, they weren’t always directly related to Rails (such as Ze Frank and Avi Bryant), which made them so much more interesting.
* The value of conferences really rests with the networking. The technical sessions can be learned from blog posts or reading tutorials. The keynotes are usually viewable online at a later date. But meeting so many Rails contributors and users is difficult without the conference setting.
* I need to speak at one of these things in the future. Looks fun.
* I did speak for five minutes about the Dwarf Algorithm. Apparently, a scheduled speaker never showed up, so it turned into a lighting talk session. I was lucky enough to be granted Anthony’s spot. Thanks Anthony!
* O’Reilly needs to beef up their conference wifi networking support. I’d rather have a slow, but steady, connection, than a spotty connection.
* Portland is pretty nice. Lots and lots of coffee shops with Free Wifi and lots of great beer.

In closing, I’d have to say that Ruby on Rails is pretty easy, and as such, so many technical sessions are unwarranted. What the community needs is not another session on some Rails plugin, but sessions on how to help move the Web forward in a productive, friendly, and profitable way. We as Rails developers can learn how to use the framework with books and blog posts. But we need more of is community discussion on moving from Web 2.0 to whatever is next, being good Web citizens, and otherwise writing excellent software. I’m afraid Ruby on Rails is so easy, that we’re just going to have to start thinking about what we can *do* with the tool now.

And that’s a sign of an amazing framework, if we’re basically done thinking about the tool and instead are focusing on what we should be building with it.

Excellent REST Tutorial Series

Tuesday, April 10th, 2007

Softies on Rails is posting an excellent REST tutorial series. They are doing a great job in describing how a web application is just a collection of resources (and not necessarily web pages), and how you can think of your web application as the gateway to manipulate those resources. If you want to learn REST, and good web architecture, this tutorial series is the way to start.

This reminds me of the great “A resource is a web page about your car, not your car itself” debate.

Norm Walsh sums this debate up nicely:


Suffice it to say that some folks think http://example.org/some/path must identify “a document” (what the AWWW calls an “information resource”) and some folks think it can identify anything at all.

In any case, thinking of your web application as a collection of resources is the way to go. You don’t usually need to get all carried away with “what is a resource?” unless you are trying to model knowledge, but that’s another story

Ruby on Rails Mangles Decimal Type to Integer

Monday, April 9th, 2007

So when is a DECIMAL not a DECIMAL? Go ahead, take your time. I’ll wait.

A decimal type is converted to an integer by Ruby on Rails through its infinite wisdom. As seen in active\_record\connection\_adapters\abstract\schema\_definitions.rb, line 180 (in Rails 1.2.3):

when /decimal|numeric|number/i
extract_scale(field_type) == 0 ? :integer : :decimal

So, apparently, Rails thinks, “Well, I know you specified a decimal type, but hey, you didn’t specify a scale, so you must have made a typo! Here, let me just change that to integer for you.”

Or, in other words:

You: I’d like a hamburger with nothing on it.

Rails: OK, here’s your hot dog.

You: WTF??!?

Apparently, this issue has been reported before. However, as of Version 1.2.3 of Rails, this issue still exists.

I’ve just opened a new issue on the Rails Trac site. You can see if any of the core developers will see why converting a decimal to an integer is completely counter intuitive.

ActiveWarehouse Gets Some Love

Wednesday, March 28th, 2007

ActiveWarehouse, the Ruby on Rails plugin for data warehouse development, was written up by InfoQ in their article ActiveWarehouse, a New Step for Enterprise Ruby.

I’ve been writing different aggregation strategies for ActiveWarehouse, trying to find something that’s not too slow or cumbersome. ActiveWarehouse supports pluggable aggregation, or rollup, strategies, so you can use what works best for you. We have some very large data sets and very large dimensions (one dimension we have has 215 million rows). So if ActiveWarehouse can eventually handle that, I think we’re in good shape.

I can say that ActiveWarehouse will work great if you have a smallish data set. I would say up to a million rows in your dimensions would be big enough. Of course, no matter how much work we put into optimizing ActiveWarehouse’s aggregation schemes, smart database tuning will always help tremendously.

Refactoring REST: searching for an abstraction — Luke Redpath

Wednesday, February 7th, 2007

Luke Redpath makes a valiant attempt to DRY up RESTful Rails controllers as he writes Refactoring REST: searching for an abstraction. I can see how this can be very useful if your controller methods follow the simple paths. Good to see some implementation patterns emerge that build on the assumptions that your controller is RESTful.

ActiveWarehouse at RailsConf

Friday, February 2nd, 2007

My buddy Anthony Eden is presenting at RailsConf 2007. He’ll be talking about Data Warehouses on Rails with ActiveWarehouse.

I’m currently building a Data Warehouse fronted by Rails, and some of the code I’ve written has ended up in ActiveWarehouse. It’s a really interesting project, and I hope to see it bring data warehousing into every application.

I’ll be at the talk, hope to see you there!

Rails, Collections, Forms

Friday, February 2nd, 2007

I just figured out how to handle collections of unsaved ActiveRecord objects in XHTML forms rendered by Ruby on Rails, so I thought I’d share with the hopes of making the next person’s search a bit quicker. Note: This post assumes you have Rails 1.2 and are generally following RESTful principles and are using `map.resources`. The main concepts work without `map.resources` but you’ll have to tweak some of the URLs.

The problem: You have a collection of unsaved (new) ActiveRecord objects that you would like to render fields for in the same form. For instance, you want to let a user enter multiple phone numbers before they initially save the User object and its collection of PhoneNumber instances.

Solution: Turns out, Rails makes this pretty easy (but of course) but the hard part is just figuring out how. We’ll assume you have a controller method that initializes the user and a phone number. We’ll start with a single phone number just to make things easy.

def new
@user = User.new(params[:user])
@user.phone_numbers << PhoneNumber.new
end

Let's first create the partial for the phone number fields. We make a partial because there can potentially be multiple phone numbers for a user, so this will keep things DRY.

<% fields_for 'phone_numbers[]', phone_number do |f| %>


<%= f.text_field :area_code, :index => phone_number_counter %>

<%= f.text_field :number, :index => phone_number_counter %>

<% end %>

Notice the `phone_number_counter` variable? And the `:index` symbol inside `f.text_field`? We’ll get to those in a moment, but they are key to making this whole thing work.

In your `new.rhtml` file, you’ll need something like this:

<% form_for :user, users_url do |f| %>


<%= f.text_field :name %>

<%= render :partial => ‘phone_number’, :collection => @user.phone_numbers %>
<% end %>

If you’ve never seen `render :partial, :collection` before, go read up on it from the docs. It’s very handy.

The first time you render the page, you’ll see something like this (edited for clarity):

When you submit the form, your controller can handle the params as such:

# POST /users
def create
@user = User.create(params[:user])
params[:phone_numbers].each_value do |phone_number_params|
@user.phone_numbers << PhoneNumber.create(phone_number_params)
end
end

Summary: When create new instances of objects from a form in Ruby on Rails, use `render :partial, :collection` to easily loop through your collection, rendering the partial once for each item in the collection. Inside your partial, you will receive (for free!) a counter variable to let you know which iteration you are rendering. You can then use that counter as the unique identifier for your form fields. Once your objects are saved, though, they will have IDs and thus you won’t need to consult the counter for an identifier.

In fact, Rails makes that scenario drop dead easy. If your objects in your collection have IDs, then just leave out the `:index` symbol from your form field builders. Just by placing `[]` at the end of your form fields identifier (as we have above with `phone_numbers[]`) is enough to tell Rails to use the ID from the object when rendering. But again, if your objects are unsaved, you must specify `:index` as we have in the above example.

ps: Is there a better way to do this? Please, let me know!

Skinny user activation

Wednesday, January 31st, 2007

Toolman Tim has written up a short but sweet article on Skinny user activation. It’s his attempt at refactoring what every web application requires: user authentication. He attacks the problem from a perspective of Skinny Controller, Fat Model. That’s just fancy Rails talk for moving your business logic into the model classes, and cleaning up your controllers. Great work, Tim! Long live OOP!