Tuesday, June 30, 2009

Adding Items to the RSS Feed

‹prev | My Chain | next›

I pick up with adding the 10 most recent meals to the site's RSS feed. First, I have to pull back the list of the 10 most recent IDs from CouchDB. Thankfully, I did something similar for the homepage, so I can re-use here:
      it "should request the 10 most recent meals from CouchDB" do
RestClient.
should_receive(:get).
with(/by_date.+limit=10/).
and_return('{"rows": [] }')

get "/main.rss"
end
To implement, I add this to the get '/main.rss' Sinatra application:
  url = "#{@@db}/_design/meals/_view/by_date?limit=10&descending=true"
data = RestClient.get url
@meal_view = JSON.parse(data)['rows']
With that example safely passing, I need to ensure that the full details are pulled back for those 10 meals. Again, I copy from the site's home page example to stub out the RestClient call that pulls back the 10 meal IDs. Then I specify that those 10 IDs need to be used to look up the full meal details for each corresponding meal. This leads to something of a longish example:
      it "should pull back full details for the 10 meals" do
RestClient.
stub!(:get).
and_return('{"rows": [' +
'{"key":"2009-06-10","value":["2009-06-10","Foo"]},' +
'{"key":"2009-06-09","value":["2009-06-09","Foo"]},' +
'{"key":"2009-06-08","value":["2009-06-08","Foo"]},' +
'{"key":"2009-06-07","value":["2009-06-07","Foo"]},' +
'{"key":"2009-06-06","value":["2009-06-06","Foo"]},' +
'{"key":"2009-06-05","value":["2009-06-05","Foo"]},' +
'{"key":"2009-06-04","value":["2009-06-04","Foo"]},' +
'{"key":"2009-06-03","value":["2009-06-03","Foo"]},' +
'{"key":"2009-06-02","value":["2009-06-02","Foo"]},' +
'{"key":"2009-06-01","value":["2009-06-01","Foo"]}' +
']}')

RestClient.
should_receive(:get).
with(/2009-06-/).
exactly(10).times.
and_return('{"title":"foo",' +
'"date":"2009-06-17",' +
'"summary":"foo summary",' +
'"menu":[]}')

get "/main.rss"
end
end
To get that example to pass, still using earlier RSS-specific examples, I use this code:
get '/main.rss' do
content_type "application/rss+xml"

url = "#{@@db}/_design/meals/_view/by_date?limit=10&descending=true"
data = RestClient.get url
@meal_view = JSON.parse(data)['rows']

rss = RSS::Maker.make("2.0") do |maker|
maker.channel.title = "EEE Cooks: Meals"
maker.channel.link = ROOT_URL
maker.channel.description = "Meals from a Family Cookbook"
@meal_view.each do |couch_rec|
data = RestClient.get "#{@@db}/#{couch_rec['key']}"
meal = JSON.parse(data)
maker.items.new_item do |item|
item.title = meal['title']
end
end

end

rss.to_s
end
Rather than driving the complete RSS implementation via RSpec examples, at this point I am going to move back to the Cucumber scenario so that I can use real data with the complete stack.

Recall the Cucumber scenario so far:



I implement the visit the feed URL with a simple Webrat visit:
When /^I access the meal RSS feed$/ do
visit('/main.rss')
response.should be_ok
end
That passes without any changes thanks to the RSpec driven work inside the Sinatra application.

To verify complete implementation of the next step, that the 10 most recent meals should be included in the RSS feed, I first check the old feed on the legacy Rails site:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>EEE Cooks: Meals</title>
<link>http://www.eeecooks.com/meals/rss</link>
<description>Meals from a Family Cookbook</description>
<language>en-us</language>
<item>
<title>Star Wars: The Dinner</title>
<description><p>Inspired by one of the many <a href="http://www.cooksillustrated.com/">magazines</a> that Robin reads, we do a little grilling today. It&#8217;s been a while, so we were pleasantly surprised that the grill even started up, let alone that we were able to cook up such yummy food.</p></description>
<pubDate>Sun, 13 Jul 2008 00:00:00 +0000</pubDate>
<link>http://www.eeecooks.com/meals/2008/07/13</link>
<guid>http://www.eeecooks.com/meals/2008/07/13</guid>
</item>
<item>
<title>You Each Take a Side</title>
...
First, up, there should be 10 <item> children of <channel>, each with a <title> child. I should also verify that the RSS item titles contain the expected values (e.g. "Meal 0", "Meal 1", etc). I can specify this in the example with:
Then /^I should see the 10 most recent meals$/ do
response.
should have_selector("channel > item > title",
:count => 10)
response.
should have_selector("channel > item > title",
:content => "Meal 0")

end
Next, I implement the see-the-summary-in-the-RSS feed step with:
Then /^I should see the summary of each meal$/ do
response.
should have_selector("channel > item > description",
:content => "meal summary")
end
That fails initially because I did not have that attribute added to the RSS::Maker call, so I add it:
  rss = RSS::Maker.make("2.0") do |maker|
maker.channel.title = "EEE Cooks: Meals"
maker.channel.link = ROOT_URL
maker.channel.description = "Meals from a Family Cookbook"
@meal_view.each do |couch_rec|
data = RestClient.get "#{@@db}/#{couch_rec['key']}"
meal = JSON.parse(data)
maker.items.new_item do |item|
item.title = meal['title']
item.description = meal['summary']
end
end
To get the remaining attributes added to the RSS feed, I add two steps:
    And I should see a meal link
And I should see a meal published date
I will get those last two steps working tomorrow.

1 comment:

  1. Hi, thanks for the tutorials, I have a question, if you can help me, I need an rss feed but without the images, how I can delete or disable. I'm working in actionscript3. Thanks for your help.

    ReplyDelete