简体   繁体   中英

How to respond to a fetch(post) with js.erb?

I am trying to make a post request that'll grab all events(Jams) and update dynamically the page via ajax. So my controller recieves params in JSON format and I'd like to respond with js just like how you would do with remote: true on a link or button.

I am using rails 6.0.2.2

This is in my.js file =>

const getJams = () => {
  const mapCenter = map.getCenter();
  const mapBounds = map.getBounds();
  const token = document.getElementsByName("csrf-token")[0].content
  fetch(window.location.origin + "/search", {
    method: "POST",
    headers: {
      'Accept': "text/javascript",
      'Content-Type': "application/javascript",
      'X-CSRF-Token': token
    },
    body: JSON.stringify({
      map_center: mapCenter,
      max_lat: mapBounds._ne.lat,
      min_lat: mapBounds._sw.lat,
      max_lng: mapBounds._ne.lng,
      min_lng: mapBounds._sw.lng
    }),
    credentials: "same-origin"
  })
}

The method in the search controller where the data is sent is like this =>

def index
    @jams = policy_scope(Jam)

    respond_to do |f|
      f.json do |f|
        render json: {
          jams: render_to_string(
            partial: 'jams/jams',
            formats: :html,
            layout: false,
            locals: { jams: @jams }
          )
        }
      end
    end
  end

Executed like this, inside my byebug the params are present, so that seems correct. If I continue my server shows me this

Completed 406 Not Acceptable in 1ms (ActiveRecord: 0.0ms | Allocations: 889)



ActionController::UnknownFormat (ActionController::UnknownFormat):

app/controllers/searchs_controller.rb:7:in `index'

I'd like to work inside that search.js.erb file to append the elements inside my view. Though, my search.js.erb contains simply console.log("a"); but that js seems not to be executed. Nothing appears in the console.

If anyone could help me I'd be grateful.

Here is the inside of the jams/_jam.html.erb partial =>

<% jams.each do |jam| %>
<div class="jam-card">
  <%= image_tag jam.photo %>
  <%= jam.status %>
  <%= jam.user.first_name %>
  <%= jam.music_style.music_style %>
  <%= display_date(jam.start_date_time, jam.duration) %>
  <%= jam.participants.count %>/<%= jam.max_participants %>
</div>
<% end %>

Hint. You don't need js.erb templates.

  • They make an absolute mess of the flow. When you reach for a js.erb template you're now context switching between Ruby and JavaScript and server side and client side on every line. This mental gymnasics does not promote good quality code.
  • js.erb templates are not served by the assets pipe/webpacker and are thus not minified or served by a CDN.
  • You know that nice restful server side app you carefully crafted? Kiss it goodbye because its now responsible for client side transformations and full of wiggle the woggle routes and spagetti code javascript views.

Either respond to the request with an array of JSON objects and let the client side handle templating or pass a HTML string back in the JSON response and let your real ajax handler actually do its job:

def index
  @jams = policy_scope(Jam)
  respond_to do |f|
    f.json do 
      render json: { 
        jams: render_to_string(
          partial: 'jams/jams', 
          formats: :html, 
          layout: false, 
          locals: { jams: @jams}
        )
     }
    end
  end
end

.then(function(response) {
  document.getElementById("some_element").innerHTML = response;
})

There are also approaches where people have used request.xhr to send back chunks of HTML in response to a HTML ajax request or used custom content types. All of them are better then js.erb .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM