Rails 4 link_to method: :post and remote: true strange behavior

772 Views Asked by At

I have an event management page which contains two partials, one with the partners not yet invited to the event, one with the partners invited to the event. Partners can either be added to the event (other_partners collection) or be removed (current_partners collection).

Strange behavior depending on order of actions

Delete then create => Everything is ok, I can add and remove with no limit

Once the page loaded, I can remove partner (method: :delete) whithout any problem, partner disappear from current_partners collection (partial) and appears in other_partners collection (partial). If a try to add a partner, it works and the partner is added to current_partners collection and removed from other_partners collection

Create then GET 500 ERROR => Rails seems to ignore ujs

Once the page loaded, If I click on a partner inside other_partner partial to add (method: :post) it to the event, rails ignores the method: :post and GET the url provided, which causes a 500 error because the action show is not present inside my controller (only create and destroy)

Here is my code :

_other_partner.html.erb

is a partial containing user's partners that don't participate to the event. On click on a partner, it is added to the event, disappear form the other_partners collection and appears in the current_partners collection.

Note that the url looks like /events/1/manage_partners?id=21. I'm passing the id of partner as additional param to create the link between event and partner. I'm not using button because partials already are inside a larger form.

  <%= div_for partner, class: "partner__current",
                       data: { behavior: "partner", id: partner.id } do %>

    <%= link_to event_manage_partners_path(event, id: partner.id),
                method: :post,
                data: { behavior: "create-partner" },
                remote: true,
                class: "link--primary" do %>
        <%= content_tag :div, nil, class: "icon icon__add_circle--black" %>
    <% end %>

  <% end %>

-

_current_partner.html.erb

is a partial listing all the partners that participates to the event. On click on a partner, it is deleted from the event, disappear from the current_partners collection and appears in the other_partners collection.

  <%= div_for partner, class: "partner__current",
                       data: { behavior: "partner" } do %>

    <%= link_to event_manage_partner_path(event, partner),
                method: :delete,
                remote: true,
                class: "link--primary" do %>
        <%= content_tag :div, nil, class: "icon icon__cancel_circle--black" %>
    <% end %>

  <% end %>

-

event.html.erb

<%= render partial: 'partners/other_partner',
                     collection: @event_facade.other_partners,
                     as: :partner,
                     locals: { event: @event_facade.event },
                     cached: true %>
<% end %>

<%= render partial: 'partners/current_partner',
                     collection: @event_facade.current_partners,
                     as: :partner,
                     locals: { event: @event_facade.event },
                     cached: true %>
<% end %>

-

create.js and destroy.js (both are similar)

$("[data-behavior='new-partner']").html("<%= j render partial: 'partners/other_partner', collection: @event_facade.other_partners, as: :partner, locals: { event: @event_facade.event }, cached: true %>");

$("[data-behavior='current-partners']").html("<%= j render partial: 'partners/current_partner', collection: @event_facade.current_partners, as: :partner, locals: { event: @event_facade.event }, cached: true %>");

-

events/manage_partner_controller.rb

module Events
  class ManagePartnersController < ApplicationController
    before_action :set_event

    def create # (url looks like /events/1/manage_partners?id=21)
      @event_facade = EventFacade.new(@event)
      EventPartnerService.new(@event).join_event(params[:id])
      respond_to do |format|
        format.html { redirect_to edit_event_url(@event) }
        format.js # { render layout: false }
      end
    end

    def destroy
      @event_facade = EventFacade.new(@event)
      EventPartnerService.new(@event).leave_event(params[:id], current_user)
      respond_to do |format|
        format.html { redirect_to edit_event_url(@event) }
        format.js # { render layout: false }
      end
    end

    private

    def set_event
      @event = current_user.events.find(params[:event_id])
    end

  end
end

-

layout/application.html.erb

<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>

-

assets/javascript/application.js (jquery-ujs loaded by bower)

//= require jquery/dist/jquery.min
//= require jquery.turbolinks
//
//= require jquery-ujs/src/rails
//= require turbolinks

-

routes.rb

resources :users, only: [:index, :show], concerns: :paginatable do
  resources :events, except: :new, concerns: :paginatable do
    resources :manage_partners, controller: 'events/manage_partners', only:[:create, :destroy]
  end
end

-

rake routes output

event_manage_partners POST (/:locale)/events/:event_id/manage_partners(.:format) events/manage_partners#create {:locale=>/en-US|fr-FR/}

event_manage_partner DELETE (/:locale)/events/:event_id/manage_partners/:id(.:format) events/manage_partners#destroy {:locale=>/en-US|fr-FR/}

Here is the 500 error:

ActionController::RoutingError (No route matches [GET] "/events/81/manage_partners"):

Rails tries to GET when I specifically ask for POST. The manage_partners_controller.rb doesn't contain an show action, only #create and #destroy, thus the error.

Again, everything works fine except the method: :post which is ignored when the link is clicked just after first page load. Strange behavior, and I'm pretty clueless here. Please help. Thank you!

1

There are 1 best solutions below

5
Yoklan On

Could be cause you are nesting a level too deep, you shouldn't nest resources more then one level deep. Take a look at this http://guides.rubyonrails.org/routing.html#nested-resources

Put this in the header of my page which solved issues with turbolink

  if(typeof Turbolinks != 'undefined') {
    $(document).on("page:change", function(){
      myFunction();
    });
  }
  else {
    $(document).ready(function (){
      myFunction();
    }); 
  }