Agile Web Development 2nd Edition

If you’ve got the first edition of this book or about to buy it to get yourself started with Ruby on Rails, don’t buy it. The 2nd edition is now available in a beta form and it’s well worth it. The most recent additions to Rails really the original print largely obsolete. Yes, that much has changed.

Getting a little off track with my project

I got to a point where I think I’m getting a little off track with my Rails project. In trying to make sure everything’s perfect along the way, I think I’ve lost sight of the rapid development part of it all. When building my models, I wrote out a lot of tests to make sure things were working. While I am glad I did that, it isn’t the way to get the application in a usable state right away.

I’m very glad I did write the unit tests, since I’ve already had to make a change where the tests were correct but my models stopped working. Running the unit tests helped me fix the problems quickly.

As I proceed to build the controllers, I’m doing what I can to get the pages to work navigationally so people can login and click around the site and see at least static content. I’ll go back in and add actual logic, including funtional tests, as I code the details.

It just dawned on me that I’ve been doing a lot of work and my co-workers haven’t been able to actually see the site. This is Ruby on Rails, so I figured that was backwards. I guess I’m still getting used to it all.

I have decided that authentication plugins for Ruby on Rails suck

My first thought when it came to implementing the authentication for my current application was to check out plugins and generators others are using to make adding this a simple five minute process. I had read about some issues with one of the first such plugins like this from when Rails was first made available, but I figured by this time they had matured a bit. I checked out a few, the primary contenders being the acts_as_authenticated plugin and the LoginEngine. LoginEngine had a nice video demonstration showing how easy it was to integrate with your site. I was going to need role-based security and part of what won me over was that LoginEngine had a sister engine for dealing with just that.

After an entire day of playing around with LoginEngine and not getting anywhere close to the results I wanted, I decided to scrap using it and any other ready-made authentication system and just write my own. I ended up wasting more time failing to adjust LoginEngine to my needs than just writing it from scratch based on information in the Agile Development with Rails book and the upcoming Rails Recipies.

But hold on, these things are great. Lots of people are using them.

Lots of people may be using them, but they are not great in all situations. I can only see them saving time in applcations where they would work out-of-the-box without modification. I do have some custom requirements which are not built into any of these plug-and-play systems.

Here’s what’s wrong

  • If you’re learning Rails, using an authentication system will not teach you anything.
  • In a lot of cases, you’re not saving much time.
  • If you need to change much with what’s there, it will take you longer than if you had written it yourself in the first place. I’m sure if you had a lot of knowledge about them, this would not be as big an issue, though.
  • David Heinemeir Hanson is vocal about his cautious view on Engines and other high-level components.
  • Just the other day, the release of Rails v1.1.1 broke LoginEngine. Look through the comments. The Engine people fixed it quickly, but it broke.

This sums it up

David Heinemeir Hanson summed up how I feel about these things from my short-lived experience with them.

The short summary is that high-level components are a mirage: By the time they become interesting, their fitting will require more work than creating something from scratch.

Defining the language of a Ruby on Rails application

Previously, I created some wireframes and setup the initial migrations to build out the tables for my application. Now it’s on to creating the models so I can actually use Rails to save data.

Generating a model

I already generated all of my tables, but I really could have done it one table at a time. With Rails v1.1 the script/generate model command defaults to generating a migration script for the model. Luckily, you can tell it to skip this with the appropriately named option of —skip-migration.

script/generate model User --skip-migration

Since I skipped creating a migration file in db/migrate, generating the User model created the following files:

app/model/User.rb
test/fixture/users.yml
test/unit/user_test.rb

With the empty template files created, I decided to write my tests first. They should mostly fail, but the point is to add the approprate code to the model to get them to pass.

My problem creating unit tests

Starting out, I’m relying heavily on reference. I’m sure a lot of people are using the Agile Development with Rails book. The basic tests I started out with ran okay. However, when I started working with fixture data as described in the book, I started getting errors like this:

RuntimeError: Called id for nil, which would mistakenly be 4
 -- if you really wanted the id of nil, use object_id

After a quick search for the error on the web I found Mike Clark’s description of what the problem was. At some point, the defaults for the way Rails runs test changed in order to improve performance. Therefore, the methods described in the book no longer work (at least the first printing I have). If you had a fixture named fred in your test/fixtures/users.yml file, you used to be able to reference it as @fred in your test functions. You can’t do this anymore by default. I therefore changed references like @fred to the now preferred format of users(:fred).

On with the unit testing

With my problem figured out, it was on to test scripts. Unit tests are used to test models. I started out with some very simple models to get my feet wet before tackling ones with more complex behavior.

