With the upcoming release of
Merb 0.4.0 lets say goodbye to respond_to and hello to provides.
This isn't as bad as it might look at first glance. I remember when rails first brought out respond_to. I thought it was awesome, and it certainly has been a good, enabling method. Merb borrowed this along with a slew of other good ideas from rails, but today Merb transcends respond_to.
The provides method does a similar job to respond_to. It gives the user the format they want if it's available. It just does it a bit differently.
Lets have an example
class OldWay < Merb::Controller
def index
@items = Item.find(:all)
respond_to do |fmt|
fmt.html { render }
fmt.js { @items.to_json }
fmt.xml { render } # use a template
end
end
def show
@item = Item.find(:first)
respond_to do |fmt|
fmt.js { render } # use a template
fmt.xml{ @item.to_xml }
end
end
#...
end
I'm sure this kind of controller setup is reasonably familiar with anyone who is offering more than plain html to users.
Lets see this same example as it is with the new provides functionality.
class NewWay < Merb::Controller
provides :js, :xml
def index
@items = Item.find(:all)
render @items
end
def show
does_not_provide :html
@item = Item.find(:first)
render @item
end
#...
end
To my eye, that's much more concise.
This will respond to the user with the format they selected and the correct headers. But the good juju is not just that provides will select the format to return to the client. Render now accepts a model or ORM collection object as well. Say you call render with an object it will render a template if it finds one, otherwise it will attempt to call to_
format method on the object.
What... No Blocks per Format
This behavior should cover a good proportion of cases without intervention, but if you need something more explicit you can fall back to good ol' ruby and use a case statement. The
content_type method will give you the current format so you can be as fine grained as you like.
How to Control all this POWER?
There are a number of methods available.
provides :format1, :format2
only_provides :format1, :format3
does_not_provide :format6
These are available as both class an instance methods so you can combine them for very fine control.
Is it extensible?
What if you want to add your own format that a controller provides? Lets say you wanted to add an MS Word format for your controller. First add the mime type you want to merb specifying the format extension, transforming method, and possible accept headers.
Merb.add_mime_type(:doc, :to_doc, %w[application/vnd.ms-word])
This makes the doc format available for use in your controller
provides :doc
# ...
render @obj
to_doc will be called on @obj and the outgoing content-type header is set to application/vnd.ms-word. Using to_doc on a model is not the best idea, please remember I'm just using it as an example.