Archives
Tags
- General (18)
- Food (1)
- Cooking (1)
- Ruby (6)
- Rails (2)
- Svn (2)
- Linux (9)
- Git (1)
- Firefox (8)
- Porn (1)
- Freyja (1)
- Witchhammer (6)
- Music (1)
- Merb (3)
- Poetry (0)
- Bolverk (3)
- Sinatra (1)
- Discogs (1)
- Centos (1)
- Python (1)
- Whinging (2)
- Travel (2)
- Scheme (7)
- Lisp (8)
- Sicp (1)
- Rot13 (1)
- Czech (2)
- Metal (3)
- Passenger (1)
- Fun (5)
- Fractals (2)
- Plt (2)
- Clojure (1)
- Continuations (1)
- Javascript (1)
- Presentation (1)
My first Merb site
Just a quick note to my legions of loyal followers (hey, Mum), I've just finished my first website written using the Merb framework.
Development travelled along relatively well. I ran into a few issues early on with dependency hell and some bugs and/or missing functionality in a few gems. I blogged about a few of my hacks.
Here is my (partial) technology stack:
- ORM: DataMapper
- Tests: RSpec
- Views: HAML/SASS (which I won't be using again, even though it's very well written)
- Hosting: Dreamhost (using Phusion Passenger, which was easy to use with a config.ru file for Rack)
I still haven't worked out how to properly get Capistrano working with the Dreamhost setup, but shit happens...
Auf wiedersehen!
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
endIt 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...
Multiple before/after model filters with Merb
This evening I found myself in a position in which I wanted to execute several "before" methods hooks/filters on a DataMapper model in a Merb application. I had a look around in the source and API docs, but couldn't really find a nice way of doing it (even though having every hook on a seperate line is not such a bad thing in terms of readability, I suppose).
Anyway, I came up with the following mixin for Extlib (which houses DataMapper's before/after hook functionality):
module Extlib
module Hook
module ClassMethods
alias_method :singular_before, :before
alias_method :singular_after, :after
def before(target_methods, filter_methods = nil, &block)
insert_multiple_hooks "before", target_methods, filter_methods, &block
end
def after(target_methods, filter_methods = nil, &block)
insert_multiple_hooks "after", target_methods, filter_methods, &block
end
private
def insert_multiple_hooks(context, target_methods, filter_methods, &block)
targets = [target_methods].flatten
filters = [filter_methods].flatten
targets.each do |target|
filters.each do |filter|
send("singular_#{context}", target.to_sym, filter.to_sym, &block)
end
end
end
end
end
end Hopefully it is fairly straight-forward. Basically, it will allow you to pass an array to the before and after methods. For example, you can do this:
before [ :create, :update ], [ :set_filename, :set_filesize, :generate_thumbnail ]
Which is equivalent to:
before :create, :set_filename before :create, :set_filesize before :create, :generate_thumbnail before :update, :set_filename before :update, :set_filesize before :update, :generate_thumbnail
I got it loaded into my Merb app by creating an app/lib directory and requireing the contents of it from the config/init.rb file.