Using YUI DataTable with Rails


Javascript/AJAXRailsTips and Tricks

I am currently working on an Rails app that integrates the YUI dataTable, and in going through the tutorials I noticed they are all assume a PHP back-end. I also saw a number of people asking how to get this to work with a Rails controller, so I thought I’d write up my experience in the hopes that it helps someone else. For basic info about setting up the dataTable, refer to the YUI site, linked above. I’m also going to try to clarify a few things that I found a bit obscure.

To create a dataTable you have to define a few basic ingredients:

  1. A dataSource. This defines where the info in the table comes from, and what format it is returned in. I’m using JSON.
  2. A schema that you define. This is a part of the dataSource and is essentially a map to your data. The schema tells the table where to find the field values.
  3. An array of column definitions. You supply the name and “key” of each column and any additional information, such as whether it is editable (and if so, which editor to use) and how to format the data inside the column if you don’t want to just spit it out directly.

Let’s start with a dataSource. In this example, we’re making a table of tasks, so I want to hit my tasks controller to return the data. Standard Rails controller action. In the code snippet below,

  1. in line 1, I supply a URL (note that the url ends in .json, and in my controller I have a responds_to block which constructs my json response).
  2. In line 2, I’m telling the dataSource — hey, you’re gonna get some JSON.
  3. And line 3, is where we define the responseSchema, which has two critical parts: the resultsList and the fields.
  var dataSource = new YAHOO.util.XHRDataSource("/projects/13/elements/21/tasks.json");
  dataSource.responseType = YAHOO.util.XHRDataSource.TYPE_JSON;
  dataSource.responseSchema = {
   resultsList: "Resources.data",
   fields: [
      {key:"task.id"},
      {key:"task.status"},
      {key:"task.percent_complete"},
      {key:"task.description"},
      {key:"task.due_date", parser:date}
      ]
  }

Let me be clear since I got hung up on this a bit. You as the application developer are responsible for two things. One, constructing your response — in other words, you can build your JSON response any way you want, with any keys, values and hierarchical structure that make sense (though it will help you to think it through and standardize it, Satyam has some good info on that here). And two, telling your dataSource how to navigate your response: i.e. — where do find what the data you’re looking for (the needle) in the response (the haystack of JSON)? This is the schema, the map of your data.
Controller code that creates my custom JSON:

# tasks_controller.rb
def index
 respond_to do |format|
      format.json{
         tasks = []
         @tasks.each do |task|
           task_container = {}
           task_container  = task
           task_container['editable_by_user'] = permission.edit? # some metadata I use
           task_container['deletable_by_user'] = permission.delete?
           task_container['resource_name'] = "task"
           tasks << task_container
        end
        data = {"Resources" => {"data" => tasks}}
        render :json => data.to_json
      }
  end
end

And just for fun, here’s a look at the JSON my controller gives me back when I hit this url ‘/projects/13/elements/21/tasks.json’.
The JSON:

{"Resources": {"data": [{"task": {"status": "not_started", "started_on": null, "updated_at": "2009-02-07T22
:03:18Z", "project_id": 13, "percent_complete": null, "high_priority": null, "element_id": 32, "deletable_by_user"
: true, "completed_on": null, "editable_by_user": true, "element_title": "looking good", "id": 50, "created_by_id"
: 7, "resource_name": "task", "description": "Pass the stimulus bill", "assignments": [], "due_date"
: "", "users": [], "resource_url": "/projects/13/elements/32/tasks/50", "due": null, "created_at": "2009-02-07T22
:03:18Z"}}, {"task": {"status": "not_started", "started_on": null, "updated_at": "2009-02-07T22:03:39Z"
, "project_id": 13, "percent_complete": null, "high_priority": null, "element_id": 32, "deletable_by_user"
: true, "completed_on": null, "editable_by_user": true, "element_title": "looking good", "id": 51, "created_by_id"
: 7, "resource_name": "task", "description": "Negotiate without pre-conditions", "assignments": [], "due_date"
: "", "users": [], "resource_url": "/projects/13/elements/32/tasks/51", "due": null, "created_at": "2009-02-07T22
:03:39Z"}}]}}

So that’s it! I’ve defined this JSON array and built it, then returned it from the controller when I get a .json request.

Now that you’ve seen the response, take another look at the responseSchema (you created above) and the two properties that you set:

  1. ResultsList. Notice it is set to “Resources.data”, which are the JSON keys I used. It uses dot-syntax to point to array of tasks in my json.
  2. Fields. Again using dot syntax, and having the ResultsList array to navigate through, it can pull the specific values it wants from the list; so ‘task.status’, ‘task.started_on’, etc., will retrieve those values from the response.

Make sense?

You are now one step away from being able to see your table. So, create your column definitions, an array of data about each column in the table. This is also where you can specify formatting and editing information (not covered in this article).

var columnDefinitions = [
  {key:"task.status",formatter:"formatPriority", sortable:true},
  {key:"task.percent_complete", label:"Percent Complete", sortable:true},
  {key:"task.description", label:"Description"},
  {key:"task.due_date", label:"Due Date", editable:true,sortable: "true",formatter:YAHOO.widget.DataTable.formatDate, editor: new YAHOO.widget.DateCellEditor({resource:'task', updateParams:"task[due]"})}
  ];

Notice that each column definition has a key: this key must be accessible in your JSON, AND it must be defined as a field.

And then you create your table. The first argument is the id of a div on the page to which the table will be attached, the last is an optional configuration hash (pagination, anyone?).

var dataTable = new YAHOO.widget.DataTable("project_tasks", columnDefinitions, dataSource, optionalConfigurationHash);

I hope this is helpful to get you started with the YUI dataTable on Rails. I may do further posts on XHR editing of individual cells in a dataTable using Rails.

Hpricot and woot!


RubyTips and Tricks

I know there are several sites for tracking wootoffs on Woot, but I wanted to write my own small program in Ruby. To do this, I used Hpricot by why the lucky stiff.

First, I need my require statements. I’ll need rubygems, since hpricot is a gem, and open-uri to access woot.

require 'rubygems'
require 'hpricot'
require 'open-uri'

Woot has an API that returns XML, so I used Hpricot::XML to parse what comes back.

doc = Hpricot::XML(open("http://www.woot.com/salerss.aspx"))

Now I want to know if it’s a wootoff. If it is, I’ll want to check more frequently. I use the at method to find the element I want, and inner_html to get the text inside that element. The element I’m interested in is woot:wootoff. I’m going to start putting the output into the text variable.

wootoff = doc.at("woot:wootoff").inner_html =~ /true/i
text = wootoff ? "wootoff! ^_^" : "no wootoff v_v"
text << "\n"

Next I want to know what the item is and the price and shipping.

text << doc.at("item > title").inner_html << "\n"
text << doc.at("woot:price").inner_html << " + "
text << doc.at("woot:shipping").inner_html << "\n"

I'll also want to know how much of the item is left, so I know if I need to rush to buy something I want.

percent_gone = doc.at("woot:soldoutpercentage").inner_html
percent_gone = percent_gone.to_f * 100
percent_left = (100 - percent_gone).round
text << "#{percent_left}% Left"

I took all that code and put it into a method, to be looped over every two minutes. I wanted it to print to the screen only if the text changed. This is what the completed program looks like.

#!/usr/bin/ruby
require 'rubygems'
require 'hpricot'
require 'open-uri'

def woot_item
  doc = Hpricot::XML(open("http://www.woot.com/salerss.aspx"))
  wootoff = doc.at("woot:wootoff").inner_html =~ /true/i
  text = wootoff ? "wootoff! ^_^" : "no wootoff v_v"
  text << "\n"
  text << doc.at("item > title").inner_html << "\n"
  text << doc.at("woot:price").inner_html << " + "
  text << doc.at("woot:shipping").inner_html << "\n"
  percent_gone = doc.at("woot:soldoutpercentage").inner_html
  percent_gone = percent_gone.to_f * 100
  percent_left = (100 - percent_gone).round
  text << "#{percent_left}% Left"
end

woot_text = ''
while true
  new_woot_text = woot_item
  if woot_text != new_woot_text
    woot_text = new_woot_text
    puts "*****************************************************"
    puts woot_text
  end
  sleep 120
end

Here is some output from the program.

*****************************************************
no wootoff v_v
Lockjaw Self-Adjusting Locking Pliers - 2 Pack
$9.99 + $5 shipping
100% Left

Of course, this is only a beginning to what you can do. You can have it send a twitter, SMS, email, or any number of things if an item you want is available or a wootoff starts.

Angel

About Angel N. Sciortino

Ruby programmer. Sysadmin. Queer and polyamorous. Welder. Crocheter and darner. Chaotic good.

More Posts by Angel N. Sciortino - Author Website

Rails Summit Latin America


EventsIntroductionsPresentationPythonRailsReviewsRubyThoughtsTips and Tricks

I am currently in Sao Paulo, Brazil at Rails Summit Latin America and the experience has been great thus far.

Ladies at the conference there is information at the end of this writeup about how to join. If you don’t feel like reading everything in this writeup that is fine but please do read about joining.

In contrast to many conferences I have been to recently I have been to just about every talk at this conference and I have thoroughly enjoyed them all. I say just about because there is a second track that is going on in another room but I haven’t been to those sessions.

The Organizers:
Fabio Akita and Gilberto Mautner Founder of locaweb have done a great job with the conference and I would like to give them a special thanks. The lineup, venue and everything has been great. Obrigado!

Theme:
I think most conferences, through the keynotes, some how seem to create a theme. The theme that I am picking up on at this conference is this: “Have No Fear” and “Just Do It”. No one actually said either of those two things but thats basically what I am taking away from most of the keynotes. They have all been especially encouraging for people to become involved. Contribute, create, and code. Give back to the community and get involved. Don’t be afraid .. put yourself out there and learn from the feedback you get.. learn from the experiences of creating.. do side projects.. basically be PASSIONATE.

The Talks:
All the talks I have seen have been excellent. I give them an excellent rating because they have all had the qualities I look for in a talk.
1. The content is good and interesting.
2. The delivery of that content is entertaining or at least engaging.

Chad Fowler – I really enjoyed Chad’s talk and as I sit here I am struggling to figure out a way to describe his talk and actually do it justice. He spoke about his background in music and how that has translated to his life as a developer. In addition, he spoke about being remarkable. He talked about many ways in which people are remarkable and many ways in which we ourselves can become remarkable people. He touched on many things and did so in such a way that I was able to stay engaged with him. There were pictures and video’s and graphs and fake numbers and.. anyway about the best I can say is that I personally really enjoyed his talk.

Dr. Nic Williams – Dr. Nic’s presentation is a little easier to sum up but at the same time I can’t really do it justice. Dr. Nic is one of those speakers that if you ever have a chance to see him speak you should definitely take the opportunity. He is hilarious and has a good message. His talk was all about how to contribute back.. how to get involved.. how to participate. Make the future you proud of the you now. Dr. Nic also talked about newgem

Chris Wanstrath – Chris’s keynote started off being about the future of Ruby and RoR but in the end he took it back to the past and where we have come from. He went through a great deal of history on how we got here which I personally enjoyed especially when he pointed out the first ENAIC programmers were all women, unfortunately he was speaking quite fast so I think a lot of his talk was lost in translation. I think the primary thing Chris was trying to get across is to not be afraid. If you have an idea.. make time to get to it you never know where thats going to go. In the very least you gain experience and you gain knowledge. Chris has had many projects in the past but his current claim to fame is all about github.

Jay Fields – Jay’s talk was about the immaturity of testing as a whole. While I agree with some of the things he said I also disagree with some of the things he said. I have had the luxury of getting to pair with Jay on projects before and its always interesting for me to see him speak because I have first hand experience with a lot of things he talks about. He described the problem of immaturity in testing as a whole first with the fact that we can’t even agree on common terminology. He then proceeded to talk about various tools and the pros and cons of each. He covered Selenium, Test:Unit, Rspec, Syntasis, and Expectations. The last two being the most immature of them all and bleeding edge. i.e. use at your own risk. He also answered a few questions about how to make your test suite fun faster and his response was basically that if you are willing to deal with the pain that goes along with it there are tools you can look into using such as null_db, unit_record, and ARBS. You can read about them on the null_db page on Agile Web Development site. That page links out to the other plugins. Jay also pointed out that all the things he was talking about are from his point of view. In other words its the context in which he works that causes him to have some of the testing beliefs he has.

David Chemlisky – David’s first talk was about doing TDD and in my opinion he did an excellent job of demonstrating TDD. I have seen him give a talk similar in the past and of all the people I have heard try to describe TDD, David is one of the most skilled at it. He gave the talk from the point of view of a teacher which in my opinion is really the only way you can truly explain TDD. He went through the process step by step with us all to show us the way. :)

His second talk was more about Acceptance testing and story runner and the newest version of story runner which is being called cucumber. He demonstrated how it worked and made sure to give context around all the terminology such as user stories etc. Hopefully there will be some way of seeing this talk again maybe through a screen cast or something of that nature. I’ll be sure to ask him if he would be willing to do that. Or maybe there is one with cucumber? Not sure haven’t had a chance to look yet.
Couple of links to stuff he talked about.
Cucumber
webrat on github and a blog post on it here

On that last note I am actually interested to know if these talks are being recorded and if they will be available somewhere? Anyone know the answer to that?

Obie Fernandez – I haven’t actually seen Obie give his talk yet but I have seen the talk (insider information) so I am going to go ahead and give a recap.. I asked him to plug DevChix and wanted to have this write up already done before he did so.. ;-) So Obie’s talk will be about the “Hashrocket Way”. He is basically giving up our secrets.. Like Dr. Nic said no secrets! His main focus will be around how we work, the fact that we follow Agile Tenants and that we value fun, collaboration, and effectiveness. We achieve those things through certain practices such as pair programming, TDD, Story Carding, launch parties etc. Again you should check out his blog.

Ninh Bui and Hongli Lai a.k.a The Phusion Guys – I woke up late so I didn’t catch all of the talk from the Phusion guys but the part that I did catch was hilariously funny and explained things like caching and database sharding. Additionally, they gave a demo of yuumis_comments.. and here is also a link to their blog

I call out all of these guys because they are some of the best speakers I have ever seen and I actually saw them speak at this particular event.

Phillippe Hanrigou – Phillippe is going to be giving a talk on how to effectively do acceptance testing which I am looking forward to but I won’t be able to cover that here because I haven’t seen it and since I don’t have insider info on that one I’ll just have to wait like everyone else. I do know that he will be talking about one tool I hadn’t heard of before called Deep Test. You should check Phillippe’s blog as well

Luis Lavena – Luis will also be giving a talk about surviving with RoR and Ruby as a windows user.. again I think the talk is going to be awesome but its in the future so I can’t really talk about that yet. You should check out his blog!

The Venue:
The venue is quite nice. The main auditorium is very well arranged and has plenty of room despite the fact that there are a lot of people here. There is a very large screen making it easy for everyone to see the slides as well as the speakers. The lighting on the actual speakers is a little weird but other than that the actual conference room is great. The audio is fantastic and the actual hang out area is quite nice as well (other than the lack of air conditioning but thats just me being a little whiny its not really that hot). One other really important point that I want to bring up is the translators. You can get a headset at the checkin area that will translate the talks from English to Spanish and Portuguese and from what I understand the translators have been doing a kick ass job so a special thanks to all those ladies in the booths translating for us.

The Community:
I was very encouraged by the number of people at the conference, the number of people using github (vast majority) and the number of people doing Ruby and RoR development on a day to day basis. It is always an exciting moment for me when I realize it is gaining in support because how much I love the language. In addition, everyone has been extremely helpful and friendly. We meet Tim Case the first day and he was more than willing to take us under his wing and show us around.

One thing that was both encouraging and discouraging is the number of women at the conference. There were women, thats the good news, the bad news is that I think from a ratio point of view the number of women at the conference is on par with what I have experienced at Ruby and RoR conferences in the US. That is to say its pretty small. Usually at conferences since there are so few women I can manage to talk to most of them and but here I have been some what intimidated by the language barrier. One other thing to point out is that there were no women speakers but hey that isn’t really that uncommon. I am hoping that when Obie does his talk and plugs DevChix for us that many of those women who were at the conference that I didn’t get to meet will come to the site and join.

Ladies Please Read
For those women who do happen to come to the site from Brazil and other countries. I would like to say that we have members world wide who can speak a number of different languages so please don’t let that discourage you from joining and participating. We would LOVE to have you all as part of the group. Also encourage other female developers you know.

If you are a women, a developer, interested in joining and/or contributing to DevChix, please contact Desi McAdam at info(-at-)devchix.com with your:

1. Name
2. Email
3. Do you know any one from DevChix?
4. A short 2 sentence bio describing your development background/experience (or what you hope to learn) and a link to your blog if you happen to have one.

Obrigado! :)

A quick (and dirty?) way to mail Oracle alerts.


Tips and Tricks

Where I work, we have about 45 external Oracle Database Servers running RHEL 3. It’s a little tough keeping up with all of them day to day, so I made a quick BASH script that will check for any ORA- alerts in your Oracle alert_*.ora file. Here goes:
********************************
#!/bin/sh

tail -500 /usr/oracle/admin/ora_sid/bdump/alert_sid.log | grep ORA- > mailoraalerts.log
wc -l mailoraalerts.log > greporacount.txt
COUNT=`awk ‘{print $1}’ greporacount.txt`
if [ $COUNT -gt 0 ]; then
mail -s “Check ” your.address@mail.net < mailoraalerts.log
fi
********************************

So what this does is greps the last 500 lines of your alert log looking for ORA- string, and pipes that out to a log file. It then does a word count on that log file. If the word count is greater than 0 (there exists ORA- errors) then email me what the error is.

Then just schedule a cron job to run at whatever interval you desire. This probably isn’t the prettiest way to do this, I’d love to see other suggestions if anyone has any! My next step is to find out how to get Oracle to email me directly when there’s an error, instead of having cron determine when I am alerted.

Enjoy!

Multiple object forms, delegation, and has_one…


RailsRubyThoughtsTips and Tricks

I had an ah ha moment that maybe shouldn’t have been such an ah ha moment but it was so I figured I would share it. Yeah so I am sure most of us have had a situation where we needed to have multiple model forms. Most of the time now days I use attribute_fu to solve this issue but attribute_fu doesn’t work with has_one associations. Today I had a situation where I had two fields that were required for a has_one association object. Long story short it came to me that if we just used the delegate method provided by rails that we could essentially act like the attributes we were setting were on the parent model. This meant we only needed to create one form with multiple fields even though some of those fields were actually on a different model. I then remembered that back when I was working with the guys over at ThoughtWorks that we used a Ruby Extension called Forwardable to be able to delegate multiple attributes on one object.

So instead of this:

delegate :first_name, :to => :profile
delegate :last_name, :to => :profile
delegate :some_other_attribute, :to => :profile

side note: I’m not sure but I don’t believe delegate can take multiple attributes (I tried to look this up but for some reason couldn’t find the documentation for this method and didn’t have time to dig in the code)

You could do the following:

include the Ruby Extension Forwardable in the parent model class


include Forwardable

and then add this line:

def_delegators :profile, :first_name, :last_name, :some_other_attribute

So yeah that was my little ah ha moment. I am sure there are even better ways than this but this was better than what we were looking at doing to begin with.