Rails Respond_To Format.Js API

rails respond_to format.js API

respond_to do |format|
format.js # actually means: if the client ask for js -> return file.js
end

js here specifies a mime-type that the controller method would send back as a response;

Default Rails mime-types.

If you try also with format.yaml:

respond_to do |format|
format.js
format.yaml
end

that will mean that your controller will return yml or js depending on what the client-side is asking;

{} in terms of ruby is a block;
If you don't specify any rails will try to render a default file from app/views/[contoller name]/[controller method name].[html/js/...]

# app/controllers/some_controller.rb
def hello
respond_to do |format|
format.js
end
end

will look for /app/views/some/hello.js.erb; // at least in Rails v. 2.3.

If you do specify block:

respond_to do |format|
# that will mean to send a javascript code to client-side;
format.js { render
# raw javascript to be executed on client-side
"alert('Hello Rails');",
# send HTTP response code on header
:status => 404, # page not found
# load /app/views/your-controller/different_action.js.erb
:action => "different_action",
# send json file with @line_item variable as json
:json => @line_item,
:file => filename,
:text => "OK",
# the :location option to set the HTTP Location header
:location => path_to_controller_method_url(argument)
}

end

respond_to do |format| format.js not working in rails 6.1.3

I think you are missing remote: true

= form_for @contact , url: contacts_path, remote: true do |f|

From the documentation:

:remote - if set to true, will allow Unobtrusive Javascript drivers to
control the submit behavior

This is what adds the js header to the request and allows the rails controller to respond with the js format.

format.js and format.json in same respond_to

Rails determines the format to take, by reading the Accept header of the http request:

Example:

  def test
f.js {
render js: "Hello World"
}
f.json {
render json: { foo: :bar }
}
end
curl localhost:3000/test -H 'Accept: application/json'
{"foo":"bar"}%

curl localhost:3000/test -H 'Accept: application/javascript'
Hello World%

Try changing the header accept in your XHR call, e.g. when using fetch:

fetch(url, { 
headers: { 'Accept': 'application/json' },
})

Similar in jquery's.ajax or raw XHtmlRequest.

Update Rails Content negotiation:

Rails has a heuristic for determine the format. Check the Doc: https://api.rubyonrails.org/classes/ActionDispatch/Http/MimeNegotiation.html#method-i-formats

formats.first will be taken as the "format" for the request, and the order is like this. First rule will "win":

  1. a parameter called "format", e.g. ?format=json
  2. Accept header
  3. path suffix, e.g. /foo/bar.json
  4. When XHR -> Always js
  5. otherwise HTML

Rails, respond_to do |format| returns ActionController::UnknownFormat

The most likely explanation is that the request is not requesting JS. In order for rails to treat the request as JS the path needs to end with .js or have the correct Accept or Content-Type headers. Not that the mime type is not registered with rails as it registers the most common mime-types for javascript.

  1. Check the rails log to confirm: tail -f logs/development.log
  2. Check the browser console for errors.
  3. Check that form that is has the data-remote="true" attribute.

<%= form_for(@thing, remote: true) %>

How to respond_to js.erb?

I found an answer to my question here.

I solved the issue with a line of code in my controller respond format.js by adding this line: {render layout: false}

Another solution might be adding data: {type: "script"} to your form_for, but in my case it didn't work.

The working controller looks like this:

def create
@feedback = Feedback.new(feedback_params)
respond_to do |format|
@feedback.save
format.html {}
format.js {render layout: false}
end
end

Thanks everyone for being involved.

using respond_to do |format| format.js to show a message inside of a modal after photo is favorited inside a modal?

To utilize the JavaScript response, you will need to add the remote: true option to your link.

http://guides.rubyonrails.org/working_with_javascript_in_rails.html

If you want to handle this via AJAX, don't use redirect back.

Also use flash.now for AJAX.

Instead handle both scenarios in you're JavaScript file.

# app/views/photos/favorite.js.erb     
<% if flash.now[:notice] %>
$('.modal-dialog.photo>.message').html("<%= j flash.now[:notice] %>")
<% else %>
$('.modal-dialog.photo>.message').html("<%= j flash.now[:alert] %>")
<% end %>

# app/views/photo/unfavorite.js.erb
<% if flash.now[:notice] %>
$('.modal-dialog.photo>.message').html("<%= j flash.now[:notice] %>")
<% end %>

It kind of goes that notice is like success and alert are error.

And change your controller to this:

def favorite
@photo = Photo.find params[:id]
favorite_photo = current_user.favorites.build(photo: @photo)

if favorite_photo.save
flash.now[:notice] = 'You successfully favorited this photo'
else
flash.now[:alert] = favorite_photo.errors.full_messages
end
respond_to :js
end

def unfavorite
@photo = Photo.find params[:id]
current_user.favorites.delete(@photo)
flash.now[:notice] = 'You successfully unfavorited this photo'
respond_to :js
end

And your routes to match this configuration.

I'd POST to favorite and DELETE to unfavorite due to the DB implications of each.

Currently you can only pass notice and alert to a render or redirect_to. But you can defined your own flash types. But don't constrain yourself by using only these two.

if success
flash[:success] = "Something good"
else
flash[:error] = "Something bad"
end

Why is respond_to executing format.html instead of format.json when using AJAX?

The way I understand respond_to bock is that when you make an AJAX
request it should answer back by using json, and If you make a regular
request it should answer back by using html. Is that correct?

Not quite. An AJAX request is just an asynchronous request and the response type should depend on the Content-Type and Accept-Type headers. An AJAX request request can actually request any possible content type - JSON is just the most commonly used and arguably the most useful type.

If the request does not contain a specific content type or accept type Rails will default to html unless you override it in the routes:

namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :things
end
end

Rails UJS which is built into rails and powers the remote: true option on forms and links actually uses application/javascript as the default content-type as it lets you write js.erb views and reuse rails templating without writing ajax handlers. If this is really a good idea though is debatable as it leads to some very questionable design decisions.

With Rails UJS the easiest way to set the content type is through the data-type attribute:

<%= link_to "Click Me!", "/foo", remote: true, data: { type: :json } %>
<%= form_with(model, html: { data: { type: "json" }}) %>

If you are sending an Ajax request "manually" with XMLHttpRequest you can set the content type with setRequestHeader.

xhr.setRequestHeader("Content-Type", "application/json"); 

With jQuery you use the type: option for the ajax funtions or jQuery.getJSON.

Also the correct way to respond is to a successful POST request is with 201 Created.

201 Created. The request has been fulfilled and has resulted in one or
more new resources being created. The primary resource created by the
request is identified by either a Location header field in the
response or, if no Location field is received, by the effective
request URI.

format.json { head :created, location: @role }

You can also optionally include the created resource in the response body.

format.json { render json: @role, location: @role, status: :created }

Rails 3.1: The new way to use 'respond_to ... format.js' without the 'page' variable

I'd go with:

render js: %(window.location.href='#{article_path @article}')

Or put something along the lines of this in your application_controller.rb:

def js_redirect_to(path)
render js: %(window.location.href='#{path}') and return
end

Then in your controllers you can just call:

js_redirect_to(article_path @article)

Note I just made this up - not tested :)



Related Topics



Leave a reply



Submit