5

I have a form with a list of stuff, and an action already in place to update items.

I want to have another button, which when clicked triggers a different action to remove the selected items.

  = form_for @new_item,:url => {:controller => "item_lists",:action => "update_list" } do |f|
     - @items.each do |it|
    %input{:type=>"hidden",:name=>"item_list[#{it.id}]position",:value=>it.position, :class=>'position'}
    %textarea{:name=>"item_list[#{it.id}]field1"}
      =it.field1
    %textarea{:name=>"item_list[#{it.id}]field2"}
      =it.field2
    %input{:type=>'checkbox', :name=>'selected_items[]', :value=>it.id}
    =(it.valid?) ? "" : it.errors.full_messages




    %input{:type=>"submit", :value=>"Save changes", :name=>'save'}
    %input{:type=>"submit", :value=>"Remove selected", :name=>'delete'}

This question seems to indicate I should inspect params in my action to figure out what was clicked. But that feels messy, my controller could quickly degenerate into a mass of ifs when I add more actions.

Is there a more elegant way to do this, i.e. get it to just route to the correct method?

Thanks for any help...

Community
  • 1
  • 1
Chris
  • 6,076
  • 11
  • 48
  • 62

2 Answers2

5

This doesn't really gel with REST. In REST and Rails you're typically going to have one action per endpoint, not decide on the endpoint based on some criteria in the request.

That being said, you can filter actions based on the submit button by checking the name of the button pressed. See this SO question.

I'd argue though that this is only appropriate if your form is doing slightly different things, like perhaps a submit button that updates in place versus a submit button that redirects somewhere afterward, e.g. "Update" versus "Update and Continue" (contrived, but you get what I mean).


Addressing your concern in the comments, your method wouldn't have to devolve into a long sequence of ifs. You could just write some code to determine which method to call based on the name of the submit button. A simple implementation might be:

# your form action
def update_list
  send update_list_action
end

protected

def update_list_action
  # just return the first action name found in the params
  action = %w(save delete).detect {|action| params[action] }
  "update_list_#{action}"
end

def update_list_save
  # handle save
end

def update_list_delete
  # handle delete
end
Community
  • 1
  • 1
numbers1311407
  • 33,686
  • 9
  • 90
  • 92
  • One action is to update items on the list, the other is to delete items on the list. The "REST" approach would be to force the user to click through to edit / delete each item individually, but I fear it will be a poor user experience... – Chris Nov 24 '11 at 16:35
  • It's not a rails problem but a general HTML problem. Submit buttons simply submit forms. There are various ways you can get around this to hide this limitation, but they're all going to be hacky (behind the scenes JS or dependence on button click events), cumbersome (e.g. a select box that passes the sub-action), or both. – numbers1311407 Nov 24 '11 at 17:17
  • In java spring you can just annotate your methods in the controller and it will call the correct one based on submit parameters even when posting to the same url. I'm surprised rails doesn't provide something similar, as different buttons on a form doing different things on a controller seems like a very common thing. – Chris Nov 25 '11 at 09:54
  • Rails probably doesn't *provide* anything similar because A.) it's geared toward REST, which frowns upon this sort of thing, and B.) you could do this yourself without much trouble. See my answer edit. – numbers1311407 Nov 25 '11 at 13:58
  • 1
    Thanks for your help, doesn't look as evil as I thought it would. I still think that the router should in principle be able to do this. This muddies the waters a bit IMO. REST is great for APIs and services but I don't think REST principles should dictate the end users experience. – Chris Nov 25 '11 at 16:30
0

I would suggest you to add a dropdown menue with the option "delete", "update",... and add some jQuery code that observes the selected item and changes the action of your form depending on the value because you shouldnt use one action to update and delete objects! There should be one action for updating and one for deleting!

davidb
  • 8,884
  • 4
  • 36
  • 72