I'm a Rails junior developer and I recently tried to reproduce a dynamic search form from these two articles using Stimulus and rails-ujs: here and here.
Basically, it's about submitting a form query through Rails.fire in the stimulus controller, sending it to a dedicated rails controller, fetch the data from the DB and then send it back to the stimulus controller which intercepts the AJAX response.
Everything works fine until it's time for my partial to be displayed.
I inspected the data in the console when received by my function and I get a strange Turbolinks function instead of the content I'm expecting.
I'm using Rails 6.1 and bootstrap 5.
Any idea where my problem comes from ?
My controller
class ZaagStoriesSearchController < ApplicationController
layout false
def search
initiate_query
render @zaag_stories
end
private
def initiate_query
query = params[:query].downcase
if query.present?
@zaag_stories = ZaagStories::Search.search(query)
authorize @zaag_stories, :show?
end
end
end
My form
<%= form_with url: zaag_stories_search_path,
local: false,
method: :post,
data: {search_target: "query", action: "ajax:success->search#handleResults"} do |form| %>
<%= form.label :query, "Rechercher un titre" %>
<%= form.text_field :query, data: {action:"input->search#search"} %>
<% end %>
My view
<div class="container mt-5 wh-75 w-85" data-controller = "category-display">
<h1 class="text-center">Mon profil</h1>
<div class="d-flex justify-content-center my-2 flex-nowrap overflow-auto py-3" data-category-display-target="categories" id= "categories">
<%= render @categories %>
<button class="btn btn-secondary" data-action="click->category-display#toggleElements" data-category-display-target="button" id="category-button">
Hide
</button>
</div>
<div class="d-flex justify-content-center mb-5" data-controller= "search">
<%= render "shared/search_form" %>
<div class = "d-flex flex-column align-items-center mx-5" data-search-target= "results">
<% @categories.each do |category| %>
<h5 id="<%=category.name %>"><%= category.name %></h5>
<%= render partial:"zaag_stories/zaag_story", collection: category.zaag_stories, as: :zaag_story %>
<% end %>
</div>
</div>
</div>
My stimulus controller:
import { Controller } from "stimulus"
import Rails from "@rails/ujs"
export default class extends Controller {
static targets = ["results", "query"]
connect() {
console.log("Hello")
}
search() {
Rails.fire(this.queryTarget, "submit")
}
handleResults() {
const [data, status, xhr] = event.detail
this.resultsTarget.innerHtml = xhr.response
}
}
And the data I get in the handleResults()
function(){
function renderWithTurbolinks(htmlContent){
var currentSnapshot = Turbolinks.Snapshot.fromHTMLElement(document.documentElement);
var newSpanshot = Turbolinks.Snapshot.fromHTMLString(htmlContent);
var nullCallback = function(){};
var nullDelegate = {viewInvalidated: nullCallback, viewWillRender: nullCallback, viewRendered: nullCallback};
var renderer = new Turbolinks.SnapshotRenderer(currentSnapshot, newSpanshot, false);
if(!renderer.shouldRender()){
renderer = new Turbolinks.ErrorRenderer(htmlContent);
}
renderer.delegate = nullDelegate;
renderer.render(nullCallback);
}
Turbolinks.clearCache();
Turbolinks.dispatch('turbolinks:before-cache');
renderWithTurbolinks("<div class=\"card my-3\" ...");
window.scroll(0, 0);
Turbolinks.dispatch('turbolinks:load');
})();
For anyone having this problem, you can add
turbolinks: falseparam to your render function call: