views:

61

answers:

2

Let's say I have a model foo, and my model has a publish! method that changes a few properties on that model and potentially a few others too.

Now, the Rails way suggests that I expose my model over rest and let the end user monkey with parameters.

What should I do if I want to expose my publish! method instead to protect my model? Is this even the best way of looking at this?

A: 

You'd add a method to your FooController that called the publish! method.

Example:

in config/routes.rb:

map.publish_foo "/foos/:id/publish/:bar", :controller => "foo", :action => "publish"

in app/controllers/foo_controller.rb

def publish
    @foo = Foo.find params[:id]
    @foo.publish!(params[:bar])
    flash[:notice] = "Your Foo has been published."
    redirect_to @foo
end

Of course, you probably want some error handling.

Steve Klabnik
This solution has one problem - it violates one of the main guidelines of REST - you've got a verb in the URL.
Milan Novota
He didn't actually say that he was concerned with staying strictly REST-ful. If he is, your solution is far better.
Steve Klabnik
That's a fair point.
Milan Novota
+3  A: 

Since you are trying to do this in a REST way, what you need to do at first is to find a resource - some thing you can query with one of the HTTP verbs.

I'd say that the "thing" we need to identify here is the status of foo. Translated into a URL:

/foos/:id/status

Status of concrete foo is a resource - and that's the first thing we need when trying to be REST compliant. When we publish some foo, it means we change (update) its status, right? So, what we need to do next is to create a route and a method which will handle the "update status of foo" request.

To do this, just add this into your routes.rb file:

map.connect "/foos/:id/status", :controller => "foos", :action => "change_status", :conditions => { :methods =>  :put }

and add something like this into your foos controller file:

# simplified
def change_status
  status_name = params[:status_name]
  foo = Foo.find(params[:id])
  foo.publish! if status_name == "published"
end

In this manner you'll end up with a quite decent RESTful design.

Milan Novota