Archives

Tags

Showing articles written in January 2009. Show all articles

REST-mapping anchor elements in Merb

One of the things I liked about the REST implementation in Rails was the ability to use an anchor to fire off a HTTP "PUT" or "DELETE" request (or, rather the illusion of such) using the link_to helper method. It basically generates a chunk of inline JavaScript in the anchors onclick event that constructs a POST form, adds a few hidden elements, and finally submits it.

I noticed the functionality was not implemented in Merb. This is not totally surprising to me. I mean, inline JavaScript is never pretty. It also means we are relying on Javascript for the link to work correctly.

Regardless of my initial inhibitions, I decided to implement the functionality into a Merb application I was working on. The main chunk came down to this mixin to Merb::AssetsMixin:

module Merb
  module AssetsMixin

    alias_method :orig_link_to, :link_to

    def link_to(name, url='', opts={})
      if opts.include?(:method)
        method = opts.delete(:method)

        if [ :put, :delete ].include? method
          opts[:onclick] = "var f = document.createElement('form'); f.style.display = 'none'; " +
                           "this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href; " +
                           "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); " +
                           "m.setAttribute('name', '_method'); m.setAttribute('value', '#{method}'); " +
                           "f.appendChild(m);f.submit(); return false;"
        else
          raise ArgumentError, "The :method option only accepts :put or :delete."
        end
      end

      orig_link_to name, url, opts
    end

  end
end

It mimicks Rails behaviour. Therefore, I call it like this:

link_to "Delete", url(:post, 1), :method => :delete
# OR
link_to "Save changes", url(:post, 1), :method => :put

I also wrote a bunch of specs and threw it up on GitHub. Eventually, I plan to set it (and the rest of my hacks) up as proper Merb plugins. If anyone wants to give me a hand, feel free to fork the project(s) and do your thing...