Frage

I'm trying to map a form_for to a specific controller and action. I've got the resources: apikey in the routes. All the solutions I've found don't seem to work. The form is placed inside a view of which the parent folder name doesn't correspond to the correct controller. Here is my form with my not working solution:

<%= form_for @key, url: { controller: :apikey, action: :update }, remote: true do |f| %>
  <%= f.label :userkey, "Key" %>
  <%= f.text_field :userkey %>
  <%= f.submit "Update" %>
<% end %>

Here is my controller:

class ApikeyController < ApplicationController
  def index
  end

  def update
    respond_to do |format|
      if @key.update(apikey_params)
        format.js
      else
        format.html { render action: 'edit' }
      end
    end
  end

  private

  def apikey_params
    params.require(:apikey).permit(:userkey)
  end

end

This is the log I get in the console:

Started GET "/accounts?utf8=%E2%9C%93&_method=patch&apikey%5Buserkey%5D=thekey&commit=Update" 

As you can see, it doesn't call the apikey but the accounts controller. What am I doing wrong?

Update

A little weird, as I didn't really change anything, I now get this error when opening the site:

No route matches {:action=>"update", :controller=>"apikey"}

This is my rake routes:

 apikey_index GET    /apikey(.:format)            apikey#index
              POST   /apikey(.:format)            apikey#create
   new_apikey GET    /apikey/new(.:format)        apikey#new
  edit_apikey GET    /apikey/:id/edit(.:format)   apikey#edit
       apikey GET    /apikey/:id(.:format)        apikey#show
              PATCH  /apikey/:id(.:format)        apikey#update
              PUT    /apikey/:id(.:format)        apikey#update
              DELETE /apikey/:id(.:format)        apikey#destroy

Update 2 Originally I had the form inside a bootstrap modal, like this:

<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
        <h4 class="modal-title" id="myModalLabel">Change API key</h4>
      </div>
      <div class="modal-body">

        <form role="form">
          <div class="form-group">

            <%= form_for @key, method: "post", remote: true do |f| %>
                <%= f.label :userkey, "Key" %>
                <%= f.text_field :userkey, class:"form-control", id:"apikeyinputfield" %>
                <%= f.submit "Update", class: "btn btn-success btn-sm" %>
            <% end %>

          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" id="submitnewapikey" data-dismiss="modal" class="btn btn-primary">Save changes</button>


      </div>
    </div>
  </div>
</div>

If I delete the surrounding modal, the form automatically to map to the correct controller and action. This is not the case when surrounded by the modal. Really weird. Maybe the modal JS code messes up the form_for JS code.

War es hilfreich?

Lösung

You don't actually need to specify the url in form_for. If no url is specified form_for will automatically identify which controller and method based on the @key parsed to it, regardless of what view the form is located.

<%= form_for @key, remote: true do |f| %>
  <%= f.label :userkey, "Key" %>
  <%= f.text_field :userkey %>
  <%= f.submit "Update" %>
<% end %>

the piece code above can have the following outcomes:

  • if @key is a new record ( @key.new_record? returns true):

    • The form will send the request to ApikeyController create action
  • if @key is a not a new record ( @key.new_record? returns false), which is your case:

    • The form will send the request to ApikeyController update action

More info can be found here.

Hope this can help you.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top