Search code examples
ruby-on-railsrubyformsroutesactioncontroller

Rails, form is calling wrong action


I have made my form:

      <tbody>
        <% @player.bases.each do |basis| %>
        <td><%= basis.id %></td>
        <td><%= image_tag(basis.image_url(:thumb), class: 'thumbnail') %></td>
        <td><%= link_to basis.name, basis %></td>
        <td><%= basis.cost %></td>
        <td><%= basis.short_info %></td>
        <td>
            <%= form_for @player, url: {:controller => 'players', :action => :remove_detail} do |f| %>
              <%= f.hidden_field :type, :value => 'basis' %>
              <%= f.hidden_field :detail_id, :value => basis.id %>
              <%= f.submit 'Remove',class: 'btn btn-danger' %>
            <% end %>
        </td>
        <% end %>
      </tbody>

In my routes, I have added this:

resources :players do
 collection do
   get 'search'
   post 'remove_detail'
 end
end

I have remove_detail in my players_controller.rb, and I have added this action to before_action to get current player. However when I press on my Remove button, it throws me error and tries to run update action of my controller. Why?

My before_action:

before_action :set_player, only: [:show, :edit, :update, :destroy, :remove_detail]

My remove_detail:

def remove_detail
type = params['type']
id = params['detail_id']

if type == 'basis'
  basis = Basis.find(id)
  name = basis.name
  @player.bases.delete(basis)

end

redirect_to @player, notice: "#{name} detail is removed"

end

Solution

  • To fix that, try as follows:

    First of all, I'd redefine your routes as follows:

    resources :players do
      member do
        delete 'remove_detail'
      end
    
      collection do
        get 'search'
      end
    end
    

    This will generate proper url for deleting a detail for a "single Player":

    /players/:id/remove_detail
    

    Because of REST-y nature of Rails, we defined the url to be accessible by performing delete request.

    Your form change accordingly:

    <%= form_for @player, { url: { action: "remove_detail" }, method: :delete } do |f| %>
    

    Changing your routes to use delete method is more to keep the convention of Rails. Post would make your application work too, but - its just Rails-y way.

    Good luck!