Posts Tagged gem

Representable gem released: Improve your REST representation code!

Monday, May 9th, 2011

The representable gem helps to keep parsing and rendering representations in one place. Once defined, it gives your model #to_xml, #from_xml and more. The initial version was released today, let’s see how it helps cleaning up your representation code.

Let’s write a Blog app!

Since your imaginery blog app has a REST API you want to provide a post resource serving and consuming article representations. Here’s a sample XML representation of an arbitrary blog post.

<post>
  <id>1</id>
  <posted_at>2011-05-09</posted_at>
 
  <comment id="1">
    <text>This is stupid!</text>
  </comment>
  <comment id="3">
    <text>No, awesome post!</text>
  </comment>
</post>

Basically, a post representation contains comments in addition to some meta data.

The Problem: Two places need to know about your Representation.

In, say, a Rails app, you’d have to tweak the models’ #to_xml method in order to render an XML representation. Alternatively, you’d use a Builder template.

If, and only if, you stick to the Rails conventions, #from_xml will work out-of-the-box. Otherwise, you have to write a manual parser as discussed earlier. Note that the <comment> tag contains an attribute not compliant with Rails.

You usually end up with some model code, maybe even a template and a hand-made parser. This distributes representation knowledge over the entire MVC framework. While this won’t kill your mother it still makes things more work to manage.

Defining a Representation

The representable gem is designed to prevent you from doing that. You simply define the representation in one place and it does the REST (I still love the word-play).

1
2
3
4
5
6
7
8
require 'representable/xml'
 
class Comment # < ...
  include Representable::XML
 
  representable_property :text
  representable_property :id, :from => "@id"
end

The Representable::XML module allows to define plain properties (line 6) and attributes (line 7).

Nesting Representations

The post representation uses the compositing feature in representable in order to embed comments.

1
2
3
4
5
6
7
8
class Post # < ...
  include Representable::XML
 
  representable_property :id
  representable_property :posted_at
  representable_collection :comments, 
    :tag => :comment, :as => Comment
end

Wow, you can define nested compositions with representable (line 6). This is easy, so how do we work with it?

Rendering Documents

You want to render a document representing your post now.

Post.find(1).to_xml 
  # => "<post><id>1</id>comment id=\"1\"..."

Representable takes care of rendering. No magic included.

Parsing Representations

What if you allow people to POST an XML document to the blog post resource?

@post = Post.from_xml(request.body)
@post.comments
# => "[#<Comment:0x8545a08 @text=\"Your blog sucks.\">]"

Again, representable deserializes the incoming representation and creates the respective objects for you. Representable doesn’t know anything about databases or your underlying data layout, though. It just creates fresh instances for compositions making it your job to process it.

Other media types?

Representable comes with XML and JSON support, you just have to mix in the respective module.

@comment.to_json
  # => "\"{text => ..."

How does it help?

Representable is a completely abstract module for rendering and parsing representations and mapping document fragments to object attributes. Nothing more.

It makes working with representations object-oriented where you had view templates and parsers before. While representable makes that workflow as simple as possible it also allows distributing your representation code, since it can be pushed into Ruby modules. Maybe it makes sense to use it on both client and server, in Rails and Sinatra?

Representable is also used in Roar to make life easier when working with REST representations and embedding or consuming hypermedia. We will discuss how representations and HATEOAS work in the next post. Cheers.

Testing your Rails 3 Engine sitting in a Gem

Monday, October 11th, 2010

or Making your Rails gem suck less

When people refer to gems they usually think of new methods and classes popping up in your Ruby application as soon as you require the gem.

However, with Rails 3, gems (and plugins) can also add behaviour, controllers, views, routes and all the other well-known pieces of Rails to your host application. These kind of gems are called engines.

Luckily, in Rails 3 we got baked-in engines support. When adding the gem to your host application, Rails will detect the engine and automatically extend things for you.

What can Engines do for me?

I, being a components-facist who refuses to write monolithic apps, am very happy about engines: They help you encapsulating parts of your application and encourage reusability in and between other projects.

Man, WordPress keeps telling me to update.

Having read great posts about writing engines, I will focus on testing engines in this post.

Testing engines right

So, if you use my Apotomo gem (and you should do that if you want real web components in your Rails app) it will add

  • new classes and stuff
  • new methods to controllers
  • add a new route

Now how do I test all that in the gem?

The Rakefile

First, I setup a Rakefile containing a Rake::TestTask. It sits in the gem’s top directory.

Rake::TestTask.new(:test) do |t|
  t.libs << 'test'
  t.test_files = FileList['test/**/*_test.rb']
  t.verbose = true
end

I can now run rake test in my gem directory which will launch my gem test suite.

The test helper

Every test suite needs a file to require all needed stuff. Usually you put that into test/test_helper.rb and require it in every test.

require 'rubygems'
require 'bundler'
Bundler.setup
 
require 'shoulda'
require 'apotomo'

I use bundler when running my tests, which makes loading local gems for development simple.

Unit tests

Testing classes and methods in gems is simple – the same setup as in your app. A unit test could look like this.

require 'test_helper'
 
class ApotomoTest < Test::Unit::TestCase
  context "The main module" do    
    should "respond to js_framework" do
      Apotomo.js_framework = :jquery
      assert_equal :jquery,  Apotomo.js_generator
    end
  end
end

The test helper is required, then we run an ordinary unit test against the gem classes, modules and methods.

Testing controllers

Things get complicated when it comes to testing controllers that use new Apotomo behaviour. I don’t want to setup things, so I use a small Rails test application in my tests. I initially stole that from José Valim’s devise, that everybody loves.

Enginex is a generator

The enginex command creates a rails app for me.

apotomo/test$ enginex dummy

Unfortunately, enginex assumes I want a new gem with a setup test directory, so what it does is:

dummy
|-- Gemfile
|-- lib
|   `-- dummy.rb
|-- Rakefile
`-- test
    |-- dummy
    |   |-- app
    |   |   |-- controllers
    |   |   |   `-- application_controller.rb
    |   |   `-- views
    |   |-- config
    |   |   |-- application.rb
    |   |   |-- environment.rb
    |   |   `-- routes.rb
  ...

What I need resides in dummy/test/dummy, so I move things a bit.

apotomo/test$ mv dummy dummy_gem
apotomo/test$ mv dummy_gem/test/dummy dummy
apotomo/test$ rm -r dummy_gem

Now I got a rails app in my test/ directory.

dummy/
|-- app
|   |-- controllers
|-- config
|   |-- application.rb
|   |-- environment.rb
...

I also remove the line

require "dummy"

in test/dummy/config/application.rb.

You’re now free to setup testing scenarios in dummy by adding controllers, actions and everything else.

Requiring the test app

My apotomo/test/test_helper.rb gets a bit longer.

ENV['RAILS_ENV'] = 'test'
require "dummy/config/environment"
require "rails/test_help"

This is all I need for now, I can now run a ActionController::TestCase against a controller in my dummy app.

Note that you should first require your engine, then the rails app so your tested gem is available in the dummy app.

Functional tests

Let’s go actually testing controllers.

Remember: we’re testing a gem that extends controllers, so first, we write a small imaginary controller and put it in test/dummy/app/controllers/dummy_controller.rb.

class DummyController < ApplicationController
  include Apotomo
 
  def apotomo
    render_widget "root" # Just some bullshit to test Apotomo.
  end
end

In the controller, I really use Apotomo as if I would be a user using it. No monkey-patching and stuff – it is a test validating that my gem works in shitty real-world controllers.

require 'test_helper'
 
class ApotomoIntegrationTest < ActionController::TestCase
  tests DummyController
 
  context "The controller" do
    should "render widgets" do
      get :apotomo
      assert_select "div#root", "I'm root"
    end
  end
end

ActionController::TestCase provides a relatively easy way to write functional tests.

Naturally, you can also test “native” controllers and routes from your engine the same way.

Unit testing controllers

Sometimes pure functional tests are too less and a unit test for your controller methods would be handy – I do that often.

require 'test_helper'
 
class ApotomoControllerMethodTest < ActionController::TestCase
  tests DummyController
 
  context "The controller" do
    should "respond to #render_widget" do
      assert_responds_to @controller, :render_widget
    end
  end
end

The test case automatically provides a controller instance in @controller. You’re free to invoke methods and test ‘em.

These were the basic steps, if you wanna know more, ask!

Comments appreciated

Dudes, why are you guys so shy? Tell me how you do it, what you like and what sucks. I really appreciate comments.

Releasing Gems self-opinionated

Wednesday, September 15th, 2010

Packaging and releasing gems is easy. Many people simply use jeweler to handle all the tiresome tasks. Others try to avoid 3rd-party tools and don’t take any “opinionated” shortcuts at all.

Not that I would care about opinions, anyway. However, I catched myself using a mixture of all ruby release tools, so here’s my current workflow.

1. Get your tests running

At some point you usually notice that your code is stable (or looks as if, at least) and you decide to release a gem. Yiha, party time!

2. Bump the version

I like doing this manually. Why? It’s so simple. Open the version.rb file, edit and save.

So, after incrementing the version by whatever minor, major, patchlevel or development flag, the version file ends up with something like

module Cells
  VERSION = "3.4.0.beta2" # i was "3.4.0.beta1"!
end

3. Update the gemspec

Now this is something where jeweler comes in handy! Having a decent Rakefile configuration I punch in

$ rake gemspec

and let jeweler create my gemspec file. Why should I write my own rake task if this gem does it for me?

4. Check the gemspec

That’s something I do. Always. Open cells.gemspec and check if all files are listed.

To get rid of nasty tmp files that aren’t packaged in your gem but appear in the gemspec, tweak the Rakefile:

spec.files        = FileList["[A-Z]*", "lib/**/*"] - ["Gemfile.lock"]
spec.test_files   = FileList["test/**/*"] - FileList["test/dummy/log/*"]

5. Commit and tag

I like doing this manually as well. I remember times where jeweler used to drive me nuts and wouldn’t let me do me what I want.

$ git commit -m "releasing 3.4.0.beta2 which looks kinda stable, dude."
$ git tag v3.4.0.beta2

Tagging this commit is important, so people browsing your code on github can jump to specific versions. You even may want to push things to your origin now.

6. Build the gem and release

Couple of months ago I happened to learn that this can be done with gem itself. The command packages and releases the gem.

$ gem build cells.gemspec

This bundles all the files into a new file cells-3.4.0.beta2.gem, which is awesome.

Let’s push it to rubygems.org.

$ gem push cells-3.4.0.beta2.gem

At this point, lean back and grab a beer. You’re done.

I really like the diversity of tools in open-source communities. And I love the fact that I’m free to use ‘em in combination. So that’s how I release things and keep control over several building steps.

You like it?

Receiving Pingbacks on Rails sites

Monday, December 22nd, 2008

If you’ve never heard of pingbacks before, you’re out. Go home.

Ok, pingbacks are this mysterical feature when you write on your blog A and refer to some article on blog B. After you publish your article on blog A, something happens behind the curtain. Suddenly there’s a new comment on the blog B article you cited in your text, and this comment links back to your article on your blog A. That’s called a pingback.

Whereas sending a pingback is just a modest effort by fireing some small XML-RPC request, receiving is quite a bunch of work. A pingback’able site needs to

  • provide an XML-RPC capable server to receive pings
  • check the refering site’s article for the link to us
  • excerpt a piece of content from this refering article on blog A
  • store the extracted content with the link on the pinged page, maybe as a comment

Fortunately, there’s already a Rails plugin to handle this tedious task, namely pingback_engine which I wrote as a christmas gift for my friends on the net.

Receiving Pingbacks with pingback_engine

To make our Rails app pingback’able we need to install the engine, setup the server url propagation and then hook in a method for processing incoming pings. That is awesomely easy.

Installation

Inside the rails app directory install the engine, and a needed gem.

script/plugin install git://github.com/apotonick/pingback_engine.git
gem install hpricot

Your Rails app is now capable of receiving pingbacks via XML-RPC.

Propagating the server for auto-discovery

However, if a blog links to you, this blog will usually scan your page to discover the XML-RPC pingback server. What a pingback’able page should do to propagate this url is described in the pingback specification.

It roughly says, to define a pingback-enabled page

  • either return a X-Pingback HTTP header
  • or provide a special link element in the page HTML header
  • or do both!

In our example, we’re on the safe side by providing both. I instruct my blog controller to send an X-Pingback header by calling set_xpingback_header in the action that shows my articles.

# file: app/controllers/blog_controller.rb
 
class BlogController
    include PingbackHelper
    helper :pingback
 
    def article
      set_xpingback_header
      # ...

This will send the respective header with the correct url as soon as some blog tries to auto-discover the address for your XML-RPC pingback server.

Additionally, we provide a special <link ..> element in our application layout so the XML-RPC address is visible everywhere in the app.

# file: app/views/layouts/application.html.erb
 
      ...
      <%= pingback_link_tag %>

Now other blogs will find your pingback server if some article links to your site.

Processing an incoming pingback
The only thing we have to implement is the pingback processing method. It’s currently put at the bottom of the rails environment file. Of course I could just delegate to another class method in some model, but for demonstration purpose it’s all in one file.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# file: config/environment.rb.
 
# ...
Pingback.save_callback do |ping|
    comment = ArticleComment.new
    comment.author     = ping.title
    comment.author_url = ping.source_uri
    comment.text       = ping.content
    comment.created_at = ping.time
 
    referenced_article = Article.find_by_url(ping.target_uri)
 
    if referenced_article
      comment.article_id = referenced_article.id
      comment.save
 
      ping.reply_ok # report success.
    else
      # report error:
      ping.reply_target_uri_does_not_accept_posts
    end
  end

Easy. Into the block to Pingback.save_callback we get a ping instance, which is enough to process, check and store the incoming pingback.
I just

  • create an ArticleComment instance, which is an ActiveRecord-derived class and represents comments in my blog (line 22)
  • assign -or map- values from ping to the comment
  • check the ping if it really points to an article in my blog
  • decide the incoming ping is invalid and discard it (line 37)
  • or save the comment in my blog and report success (line 34)

Anyway, all we have to do now is to login to some blog (recent WordPress blogs work great) and publish an article that links to a pingback’able page on our Rails site. The blog will send us all the information we need to receive the ping, and the pingback_engine will almost do the rest!

Testing manually
For debugging or testing purposes you can also use a test script shipped with the plugin. All you need is your set up rails site and a HTML page accessable on some webserver. The HTML page must link to a pingback-enabled page on your rails site.

By firing

pingback_engine $> script/send_pingback.rb http://site.com/page_linking_to_us.html http://my.rails.site.com/article-31

you can issue an XML-RPC pingback on the local server and debug things.

However, it should all work as it is shipped, so have fun when making your Rails site pingback’able!