1

I'm in the process of migrating a legacy Rails 5.0 app to (hopefully) 7.x. I got to 5.2.x without too much trouble. I'm currently trying to upgrade to 6.0 and I have a problem with controller actions that are set up to render either js or html depending on the type of request. For example, in a standard 'new' action of the general form:

def new
  @post = Post.new
  respond_to do |format|
    format.js
    format.html
  end
end

if a jQuery ajax request is sent with dataType: 'script', the server renders the views/posts/new.html.erb template instead of views/posts/new.js.coffee. The console confirms that the request is received as a js request but that html is being rendered, e.g.

Started GET "/posts/new" for 127.0.0.1
Processing by PostsController#new as JS
  Rendering posts/new.html.erb
  Rendered posts/new.html.erb

However, if I remove new.html.erb from the view directory, then the server renders the js template as required.

Started GET "/posts/new" for 127.0.0.1
Processing by PostsController#new as JS
  Rendering posts/new.js.coffee
  Rendered posts/new.js.coffee

I'm seeing the same behavior with a number of different controllers/actions.

Any suggestions on what I'm missing? FWIW, I am not using webpacker, just regular sprockets. And ruby 2.6.6. The only thing I've changed from 5.2.x related to javascript is to add an assets/config/manifest.js file with the following:

//= link_tree ../images
//= link_tree ../javascripts .js
//= link_directory ../stylesheets .css

Edit: Also FWIW, I added a block with a test statement to the #js and #html methods -

  respond_to do |format|
    format.js {puts "calling js"}
    format.html {puts "calling html"}
  end

and confirmed that the #js method is the one that's being called, even though it is rendering the html template.

2
  • does new.js.erb work instead of .coffee? Commented Oct 17, 2023 at 14:15
  • Ah, yes! new.js.erb does work! So apparently Rails 6 does not handle coffeescript automatically. I can't see anything in the release notes for 5.0, 5.1, 5.2 or 6.0 to indicate that this was changed. What is the appropriate way to get coffeescript compiled under Rails 6? I tried downgraded sprockets from 4.2.1 to 3.7.2, the last version I had before upgrading to Rails 6, but that hasn't solved the problem. Commented Oct 18, 2023 at 5:46

2 Answers 2

0

Without going too deep, this bit here is an issue:
https://github.com/rails/rails/blob/v6.0.0/actionview/lib/action_view/path_set.rb#L48

def find(*args)
  find_all(*args).first || raise(MissingTemplate.new(self, *args))
  #              ^^^^^^
end
# where `find_all` returns
# =>
# [
#   #<ActionView::Template app/views/posts/new.html.erb locals=[]>,
#   #<ActionView::Template app/views/posts/new.js.coffee locals=[]>
# ]

html format is added along the way as a fallback for js:
https://github.com/rails/rails/blob/v6.0.0/actionview/lib/action_view/lookup_context.rb#L291-L294

if values == [:js]
  values << :html
  @html_fallback_for_js = true
end

This is definitely a rails bug. I'm not exactly sure when it was fixed but everything works fine in rails v7.


If you're planning on upgrading, try some later rails 6 versions, see if they fixed it back then. For now I can think of a couple of solutions:

respond_to do |format|
  format.js { render formats: :js } # explicitly render js format only
  format.html
end

Other than that, you could override find_all method and fix the order of templates to correspond to the order of formats - [:js, :html]:

# config/initializers/render_coffee_fix.rb

module RenderCoffeeFix
  def find_all(path, prefixes = [], *args)
    templates = super
    _, options = args

    ordered_templates = options[:formats].map do |format|
      templates.detect { |template| template.format == format }
    end.compact

    ordered_templates
  end
end

ActionView::PathSet.prepend(RenderCoffeeFix)
Sign up to request clarification or add additional context in comments.

Comments

0

You may need to explicitly set the accepts header in your JQuery ajax request. Since you have templates for both formats. I believe Rails is favoring the HTML format, so long as the request deems it acceptable.

2 Comments

Also, I believe the respond_to block in your action is no longer necessary, since you are using the default behavior of rendering a template named after the action. In other words, Rails will respect the desired response type, so long as there is a matching template available.
Thanks for the suggestion. I tried doing that but without success. The browser debugging window indicates that without specifying the accepts header explicitly, the header is text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01. When I do specify it, e.g. text/javascript, in the jQuery.ajax function using the documented syntax, the debugger confirms that that is being applied. However the response behavior is unchanged.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.