It’s just data

Prototyping Intertwingly on Rails

It is said that Rails is opinionated software.  I’ve been exploring to see how it stacks up on a subject area where I have opinions: weblogging software.  So far, it has measured up pretty well. 

database.yml is used to configure the databases used.  Now lets look at the software.  I feel compelled to note that this is a work in progress, and very much incomplete.  This being said, even these initial results produces something recognizable as a weblog.

uris

URIs are definitely something I have an opinion on.  I don’t cotton to the idea of putting the action in the URI as I feel that URIs are intended to uniformly identify, well, resources.  I also have amassed a legacy of different URI conventions, all of which I wish to continue to support.

In Rails, when requests come in, the first thing that happens in that the request gets routed based on the URI.  URIs are composed of segments separated by slashes.  routes.rb enables you to name the segments, match segments against requirements you specify, and to do a first order partitioning of requests into actions.  Segments at the end of URIs can be defaulted, something that is defeated by my need to access the path component at the end.  This does, however, work for my archive URIs.

While I need to do additional parsing in the controller to distinguish index.html from index.atom for example, this initial partitioning is useful.

Controller

The next piece involved is blog_controller.rb, which serves as the nerve center of the weblogging application.  Its first responsibility is to field all the routed actions.  Each of these methods tend to be small.

Following this, I have a number of methods are specific to my weblog, which I have chosen to mark as private, even though this is not strictly necessary.  parse_date is a method to convert a date — or portions thereof — into an SQL query.  paginate_with_path will further parse the URI as mentioned above, and this method also serves as the branching off point for handling post requests. paginate optionally filters the query with a full text search and limits the results to a page (of typically 10) entries.  post handles previews and posts.

Finally, there are two small pieces of bookkeeping.  determine_layout determines the overall layout of the results.  This is useful for sites that generate mostly HTML with a common theme.  My site is borderline as has three classes of pages with a common theme, one with a different theme, and the rest of the responses (feeds, trackback, pingback, etc) are not HTML so don’t need any layout at all.  Ultimately, I may simply go with a set of partial templates (described below) and common CSS.  default_template_name completes the controller by utilizing the parsed flavour to determine the template name (as opposed to the rails tradition of using the action name).

Model

The controller makes use of entry.rb and author.rb for persistence.  Entry we have seen before, though I have now added an indication that an entry belongs_to an author, and unabashedly added code that David Heinemeier Hansson refers to as “muddling the model” by associating an entry with its resource identification.  Rails' approach of dealing with URIs as  a collection of named segments is helpful here.

View

Views start out with a blog.rhtml (and archive.rhtml) layouts which determine the overall look and feel of the HTML results.  Like JSP, ASP, and PHP, these pages are mostly HTML with a little bit of presentational logic mixed in.  While not strictly necessary, I’ve placed my sidebar into a separate partial as I tend to edit it with a different frequency than my layout.

html.rhtml contains the HTML flavor of my index page, search results , and the like.  Again, this is very much like JSP, ASP, and PHP; where blog_helper.rb effectively implements the equivalent of tag libraries.

atom.rxml provides support for Atom feeds for each of these pages, and utilizes a very different approach to building xml.  As my HTML pages are actually XHTML, I could productively use this approach for those pages too.

post.rhtml and preview.rhtml are two other rhtml files to support a individual post (with comments) and preview pages.  Both of these make use of a the partial commentform.

Finally, archive.rhtml produces my “month at a glance” page.

There also is the the various accompaniments of error pages, icons, images, javascripts, and stylesheets.

tests

entries.yml and authors.yml provide test data for entry_test.rb and author_test.rb.

Much more significant is the blog_controller_test.rb which issues mock HTTP requests against the various actions and verified the results - even to the point of parsing the resulting HTML for specific content or a given number of tags that match a specified criteria.  While this test suite only covers the basics at the moment, it has already proven quite helpful in flushing out a number of bugs.

Load

load.rb is the confidence builder with require 'config/environment' replacing the calls to ActiveRecord::establish_connection and the definition of the model.  Additionally, support for parsing authors and slugs (used in muddling the model) have been added.

