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. If you can help me, it would be great.
In a view, an event trigger this function that basically do a fetch request:
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:
console.log('hello');
However, in that case, I get an error from the server: ActionController::UnknownFormat at the line 'respond_to do |format| I have the feeling that the server do not understand the header of the 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. 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. However, it is not executed (console.log does not execute).
Do you have any idea? Thank a lot for your help.
I manage the other way around. I never succeded with js.erb.
So I use a fetch call with a response in text:
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.