Since testing is a large topic, I’ll leave the samples and details to other sources like A Guide to Testing the Rails and just give you an example of a test function used to make sure that a user can’t be created with a username that already exists.

 # use function names that would make sense in a story
def test_that_we_cannot_create_a_username_that_already_exists
   good_user = User.new
   good_user.username = "testuser"
   good_user.password = "password"
   #
   # this user should save so assert that it does
   #
   assert good_user.save, good_user.errors.full_messages.join("; ")
   #
   # now try to add a duplicate username
   #
   dupe_user = User.new
   dupe_user.username = "testuser"
   dupe_user.password = "password"
   dupe_user.save
   #
   # This user should not have been saved
   # so only cause a test failure if it DOES exist
   #
   assert_raise(ActiveRecord::RecordNotFound) { User.find(dupe_user.id) }
end

I could have used some fixtures to simplify things, too.

The problem with tests are that unless the model has the rules in place to enforce them the tests fail. Therefore, we need to add the appropriate code to our models so our tests pass.

Making the unit tests pass by creating the model

Since I was able to quickly write up some tests that said my models weren’t doing what I wanted them to do, I had a small bit of work to do. Luckily to prevent duplicate usernames, there was only two lines I need to add the logic.

validates_presence_of :username
validates_uniqueness_of :username

The first line just makes sure we have a username and the next informs Rails to make sure the value is unique. This was all that was necessary to have my test pass.

Based on what I’ve been through so far, most of your validation should be about as easy as what you’ve seen. You can definitely get more complex. The application I’m working on has voting periods which are not supposed to overlap each other. Unit tests helped me out a great deal by allowing me to quickly put the code into place to make sure when I add a voting period, it doesn’t conflict with the date range from another one.

Next steps

I have a lot of unit tests and rules and relationships in my models now. There’s still some missing stuff here and there, but I’ll be able to add it later when I need it. All my current tests will be useful later on to make sure I don’t break anything.

My next stop is to start setting up controllers, create functional tests and get some web pages working. However, one thing I need to think though first is authentication and security. Even if I’m not initially checking security, it’s probably better in the long run to have the function calls in place from the start. At the very least, I should have an idea for how I plan to implement it.

Starting my first big Ruby on Rails app

I’ve settled into a new project and I’m excited that I’ll be using Ruby on Rails to develop it. With the recent release of Rails v1.1, it seems to be a great time to start. I’m going to try to stay on a weekly schedule during development. Hopefully I’ll hit upon most of the issues someone has when they’re initially getting into Rails and I’ll be able to provide some helpful information.

What am I building?

First off, while I would have loved to just dive into the code and start building things, this project turned out to not be the best to do that with. I started by building out wireframes. The main reason was that I was building off of someone else’s vision and the wireframes offered a way to learn what that was very quickly and also provided our designer the same information and something he could build a design from. It took roughly three days and I now feel I know what I need to do.

wireframesI created the wireframes using Visio with the templates and stencils available at Garrett Dimon’s site. Using these will save you a whole lot of time if you need to build some wireframes. I would use Omnigraffle on Mac OSX, but I’m just more familiar with Visio.

Sketching the database

ERD sketchOnce I had a better understanding of the site, I went to work on the tables I’d need in the database. I generally use pen and paper initially to draw out the tables I think I’ll need along with the relationships. When this is ready to become more finalized, I then go back to Visio to create an ERD diagram and start adding fields. Again, my familiarity with Visio is why I chose it. If anyone has recommendations on a good ERD tool for OSX, I’d be interested in checking it out.

ERD in visio with hand written notesMy intent with the ERD is not to create a living, breathing document connected to the database. I’d love that, but it’s more about quickly coming up with a starting point to get into creating Rails migrations and creating the models. You’ll notice some handwritten notes, too. These were pointing out things I missed which then get updated in the document.

Migrations

If you’re not familiar with Migrations, here’s a good rundown on it. You can get further information on the Rails wiki UsingMigrations page. Basically, they allow you a nice method for updating and rolling back changes to the database. You can also add and alter data, as well.

This was straightforward for the most part, the only part I had to research was in creating some join tables in a has_and_belongs_to_many relationship. These tables don’t need an id field and the create_table function adds it by default. There’s an :id option you can set to false to suppress it. Here’s an example:

create_table :messages_images, :id => false do |t|
   t.column :message_id, :integer, :null => false
   t.column :image_id, :integer, :null =>false
end

Next steps

Building out the language of the application with unit tests and models. From the first Dallas Ruby Brigade meeting, Adam Keyes mentioned that he starts his Rails apps by creating his models, which defines the language he’ll use in the rest of his application. This made a lot of sense to me so that’s the approach I’ll be taking.

More Articles

Page 6 of 9 » ‹ First  < 4 5 6 7 8 >  Last ›