Right now all my actions use the redirect_back
method. Now I want to be able to request, accept, and reject without redirecting or refreshing the entire page.
Improve this experience with Ajax
- Change the default behavior of links and forms.
- When the user clicks on a link/form, keep them where they are instead of sending them to a different URL.
- Make the same GET/PATCH/POST/DELETE request as before, to the same route and with the same parameters; but it will be in the background, using JavaScript.
- In the action triggered by the request, instead of responding with a .html.erb template or redirecting, respond with a .js.erb template containing some jQuery.
- The jQuery will run in the user’s browser and update just the part of the page that needs it (sliding in the comment, updating the like count, etc).
At the bash prompt run these two commands to modify config/importmap.rb
:
% ./bin/importmap pin @rails/ujs
% ./bin/importmap pin jquery
Then in app/javascripts/application.js, I added these lines:
import "@hotwired/turbo-rails"
import "controllers"
import jquery from "jquery";
window.jQuery = jquery;
window.$ = jquery;
import Rails from "@rails/ujs"
Rails.start();
Now change anywhere in the app that was using a Turbo-type request.
Change the link from submitting an HTML request to a JS request
Make it so that when the user clicks on the delete link, it doesn’t navigate them to the URL specified by the href=""
attribute. Instead, keep them right where they are.
Attach a custom JavaScript event handler to the link that triggers the action so the appropriate CRUD occurs.
The request that is placed must be of the format .js
, rather than .html
. Then respond_to
it accordingly.
The link_to
and form_with
methods accomplish all of this.
In the calendar
<!-- views/availabilities/index.html.erb -->
<% availability.requests.pending.each do |request| %>
<div id="request_<%= request.id %>" class="request-section">
<p><%= request.sender.username %> wants to join</p>
<%= form_with(model: request, url: accept_availability_request_path(request.availability, request), method: :post, local: false) do |form| %>
<%= form.submit 'Accept', class: "btn btn-success btn-sm" %>
<% end %>
<%= form_with(model: request, url: reject_availability_request_path(request.availability, request), method: :post, local: false) do |form| %>
<%= form.submit 'Reject', class: "btn btn-danger btn-sm" %>
<% end %>
</div>
<% end %>
Use jQuery to remove the comment from the DOM. Use a unique id=""
or the helper method dom_id
to easily select with $()
:
respond_to JS
Edit the accept and reject action to handle requests for format JS:
class RequestsController < ApplicationController
before_action :set_request, only: %i[ show edit update destroy ]
def accept
@request = Request.find(params[:id])
@request.accepted!
respond_to do |format|
format.html { redirect_to availability_requests_path(@request.availability), notice: 'Request accepted.' }
format.js # This will look for a file named `accept.js.erb` in `app/views/requests/`
end
end
def reject
@request = Request.find(params[:id])
@request.rejected!
respond_to do |format|
format.html { redirect_to availability_requests_path(@request.availability), notice: 'Request rejected.' }
format.js
end
end
# ...
Create template files
// views/requests/accept.js.erb
console.log("accepted");
$("#request_<%= @request.id %>").fadeOut("slow", function() { $(this).remove(); });
// views/requests/reject.js.erb
console.log("rejected");
$("#request_<%= @request.id %>").fadeOut("slow", function() { $(this).remove(); });
Next Steps
Now that AJAX is working for accept and reject, I will add AJAX to the other buttons on the calendar.
Top comments (1)
Wow!