The Defacto Os X Dev Environment Setup: Updated

After picking up a new Core2 iMac, the first thing I did was set up my Rails environment on it. I hit the normal link from the Rails install page, and went over to Hivelogic.

I've used this quick tutorial millions of times it feels like. I don't even read it anymore, I just copy and paste everything and boom, I'm done.

But about half a year ago I stopped using the bottom half of it. After moving to edge rails for some RESTful goodness, and moving to mongrel for even local dev work, the lighty part of the tutorial was pretty useless for me.

Well visiting the other night I see that Dan Benjamin has updated his famous getting started post.

Here's a quick list of what he helps you get installed, and what it updated.

  • Ruby 1.8.4 -> 1.8.5
  • Rails 1.1 -> Rails 1.2
  • Lighttpd -> Mongrel
  • MySQL 5.0 == MySQL 5.0
  • + Subversion 1.3.2

Popularity: 3% [?]

    Categories: Rails, Ruby     No Comments »

Associated and Non Associated Resources

Problem: Your site has resources that can exist alone as well as be associated to another resource. You want to stay DRY as well as keep your routing RESTful.

I just came across this problem while working on a project, and its solution is a bit easier than you'd think. Thanks to Ruby being so dynamic, Rails provides a really easy way to accomplish this. I'll give my use case as an example.

So I've got a website I'm working on. It's for a church. Part of the data model will include Events and Groups. Groups will have_many Events. Simple enough. Here's the wrench, Events can exist on their own as well. So the "Church" can have Events, which would be an Event existing alone without an association to anything, and every Group in the church will have_many Events.

We also want to use RESTful routes so that we can have routes like: /events, /events/1, /groups/1/events, /groups/4/events/32

Ok, so lets get jammin' on the solution.

Lets knock out the data model first. We want to keep this DRY, so we'll use Single Table Inheritance to keep track of the Events. We'll have Events and GroupEvents. GroupEvents will inherit from the parent Events:

Class GroupEvent < Event

This way Events.find(:all) will return regular Events as well as GroupEvents. We'll add one extra attribute for GroupEvent, group_id, this allows a GroupEvent to belong_to a Group. Lets make our migrations:

Data Tables

class CreateGroups < ActiveRecord::Migration
  def self.up
    create_table :groups do |t|
      t.column :name, :string
      t.column :description, :text
    end
  end
 
  def self.down
    drop_table :groups
  end
end
 
 
class CreateEvents < ActiveRecord::Migration
  def self.up
    create_table :events do |t|
      t.column :type, :string
      t.column :title, :string
      t.column :description, :text
      t.column :date_on_, :datetime
 
      # extra attribute for GroupEvent
      t.column :group_id, :integer
    end
  end
 
  def self.down
    drop_table :events
  end
end

If you're unfamiliar with STI, the type column is there to keep track of what type of object the row is. We also added the group_id attribute for the GroupEvent.

Ok, so our DB is set up. Lets get our association on... Start by creating a new model named GroupEvent:

Data Model

class GroupEvent < Event
  belongs_to :group
end

GroupEvent inherits from Event. Since Event inherits from ActiveRecord::Base, our GroupEvent class is still an ActiveRecord. Its just extended a bit. We also added a belongs_to association to Group. So Group will have_many GroupEvents, not Events. Next up, the Group model...

class Group < ActiveRecord::Base
  has_many :events, :class_name => 'GroupEvent', :foreign_key => 'group_id'
end

Here's where we're pulling a few Rails tricks. We're using telling Group that it has many events, but GroupEvents, using group_id as a foreign key (remember when we added that?!). So now we're able to use:

@group = Group.find(1)
@events = @group.events

Whoa, nice! We didn't have to have a separate table just for GroupEvents, which means we dont have to manage 2 different models and their attributes if they get updated. We also don't have to use syntax like @group.group_events which is a bit ugly if you ask me. Groups have events, lets obfuscate HOW it has them to the back, so in the implementation we're just worried about events, not namespaced events, blegh.

OK! NICE! So far so good. What about the routes? I want http://mychurch.com/events and http://mychurch.com/groups/2/events, not http://mychurch.com/groups/3/group_events.

Lets dig into the routing...

map.resources :events
 
map.resources :groups do |group|
  group.resources :events, :controller => 'group_events', :name_prefix => 'group_'
end

First things first, we add a resource for Event. Next, since we want nice pretty nested routing, we nest GroupEvent into Group. Here's some more configuration (EEP! yes yes, our requirements are outside of a convention, BUT NOT BY MUCH!). We want to define the route to use 'events' in the actual URI, but we don't want to stomp all over our previously declared resource, events. Our generated named routes will clash, we can't have 2 events_path methods. So we add a :name_prefix option. This basically appends 'group_' to every little route helper we have. So event_path in the Group context becomes, group_event_path. The tricky one is new_event_path turns to group_new_event_path, so its not AS pretty, but good enough :)