If you would like to try this out yourself, make sure that you have rails and libxml-parser-ruby1.8 installed, download rails.tgz and atom.tgz, and run the following commands:

rails weblog
cd weblog
ruby script/generate model entry
ruby script/generate model author
ruby script/generate controller blog
tar xzf rails.tgz
tar xzf atom.tgz
ruby db/load.rb atom/*.atom
rake
ruby script/server

You should now be able to access a local copy of reasonable facsimile of my weblog at http://localhost:3000/blog/.

Conclusion

I still have much to explore: localization, logging, redcloth or equivalent, caching, spell checking, trackbacks, automated excerpts, Atom publishing protocol, comment throttles, etc., etc., etc.; however at this time I see nothing that will likely get in my way — to the contrary, I see quite a bit of things that I can build upon in Ruby on Rails.

And all with very few lines of code.  rake stats helpfully produces the following statistics:

+----------------------+-------+-------+---------+---------+-----+-------+
| Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |
+----------------------+-------+-------+---------+---------+-----+-------+
| Helpers              |    75 |    58 |       0 |       5 |   0 |     9 |
| Controllers          |   179 |   133 |       2 |      11 |   5 |    10 |
| APIs                 |     0 |     0 |       0 |       0 |   0 |     0 |
| Components           |     0 |     0 |       0 |       0 |   0 |     0 |
|   Functionals        |   196 |   141 |       2 |      21 |  10 |     4 |
| Models               |    75 |    56 |       2 |       3 |   1 |    16 |
|   Units              |    49 |    38 |       2 |       6 |   3 |     4 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total                |   574 |   426 |       8 |      46 |   5 |     7 |
+----------------------+-------+-------+---------+---------+-----+-------+
  Code LOC: 247     Test LOC: 179     Code to Test Ratio: 1:0.7

It seems that I have to move your feed from the DEVELOPERS into the RUBY category. I’d also like to mention that RUBY has precedence over all other categories in my feed reader, so it’s all for the better :)

Posted by Paul Goscicki at

Sam Ruby: Prototyping Intertwingly on Rails

[link]...

Excerpt from del.icio.us/tag/ruby at

Ruby on Ruby. Ack!

Posted by Justin Watt at

In blog_controller_test.rb,  test_comments is defined twice.

But generally, I wish my code was that obviously well-structured.

Posted by Jeremy Dunck at

Jeremy: good catch!

The first definition seems to be bogus and should be removed.  As to the structure, I can draw upon the experience from my existing implementation and I am trying to follow how Rails seems to be encouraging me to to structure things, so both of these are to the positive.

The potential negative is that what you are seeing is before entropy has had a chance to set in.  The existence of a test suite should mitigate this somewhat as it enables refactoring with impunity.

Posted by Sam Ruby at

Ruby on Ruby on Rails

It is good to see Sam Ruby “Prototyping Intertwingly on Rails”. He loves porting his blog software to every framework under the sun, and this time he talks about his experience porting to Rails. I still have much to explore: localization, logging,...

Excerpt from techno.blog("Dion") at

Nice.

Q: why does author model contain:  ‘has_many :post’ instead of ‘has_many :items’ ?

Posted by Thomas at

Thomas: both are wrong.  ;-)

Had I ever tried to reference author.post, I would have received a runtime exception.

The correct answer is has_many :entries, (thus: author.rb).  This results in a query of all entries which contain an author_id which matches this author.  I’ve added author_id on the two comments in entries.yml, and added the following test to author_test.rb:

# Entries relationship
def test_entries
  assert_equal @john_smith.entries[0], @blue_comment
end

Thanks!

Posted by Sam Ruby at

View Source

Una de las formas más divertidas de aprender Rails, es mirar código que ha hecho otra gente. El famoso “by example”. Pues bien, Sam Ruby ha reimplementado su software de blog con Rails y lo comenta en este artículo: Prototyping Intertwingly on...

Excerpt from Railes y Traviesas at

Add your comment