js 请求 Rails 6.0 应用程序渲染 html 模板而不是 js

js requests to Rails 6.0 app render html template instead of js

提问人:Mark Thomson 提问时间:10/17/2023 最后编辑:Mark Thomson 更新时间:10/20/2023 访问量:85

问:

我正在将一个遗留的 Rails 5.0 应用程序迁移到(希望)7.x。我没有太多麻烦就到了 5.2.x。我目前正在尝试升级到 6.0,但我的控制器操作有问题,这些操作设置为根据请求类型呈现 js 或 html。例如,在一般形式的标准“新”操作中:

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

如果使用 发送 jQuery ajax 请求,则服务器将呈现模板而不是 。控制台确认请求是作为 js 请求接收的,但 html 正在呈现,例如dataType: 'script'views/posts/new.html.erbviews/posts/new.js.coffee

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

但是,如果我从视图目录中删除 new.html.erb,则服务器会根据需要呈现 js 模板。

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

我在许多不同的控制器/操作上看到了相同的行为。

关于我缺少什么有什么建议吗?FWIW,我没有使用 webpacker,只是普通的链轮。和 ruby 2.6.6。我从 5.2.x 与 javascript 相关的唯一更改是添加一个包含以下内容的文件:assets/config/manifest.js

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

编辑: 同样是 FWIW,我在 #js 和 #html 方法中添加了一个带有测试语句的块 -

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

并确认 #js 方法是被调用的方法,即使它正在呈现 HTML 模板。

javascript jquery ruby-on-rails-6 rails-upgrade

评论

0赞 Alex 10/17/2023
代替 .coffee 工作吗?new.js.erb
0赞 Mark Thomson 10/18/2023
啊,是的! 确实有效!所以很明显,Rails 6 不会自动处理 coffeescript。我在 5.0、5.1、5.2 或 6.0 的发行说明中看不到任何表明已更改的内容。在 Rails 6 下编译 coffeescript 的合适方法是什么?我尝试将链轮从 4.2.1 降级到 3.7.2,这是我升级到 Rails 6 之前的最后一个版本,但这并没有解决问题。new.js.erb

答:

0赞 OutlawAndy 10/17/2023 #1

您可能需要在 JQuery ajax 请求中显式设置标头。由于您有两种格式的模板。我相信 Rails 偏爱 HTML 格式,只要请求认为它是可以接受的。accepts

评论

0赞 OutlawAndy 10/17/2023
此外,我相信您的操作中的块不再是必需的,因为您正在使用渲染以该操作命名的模板的默认行为。换句话说,只要有匹配的模板可用,Rails 就会遵循所需的响应类型。respond_to
0赞 Mark Thomson 10/18/2023
谢谢你的建议。我试过这样做,但没有成功。浏览器调试窗口指示,如果不显式指定标头,则标头为 .当我使用记录的语法在函数中指定它时,调试器会确认正在应用它。但是,响应行为保持不变。acceptstext/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01text/javascriptjQuery.ajax
0赞 Alex 10/20/2023 #2

在不深入的情况下,这里有一个问题:
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在此过程中添加了格式,作为 :
https://github.com/rails/rails/blob/v6.0.0/actionview/lib/action_view/lookup_context.rb#L291-L294 的后备
js

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

这绝对是一个 rails 错误。我不确定它是什么时候修复的,但一切正常。rails v7


如果你打算升级,可以尝试一些后来的 rails 6 版本,看看他们当时是否修复了它。现在,我可以想到几个解决方案:

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

除此之外,您可以覆盖方法并修复模板的顺序以对应于格式的顺序 - :find_all[: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)

评论

0赞 Mark Thomson 10/20/2023
匪夷所思!非常感谢。