Next we know our @group.events are going to be very different from our @events, so we need a GroupEventController. In order to properly map this, we use the :controller option. Without it, the routing will use EventController (those darn conventions...), and that would just process our logic for normal Events, not our scoped Group events.

So there ya have it. Around 10 lines of code and we have our domain model nice and dry, and our routes very logical!

Did I screw something up or got a better way to do this? Tell us all in the comments.

Popularity: 3% [?]

    Categories: Rails, Ruby     2 Comments »

Its like a Ruby on Rails Christmas

Whoa. So you sit down and watch The Office and 30Rock for one second, and you miss out on things you've been waiting for for months.

What is this I speak of, well Rails 1.2 final of course! Now everyone afriad of running Edge can have beautiful built in RESTful routes. I've been running Edge since around September, and getting RESTful has been the best thing I've done since moving to Rails for most projects. It comes highly recomended from this lowly developer.

The other thing we got today was Prototype 1.5 final, which has been a long time coming. Along with that comes, drumroll... DOCUMENTATION! Yes, we all love prototype, but we all had the same problem, how the heck can I get what I want out of it without reading the source! So after a ton of work from Sam Stephenson and Justin Palmer we now have a great place to peruse the library that saves us all a ton of time.

Using Rails, I dont find myself writing much javascript TOO much these days thanks to helpers and RJS, but it still totally handy, AND MUCH NEEDED!

Thanks goes out to Sam, Justin, DHH, Rails Core and all the rest of the patch submitters. What a great start to the year. I think its gonna be a big one.

Popularity: 2% [?]

    Categories: Rails     No Comments »

I Bring You Aim Status Helper 2

Well, I've got this whole week off and I've gotten pretty bored pretty quick. So why not update some little projects?

That's what I've done with my little Aim Status Helper. The last one was pretty ghetto. You handed it an aimname, and it basically force fed what I wanted it to. Yeah, you could override the display text, but what if you didn't want any! Or what if you just wanted to know the status, without displaying anything?

I think I've done a good job in taking care of that now. So, I bring you Aim Status Helper 2! Thats right, 2!

I went ahead and created a whole new namespace for this updated version because it uses a completely different method to find out the status of an aim member. Before I was using a fancy URL that you pass the image paths in, and AOL responds with the status image url. Thats great, as long as you're just wondering if the user is ONLINE or OFFLINE. If the user is Away or Idle, they still show as online. Not really helpful.

Now I'm talking directly to the Aim Web API. And let me tell you, boy is it crap. I made a little lemonade out of it though, and I think I came up with something that is dynamic enough that it should cover most bases.

It's really just 4 methods. A request method to get the returning xml. A method to parse that and return the status in plain text, a method to display the icon, and a nice little aim_to method that will provide a link to pop open a message window to the user you pass in.

Ok, so heres some code:

aim_status 'maddox123456' => "online"

oooh, nice. This just returns the status. So you can do anything you want with it. If you have some other fancy way to display AIM status, and are just looking for a way to GET the status, just use this.

aim_status_icon 'maddox123456'

aim status Jon Maddox

This will throw an icon into your page. The normal options for image_tag are available.

aim_to 'Jon Maddox', 'maddox123456'

Jon Maddox

This will wrap one of those fancy "aim://goim?screename=maddox123456" links around whatever you pass to it. The normal options for link_to are available.

aim_to( aim_status_icon('maddox123456'), 'maddox123456')

aim status Jon Maddox

Wrap the last two up, and you get basically what I was doing with the first version of this silly plugin.

So basically, what you get with this new version is a better way to GET the status, and wayyyyy more freedom to do anything you want with it. I know that the first version I made barely worked for 2 instances of use. So I can imagine it probably didn't work for any of you guys. This one should solve that.

Requirements: Rails 1.2 rc1 or Edge

More info here: http://github.com/maddox/aim_status_helper/tree/master

Install:

git clone git://github.com/maddox/aim_status_helper.git vendor/plugins/aim_status_helper

Popularity: 6% [?]

    Categories: Rails     4 Comments »

Test Your respond_to Block

Getting RESTful and wondering how to test your respond_to block in your controller to make sure its returning the right format? Drop these into your test_helper.rb.

def assert_xml
  assert_match 'application/xml', @response.headers['Content-Type']
end
 
def assert_rss
  assert_match 'application/rss+xml', @response.headers['Content-Type']
end

Then in your functional tests, use them like this:

def test_return_xml
  get :index, :format => 'xml'
  assert_xml
end
 
def test_return_rss
  get :index, :format => 'rss'
  assert_rss
end

Yay!

Popularity: 4% [?]

    Categories: Rails, Ruby, Snippets     2 Comments »