Rails on the Run

Rails experiments by Matt Aimonetti

Browsing Posts tagged spec

Like most people who started with Rails a while back, I first loved Rails fixtures and ended up hating them (slow, a pain to maintain etc…).

I went through different experiments, trying different existing libs, writing my own solutions etc… I wasn’t quite satisfied until I found factory_girl from thoughtbot.

You might not feel the need for a decent fixtures solution if you do a lot of mocking/stubbing, but I recently came back from my “mock everything you can outside of models” approach and I’m getting closer to the mock roles, not objects approach. So, I’m loosing my model/controller testing separation but I’m gaining by not having to maintain “dumb mocks” which don’t always represent the real API behind. I mean, how many times did I change a Model, messing up my app but all my specs were still passing. Anyway, that’s a long discussion, which will be covered by wycats during merbcamp

So here is a simple example of how I use factory girl in a Merb + DataMapper app. (you can do the same in a Rails app, there is nothing specific to Merb in factory_girl).

  • I. create an empty app, set the ORM etc…
  • II. git pull and install factorygirl from http://github.com/thoughtbot/factorygirl/tree/master. Or install thoughtbot-factory_girl gem using GitHub gem server.
  • III. create a spec/factories.rb file. (You might prefer to create a folder called spec/factories and add a factory per model)
  • IV. modify spec_helper.rb and add the following
  require 'factory_girl'
  require File.dirname(__FILE__) + '/factories/index.html'
  • V. write some specs against a Client model

  • VI. Create the Model

  • VII. create a factory

  • IIX. run your specs

    failing specs

  • IX. fix the model (note that I set dependencies "dm-validations" in my init.rb)

  • X. run the specs

    passing specs

  • XI. add more specs

As you can see, Factory.build(:client) only creates a new instance of the Object, while Factory(:client) creates, saves and loads the instance.

  • XII. get them to pass

Factory Girl makes fixtures simple and clean. Here is another example for creating associations:

Factory Girl also supports sequencing, check out FG read me

In conclusion, Factory Girl is a mature and solid factory solution which will take you less than 15 minutes to get used to. It will offer you loads of flexibility and less frustration than good old yaml fixtures. You can also use it with existing fixtures if you want to start using it in an existing app.

DrNic the most famous Australian Rails developer surprisingly doesn’t spend most of his time working on Rails read interview
That’s maybe why he recently became so active in the Rails community ( see Magic Multi-Connections, Magic Models, map_by_methods, Gem Generator etc..)

Today he released something very helpful for the Rails Community, not another Gem or another cool plugin to extend Rails but a web application to help you planning your conferences. We already had other tools such as conference meetup but it’s the first time that we get a product helping you to plan a conference by scheduling the sessions you want to attend.

screenshot

screenshot of the entire schedule

I had a quick chat with DrNic about his latest creation and here is what he said:

“its been fun building just how I thought session selection might look + feel
web2.0 = permissive voyeurism I think!”

I share the same vision than Nic on session selection and I really enjoyed booking my Rails sessions and seeing what other people selected. (I guess that’s my voyeur side, don’t you like web2.0?)

If you wanna see what I planned on attending, checkout my schedule: my schedule

Thanks Nic for the good work and too bad you are not presenting anything at the RailsConf (move your bum to come up with a better submission next year!)

With the recent Buzz around Adobe Apollo I figured out that since I recently switched to Mac and that I didn’t try the latest Flex upgrade, I should try Flex 2.01 for Mac.

I really like what Adobe did with Flex, Unit testing, better accessibility, etc… but one thing I regret, it’s getting closer and closer to Java and AS3 syntax is a pain to use when you got used to Ruby.

Anyway, what I really wanted to do was to have Flash quickly access my Restful Rails app. The adobe guys came up with a RoR Ria SDK but well…. it only covers Flex and requires FlashPlayer 9.
I also found some great tutorials on how to use the efficient AMF messaging protocol with Rails using the WebOrb for Rails plugins

All that was really nice and I had fun, but it was an overkill for what I wanted to do. Let me show you how in less than 5 minutes how you can access you Rails Model from Flash and add some new item directly from Flash.

Create your new Rails app and use the script/generate scaffold_resource command to generate your Event Model.

script/generate scaffold_resource Event

It should create all that for you:

exists  app/models/
  exists  app/controllers/
  exists  app/helpers/
  create  app/views/events
  exists  test/functional/
  exists  test/unit/
  create  app/views/events/index.rhtml
  create  app/views/events/show.rhtml
  create  app/views/events/new.rhtml
  create  app/views/events/edit.rhtml
  create  app/views/layouts/events.rhtml
  identical  public/stylesheets/scaffold.css
  create  app/models/event.rb
  create  app/controllers/events_controller.rb
  create  test/functional/events_controller_test.rb
  create  app/helpers/events_helper.rb
  create  test/unit/event_test.rb
  create  test/fixtures/events.yml
  exists  db/migrate
  create  db/migrate/001_create_events.rb
  route  map.resources :events

let’s edit the migration file:
db/migrate/001createevents.rb

class CreateEvents < ActiveRecord::Migration
  def self.up
    create_table :events do |t|
      t.column :title, :string
      t.column :description, :string
      t.column :location, :string
        t.column :starts_at, :datetime
        t.column :ends_at, :datetime
    end
  end

  def self.down
    drop_table :events
  end
end

And let’s add some fixtures:
test/fixtures/events.yml

meeting:
  id: 1
  title: Meeting
  description: Boring meeting with the whole staff
  location: conference room
  starts_at: 2007-11-02 09:00:00
  ends_at: 2007-11-02 10:30:00
Joe_bday:
  id: 2
  title: Joe Bday Party
  description: Come and celebrate Joe's Birthday
  location: Lapin Agile Pub
  starts_at: 2007-09-07 20:00:00
  ends_at: 2007-09-07 23:30:00

Ok, now simply migrate your database,load the fixtures and start the webrick:

rake db:migrate
rake db:fixtures:load
script/server

Great, we are done with Rails.

Let’s launch Flash

Create a new Flash document and create a new .As fie in TextMate (or your favorite editor). We’ll write a quick ActionScript class to access Rails.

class Restfulflash{
    public var gateway:String;

    function Resftfulflash(gateway:String){
        this.set_gateway(gateway);
    }
    public function set_gateway(gateway:String){
        this.gateway = gateway;
        trace("gateway set to:"+gateway);
    }

    public function get(model, callback){
        var railsReply:XML = new XML();
        railsReply.ignoreWhite = true;
        railsReply.onLoad = function(success:Boolean){
            if (success) {
                    trace ('Rails responded: '+railsReply);
                    callback.text = railsReply;
            } else {
                    trace ('Error while waiting for Rails to reply');
               callback.text = 'error';
            }
        }
        var railsRequest:XML = new XML();
        railsRequest.contentType="application/xml";
        railsRequest.sendAndLoad(this.gateway+model, railsReply);
        delete railsRequest;
    }

    public function create(model, newItem){
        railsRequest.onLoad = function(success){
                trace("Item creation success: " + success);
                trace(this);
        };
        var railsRequest:XML = new XML();
        railsRequest.parseXML(newItem);
        railsRequest.contentType="application/xml";
        railsRequest.sendAndLoad(this.gateway+model+'/create/index.html', railsRequest,'POST');
        delete railsRequest;
    }
}

Save this file in the same directory as your .fla file

In your fla file add:

// Create a XML object to hold the events from our Rails app
rails_events = new XML();

// Prepare the connection to Rails (it would be nicer to do that in 1 step, but to make things clearer i decided to do it in 2)
var rails:Restfulflash = new Restfulflash();
rails.set_gateway("http://localhost:3000/");

// Get the events from rails and load the result in the rails_event XML object.
rails.get('events', rails_events);
trace(rails_events);

// Let's create a new event
newEvent = new XML('<event><description>Spend some time with Grandma before its too late</description><ends-at type="datetime">2007-11-02T18:30:00-07:00</ends-at><id type="integer">1</id><location>Paris, France</location><starts-at type="datetime">2007-11-02T16:00:00-07:00</starts-at><title>Visit Grandma</title></event>&#8217;)
rails.create(&#8216;events&#8217;, newEvent);

// Verify  that the event was added
rails.get(&#8216;events&#8217;, rails_events);
trace(rails_events);

There you go, you have all the events provided to you by Rails nicely prepared in an easy to parse XML object. You can bind the results to a Datagrid or display the info the way you want it. Ohh and by the way, we just added a new Event to the database… easy, isn’t it? The code is a bit dirty but it’s still a good example why you need to use REST and how easy it is to get Flash to talk with Rails. (I strongly encourage that you also look at the very good WebOrb plugin for Rails)