Chad Denaux
Chad Denaux

Reputation: 139

Rails - turbolinks issue

I am trying to have jquery enabled after the redirect_to update_path, I have tried disabling turbolinks all-together, but that doesn't help. I am currently doing a window.location.reload() function on successful update, but it is a horribly ugly work around. Is there a better way to accomplish this?

this is in .js

    $.ajax ({
         type: 'POST',
         url: "http://localhost:3000/chess/" + sv + "/" + val,
         success: function(d){
            count = 0;
            window.location.reload();
         }

       });

this is in the controller.rb:

def move
  piece = params[:piece].chomp(",").each_char.map(&:to_i)
  a = piece[0]
  b = piece[2]

  square = params[:square].chomp(",").each_char.map(&:to_i)
  c= square[0]
  d= square[2]

  pieceVal = @@arr[a][b]
  squareVal = @@arr[c][d]

  @@arr = @@arr.each_with_index.map do | e1, i1|
    @@arr[i1].each_with_index.map do |e2, i2|
       if (i1 === a && i2 ===b)
         @@arr[a][b]  = [0]
       elsif (i1 === c && i2 === d)
        @@arr[c][d] = pieceVal
       else
        e2 = @@arr[i1][i2] 
       end
    end
  end

  redirect_to update_path



end

I tried setting turbolinks: false after redirect, but that just disabled the jquery completely.

Upvotes: 0

Views: 322

Answers (1)

Josh Brody
Josh Brody

Reputation: 5363

Sorry for the book: I thought I'd explain what's going on instead of just giving you an answer.

Issue

So turbolinks is a non-issue here. The issue is in your implementation (and it's not that big of issue)

When you write redirect_to ..., it tells your browser go to to the Location as specified in the response header. It returns no body (like a GET request returns a body of HTML)

The implementation

The trick here is to implement some way of replacing the content of the chess board with the new chess board, without reloading the entire page. Because we already know the output of the new chess board, we can do that with javascript.

HTTP requests by example

HTTP requests (think of them as the results of controller methods) can respond to many different formats. You're already familiar with HTML responses, those are standard. There are other formats, including (but not limited to) XHR requests (stands for XML HTTP Request) and JSON requests.

Similarly to my response to a question you asked yesterday, you can see the difference by adding the following into application_controller.rb (assuming you added the other code as well):

def test
  respond_to do |format|
    format.html { render :text => "I love me some #{params[:cookies]} with my #{params[:cream]}" } 
    format.json { render :json => { :result => "I love me some #{params[:cookies]} with my #{params[:cream]}", :cookie_result => params[:cookies], :what_kind_of_cream_did_he_want => params[:cream] } 
    format.js { render :text => "alert('I love me some #{params[:cookies]} with my #{params[:cream]}');" } 
  end
end

And then hitting localhost:3000/chocolate-chip/and/milk.json in your browser to view the resulting JSON, for example.

Of note: Rails expects XHR requests (most of the time, a response for ajax requests) to have a format of js, don't let it trip you up.

We can't call localhost:3000/chocolate-chip/and/milk.xhr because we have no MIME type for it; a browser doesn't know how to handle it, and our Rails server (like puma or webrick) don't know how what to do with it. That's fine, and normal.

XHR requests are a client-side thing (in terms of your HTML/JS). They can be likened to how you send a POST request: you instruct the browser to do something.

What we want to do is tell the browser to send an ajax request. Thankfully, Rails makes this easy if you're using jquery_ujs (which you probably are, just check your application.js file for it)

To view our generated XHR response from the example above, put <%= link_to "What kind of cookies", "/chocolate-chip/and/milk", :remote => true %> somewhere in an existing *.html.erb file that you can view. Go ahead and click it. It should return an alert box exclaiming our love for chocolate chips and milk.

As you can see, our inline javascript is executed.

Solution

So now the question is "how can I get my chess board to be replaced with this?"

The best practice for this is to have a partial of _board.html.erb that renders the board. <div id="chess_board_wrapper"><%= render 'board' %></div> if it's in the same view path that the controller expects (per Rails conventions, and you should be following them). Note: having an ID attribute in the parent element of the rendered chess board is important here; we'll need it later.

Inside _board.html.erb, just copy-pasta your existing chess board markup.

Now, create a move.js.erb (yes, .js.erb), just like you would a new.html.erb. Inside that move.js.erb file, you can simply write $('#chess_board_wrapper').html('<%=j render "board" %>');

Then, tell your move method to respond to XHR requests,

def move
  # ...
  respond_to do |format|
    format.js # should automatically read move.js.erb 
    format.html { redirect_to update_path } 
  end
end

and the rest is history. I'm pretty sure that you can remove the success function from your ajax call as well.

Upvotes: 2

Related Questions