I’m working on a RESTful app, and I’ve hit a snag. Here’s a
simplified example of the problem. (Excuse me if this example code
isn’t strictly correct; I’m typing from memory.)
Suppose I have a table which models a simple counter. It has a single
column, “count”:
class CreateCounters < ActiveRecord::Migration
def self.up
create_table :counters do |t|
t.column :count, :integer
end
end
def self.down
drop_table :counters
end
I’ve created a RESTful controller using the scaffold_resource
generator. In the “show” view, I’d like to put a link which
increments the counter by one:
<%= h @counter.content %>
<%= button_to “++”, ??? %>
If this were a traditional rails app, the next step would be obvious.
I’d add an “increment” action to the controller:
CounterController
…
def increment
@counter = Counter.find(params[:id])
@counter.count += 1
@counter.save
redirect_to :action => “show”
end
end
And I’d link the action to the controller:
<%= h @counter.content %>
<%= button_to “++”, :action => “increment” %>
However, this isn’t RESTful. The REST way, as best I understand, is
that updates to an existing resource are accomplished by PUTing an
updated version of the resource to the resource’s path, as if the user
had opened the “edit” view, manually incremented the count, and
clicked “submit”.
And that’s where I get hung up. How do I create a link (or button) in
the view which will call “update” in this way?
Here’s one attempt I made:
<%= h @counter.content %>
<%= button_to “++”,
counter_path(
:id => @counter,
:counter => { :count => @counter.count + 1 } ),
:method => :put %>
But that’s wrong for two reasons. First, the counter_path helper
flattens the nested hash, so the for a counter with id 1 and
count==42, the URL comes out like “/counters/1?count43” - which won’t
be parsed correctly into the params hash by the “update” action.
Second, and more importantly, it’s not truly RESTful, because it’s
PUTing to “/counters/1?count43”, not “/counters/1”.
As far as I can tell what I really need is a way to add extra hidden
fields to the form that button_to generates. But I can’t find any way
to do that. And from my reading of the button_to (and link_to)
source, there is no way to do this.
So: am I missing something? What’s the right way to do this? Do I
have to construct the form and hidden fields manually, without the
help of button_to? Or is there another way to go about it entirely?
Thanks in advance,
–
Avdi