Search code examples
ruby-on-railsroutesrails-routing

Rails custom action missing required key error


show.html.erb

<h1><%= @script.Name %></h1>

<%= simple_form_for @script , :url => script_execute_path do |f| %>
  <%= f.input :mainDirectory %>
  <%= f.input :customFilePath %>
  <%= f.button :submit, 'Run' %>
<% end %>

routes.rb

  root :to => "scripts#index"
  resources :scripts do
    get "execute"
  end

Model

class AddNameToScript < ActiveRecord::Migration
  def change
    add_column :scripts, :Name, :string
    add_column :scripts, :Description, :text
  end
end

execute is a custom action added by me and I want to goto that action from show.

routes.rb

...
    script_execute GET    /scripts/:script_id/execute(.:format) scripts#execute
...

But I am getting an error

No route matches {:action=>"execute", :controller=>"scripts", :id=>"1"} 
missing required keys: [:script_id]

But why do I need a [:script_id]? Isn't it a custom action and I can define the way I want? What's missing here and how do I pass [:script_id]?


Solution

  • As you can see from your router output, execute is expecting a script_id parameter (/scripts/:script_id/execute(.:format). To remove that expectation, you need to declare that route at the collection instead of member level. You can do this in one of two ways:

    get :execute, on: :collection
    

    Or if you have other routes that you want to include on the collection, you can throw it in a block:

    collection do
      get :execute
    end
    

    FYI, after this change run rake routes | grep execute again to see what the name of the URL helper has changed to so you can update your view accordingly.

    Cheers!


    UPDATE:

    To answer the question in the comments, if you wanted to pass in a script_id parameter (or any parameter for that matter), you can do so by declaring it as a parameter to the URL helper. So based on your current view, it would look like this:

    <h1><%= @script.Name %></h1>
    
    <%= simple_form_for @script , :url => script_execute_path(script_id: @script.id) do |f| %>
      <%= f.input :mainDirectory %>
      <%= f.input :customFilePath %>
      <%= f.button :submit, 'Run' %>
    <% end %>
    

    However, I would like to point out a couple more things here:

    1. It appears that you're intending to update a Script object, so I'm not sure why you're creating the execute method from a show view, instead of just using the update method that's already available via resources :scripts from an edit view.
    2. Again, it appears that you're intending to PUT or POST something based on your view, but your execute route is defined as a GET. Not sure if that's what you intend.