简体   繁体   English

有没有办法在 fetch 调用后呈现 js.erb ?

[英]Is there a way to render a js.erb after a fetch call?

In my Rails app, I want to render a js.erb partial after a fetch call and for some reasons I do not understand it does not work.在我的 Rails 应用程序中,我想在 fetch 调用后呈现 js.erb 部分,但由于某些原因我不明白它不起作用。 If you can help me, it would be great.如果你能帮助我,那就太好了。

In a view, an event trigger this function that basically do a fetch request:在一个视图中,一个事件触发了这个函数,它基本上是一个 fetch 请求:

function updateState(id, state){
      const csrfToken = document.querySelector('meta[name="csrf-token"]').attributes
          .content.value;
      fetch(window.location.origin + "/update_state", {
          method: "POST",
          headers: {
            'Accept': "JS",
            "Content-Type": "application/json",
            "X-CSRF-Token": csrfToken
          },
          body: JSON.stringify({'id': id, 'state': state}),
          credentials: "same-origin"
        })
}

Then in my controller:然后在我的控制器中:

  def update_state
    @model = Model.find(params[:id])
    authorize @model
    @model.update(state: params[:state])

    respond_to do |format|
      format.html { redirect_to xxx }
      format.js
    end
  end

In my js.erb files:在我的 js.erb 文件中:

console.log('hello');

However, in that case, I get an error from the server: ActionController::UnknownFormat at the line 'respond_to do |format|但是,在这种情况下,我从服务器收到一个错误: ActionController::UnknownFormat 在 'respond_to do |format| 行I have the feeling that the server do not understand the header of the fetch: 'Accept': "JS"我有一种感觉,服务器不理解 fetch 的标题:'Accept':“JS”

When I look at the logs of the server:当我查看服务器的日志时:

Started POST "/update_state" for 127.0.0.1 at 2019-04-04 11:22:49 +0200
Processing by ModelsController#update_state as JS

But I think that Rails does not recognize it.但我认为 Rails 无法识别它。 How do I do?我该怎么办?

I tried also this in the controller:我也在控制器中尝试过这个:

  def update_state
    @model = Model.find(params[:id])
    authorize @model
    @model.update(state: params[:state])
    render 'update_state.js', layout: false
  end

Which does not fire errors.这不会触发错误。 I received in the client side the js.erb.我在客户端收到了 js.erb。 However, it is not executed (console.log does not execute).但是,它不执行(console.log 不执行)。

Do you have any idea?你有什么主意吗? Thank a lot for your help.非常感谢您的帮助。

I manage the other way around.我反过来管理。 I never succeded with js.erb.我从未成功使用 js.erb。

So I use a fetch call with a response in text:因此,我使用带有文本响应的 fetch 调用:

function updateState(id, state){
  const csrfToken = document.querySelector('meta[name="csrf-token"]').attributes
      .content.value;
  fetch(window.location.origin + "/update_state", {
      method: "POST",
      headers: {
        'Accept': "JS",
        "Content-Type": "application/json",
        "X-CSRF-Token": csrfToken
      },
      body: JSON.stringify({'id': id, 'state': state}),
      credentials: "same-origin"
    }).then(response => response.text())
      .then(data => {
       div.inserAdjacentHTML('XXX', data);
    });
}

Then in the controller/action:然后在控制器/动作中:

  def update_state
    @model = Model.find(params[:id])
    authorize @model
    @model.update(state: params[:state])
    render 'update_state.js', layout: false, content_type: "text/plain"
  end

That way, it works.这样,它就起作用了。 Hope it helps.希望能帮助到你。

Edit : look at the edit for a fully working solution on triggering manually a .js.erb file.编辑:查看有关手动触发 .js.erb 文件的完整工作解决方案的编辑。

Had the same issue and there are actually two problems here.有同样的问题,实际上这里有两个问题。 Your are right, your headers are not.你是对的,你的标题不是。 These headers to trigger the .js.erb worked for me and seems pretty right :这些触发.js.erb标头对我.js.erb ,看起来很正确:

'dataType': 'json',
'contentType': 'application/json; charset=utf-8',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-Token': - your CSRF method to get the token -

But secondly to trigger the js response, your respond_to block :但其次要触发 js 响应,您的respond_to块:

respond_to do |format|
  format.html { redirect_to xxx }
  format.js
end

Has to have the format.js first.必须先有 format.js。 As rails has a response for the HTML it will respond with HTML first and seems to not even look for the next format block.由于 rails 对 HTML 有响应,它将首先以 HTML 响应,并且似乎甚至不寻找下一个格式块。

respond_to do |format|
  format.js
  format.html { redirect_to xxx }
end

Hope it helps :-)希望能帮助到你 :-)

Edit 13/11/2018编辑 13/11/2018

Hey, long time no see !嘿,好久不见! The same issue happened to me again and my own previous reply wasn't solving the issue.同样的问题再次发生在我身上,我自己之前的回复没有解决问题。 Like you, the .js.erb file was rendered but nothing happened and the console.log was not displayed.和你一样,.js.erb 文件被渲染了,但什么也没发生, console.log也没有显示。 So I created a link_to with remote: true that triggered my .js.erb file and compared the requests.所以我创建了一个带有remote: truelink_to触发了我的.js.erb文件并比较了请求。 Everything was the same except one thing : the type of the request.除了一件事之外,一切都相同:请求的类型。 One was a fetch, the other was an xhr .一个是 fetch ,另一个是xhr It appears that the .js.erb files are triggered only by the xhr requests.似乎.js.erb文件仅由xhr请求触发。 So the solution is to build an old xhr request instead of a fetch, like this :因此,解决方案是构建一个旧的xhr请求而不是 fetch,如下所示:

    const url = 'your_custom_path' // Build the url to fetch
    const csrf = document.querySelector('meta[name="csrf-token"]').getAttribute('content')

    let xhr = new XMLHttpRequest();

    // Will be a GET request here
    xhr.open('GET', url, false);
​    
    // Setting the headers
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.setRequestHeader('X-CSRF-Token', csrf);
    xhr.setRequestHeader('dataType', 'script');
​
    // What to do with the response
    xhr.onload = function() {
      let responseObj = xhr.response
      eval(responseObj) // You need to eval() manually the response for it to be executed
    }
​
    // Sending the request
    xhr.send()

Hope it helps, even some months later!希望它有所帮助,即使是几个月后! ;) ;)

I ran into this issue in Rails 6 using fetch.我在 Rails 6 中使用 fetch 遇到了这个问题。 My issue was solved by simply placing format.js above format.html.我的问题是通过简单地将 format.js 放在 format.html 之上来解决的。 Thanks @holino.谢谢@holino。 The following fetch works.以下提取有效。

  fetch(event.currentTarget.dataset.destroyPath, {
    method: 'DELETE',
    dataType: 'script',
    credentials: 'include',
    headers: {
      'X-CSRF-Token': csrf
    },
  })

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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