Archive for the ‘rubyonrails’ Category

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!

Portland, Here I Come

Monday, January 29th, 2007

Thanks to CD Baby, I’m going to RailsConf 2007 for free! I was one of the Top 20 Rails Contributors during Hackfest 2007. I want to know what Jeremy McAnally did to win first place with 1955 points. That man is a machine.

Some Thoughts on CRUD

Thursday, January 25th, 2007

I sent a helpful PDF on Rails support for CRUD and REST to a buddy of mine. He asked for some clarifications. Here’s what I sent to him.

Try to think in nouns, and not verbs. Nouns are your Model classes, things which you can have instances of (User, BankAccount, Book, Login). That last example, Login, is where (hopefully) the light bulb goes off. Consider if you could only Create, Read, Update, or Delete *things* (nouns). How would you do a login?

One way, the old way, is to add a login method on your user controller. Think about what you’re saying. You want to call the method (or *verb*) “login” on User. Already you can see we’ve left the CRUD methods, and a warning bell should go off.

If a user authenticated via User.login, what artifacts are generated? Are you simply returning a boolean? If so, how do you track logins? How do you ask “When was the last time I logged in?”

To solve the problem, you noun-ify the concept of login. Create a Login model, and make a relationship between User and Login.

User has_many :logins

This way, you can Create an instance of Login. No more special verb for login, just Create one. This way, you’re tracking all logins as *things* (nouns) and you can do CRUD on them all you want.

The moral of the story is: Think in *things*, not actions. Nouns instead of verbs. Use relationships like `has_many`, `has_many :through`, and `belongs_to` to connect the dots. Then, you are free to have very simple Controllers which are only concerned with CRUD methods.

Once you get these core concepts down (which are just standard Web app best practices), you can investigate Rails’ REST support. It’s a bunch of conventions to help build CRUD apps.

Rails Tests With Fixtures Suddenly Stopped Working From Command Line?

Thursday, December 28th, 2006

Now, this is a weird one. I’m hoping someone might have a clue as to why this started.

All of my Rails tests work fine in RadRails. However, if I try to run them from the command line via `rake`, they fail. After much searching, turns out that only the tests with fixtures were failing. And after even more investigation, it turns out that the method `setup_with_fixtures` was never being called. This method is defined in `fixtures.rb`, which also aliases the `setup` method to `setup_with_fixtures`.

To get my tests which use fixtures to work again, I had to place a call to `super` inside my test’s `setup` method. This kicked off `setup_with_fixtures` just fine.

Now, here’s the weird part. This all works without the explicit call to `super` in RadRails. Also, apparently I don’t need this call because the builtin generators don’t include that call.

So, something is happening in the load order on the command line with is altering the behavior of `setup` in tests.

validates_date_time Not Ready for Prime Time

Wednesday, December 20th, 2006

Just a warning to those that might be looking to use `validates_date_time` for Rails.

It turns out that it implements its own date and time parsing. This is separate from the current date and time parsing in Rails, which is currently handled by the DB driver. This dual reality is very confusing, and creates two different parsing logics and semantics in your application. I fought for an hour trying to figure out why ‘2006-1-1′ was not a valid date. It was working before this plugin.

Reason? My current database, MySQL knows what ‘2006-1-1′ is and thus was able to parse it. But the plugin doesn’t know this format.

I’m not saying that I approve of the fact that the date/time conversion is handled by the database driver. In fact, I know it’s not very portable. But this plugin should rely on that behavior, or be much more liberal and understand 2006-1-1, or use any existing Date or Time parsing.

Another odd thing about this plugin is that `validates_date_time` can’t handle just ‘1/1/2006′, as it is expecting a time part in there. It doesn’t default to midnight.

For the time being, I’d recommend writing your own `validates_datetime` to match what you are expecting. Don’t reinvent the wheel. If you need to do date parsing, there are existing options to rely on.

Testing Rails ActionMailers

Tuesday, December 19th, 2006

The Exciter has a great post for testing Rails ActionMailer fixtures. It tells you to throw out the generated fixtures and tests that come from the generators, and to write very simple tests that check bits and pieces of the email’s content.

Sometimes, You Just Don’t Need a Plugin

Wednesday, December 13th, 2006

I loved this blog post by Obie Fernandez because it illustrates how we, as developers,
sometimes choose the more technically challenging way to do things
instead of just the simple way.

In blog entry, this developer needed to solve a problem, and ended up
writing a whole rails plugin for it. If you read through the
comments, you’ll realize he took the difficult route. His problem
could have been solved by some simple OOP.

Read the blog entry, from top to bottom including the comments. I love it
because it shows how sometimes you just need to write a few lines of
code. :)

Locking Rows in SQL Server 2005

Friday, December 8th, 2006

There turns out to be a few different ways to lock rows in SQL Server 2005.

The `SERIALIZABLE` tag is one of the options. Here are a few more:

SQL Server Row Locking Strategies

As an aside, Rails (and Hibernate) support object locking with database locking semantics. In Rails 1.1.x, only optimistic locking was supported. Rails 1.2 added support for pesimistic locking.

Hibernate accomplishes the row lock with:

return tableName + ” with (updlock, rowlock)”;

AFAICT, Rails punts on this. I can’t find the locking syntax in the connection adapter. There is an add_lock! But it expects the locking syntax string unless you can use the default (`FOR UPDATE`, which of course SQL Server doesn’t support). That’s pretty lame on Rails’ part. But anyway…