I'm trying to wire up this AJAX POST request in my react component to communicate with my rails api controller. The console logs a 404 error and I can't seem to hit the pry.
react/src/pages/HomeIndex.js
getCompare() {
$.ajax({
url: '/api/sources/compare',
type: 'POST',
data: {value: this.state.inputValue, from: this.state.compareFrom, to: this.state.compareTo },
contentType: 'application/json'
})
}
controllers/api/sources_controller.rb
def compare
binding.pry
end
config/routes
post '/api/sources/compare', to: 'api/sources#compare'
namespace :api do
resources :sources, only: [:index, :compare]
end
rake routes
api_sources_compare POST /api/sources/compare(.:format) api/sources#compare
update
I tried updating the routes with several permutations...
namespace :api do
resources :sources, only: [:index] do
collection do
post :compare
end
end
end
namespace :api do
resources :sources, only: [:index, :compare] do
collection do
post :compare
end
end
end
namespace :api do
resources :sources, only: [:index] do
collection do
resources :compare, only: [:compare]
end
end
end
namespace :api do
resources :sources do
post :compare
end
end
...all with the same outcome.
You can solve this by stringifying your AJAX payload, as follows:
getCompare() {
let data = JSON.stringify({value: this.state.inputValue, from: this.state.compareFrom, to: this.state.compareTo })
$.ajax({
url: '/api/sources/compare',
type: 'POST',
data: data,
contentType: 'application/json'
})
}
Related
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.
Edit : look at the edit for a fully working solution on triggering manually a .js.erb file.
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 :
'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 :
respond_to do |format|
format.html { redirect_to xxx }
format.js
end
Has to have the format.js first. 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.
respond_to do |format|
format.js
format.html { redirect_to xxx }
end
Hope it helps :-)
Edit 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. So I created a link_to with remote: true that triggered my .js.erb file and compared the requests. Everything was the same except one thing : the type of the request. One was a fetch, the other was an xhr. It appears that the .js.erb files are triggered only by the xhr requests. So the solution is to build an old xhr request instead of a fetch, like this :
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. My issue was solved by simply placing format.js above format.html. Thanks #holino. The following fetch works.
fetch(event.currentTarget.dataset.destroyPath, {
method: 'DELETE',
dataType: 'script',
credentials: 'include',
headers: {
'X-CSRF-Token': csrf
},
})
I have an ajax post to my backend rails app, it's to post a upload a file.
Post response with my files list in JSON
After that I need to reload my files list at view detalhes.html.erb page. This list is a partial. Here is what I have:
controller method:
def upload_arquivo
#ponto_venda = PontoVenda.find(params[:pv_id])
nome = params[:key].split('/').last
#arquivo = Arquivo.new(nome: nome, endereco: params[:url], s3_key: params[:key], tamanho: params[:tam], user_id: params[:u_id], tag_id: params[:tag])
if #arquivo.save!
ArquivoPontoVenda.create(arquivo_id: #arquivo.id, ponto_venda_id: #ponto_venda.id, fachada: false)
response = { files: filtro_pv_arquivos, message: "O arquivo '#{nome}' foi salvo" }
else
response = { files: '', message: 'Ocorreu um erro ao salvar o arquivo, por favor, tente novamente' }
end
render json: response
end
My ajax post method at _arquivos_upload.html.erb:
$.ajax({
url: 'some_url,
type: 'post', processData: false
})
.success(function(data) {
console.log(data.files.length);
// trying to reload partial after post request
$('#display-arquivos').html("<%= escape_javascript(render "arquivos_buscados") %>");
});
data.files are correct, I just need to find a way to pass this to my render partial. How can I do that? Or if this is a bad way to do it, how can I do better?
Here is where I render my partial detalhes.html.erb:
<div class="card" id="display-arquivos">
<%= render "arquivos_buscados" %>
</div>
I already have try a lot of this:
github link
set .html(data.files)
use js.erb file logic
That looks good. I'd suggest modifying your partial to accept a local variable and then explicitly passing it in when you render the partial.
<div class="card" id="display-arquivos">
<%= render "arquivos_buscados", locals { files: #files #add this } %>
</div>
$('#display-arquivos').html("<%= escape_javascript(render "arquivos_buscados", locals: { files : data.files } ) %>");
I think I would render back html instead of json. Then, in .success function of the ajax call, just do:
$.ajax({
url: 'some_url,
type: 'post', processData: false
})
.success(function(data) {
$('#display-arquivos').html(data);
});
You'll probably need to change your controller action along the lines of:
def upload_arquivo
...
if #arquivo.save!
ArquivoPontoVenda.create(arquivo_id: #arquivo.id, ponto_venda_id: #ponto_venda.id, fachada: false)
#files = #populate your #files variable
render "arquivos_buscados"
else
render :something_else
end
end
i am encoding a chromium extension that connects to a ruby server in order to save or send a reminder notification when the time comes, the connection works and it is possible for the user to create a reminder (on our ruby server) since the extension. my problem is during the sign_in that I would like to be able to do since the extension in order to recover authanticity_token, when I send the request to the server I have an error in javascript console type:
XHR failed loading: OPTIONS "http://localhost:3000/users/sign_in".
send # jquery.js:4
ajax # jquery.js:4
ajaxLogin # log_in.js:26
(anonymous) # log_in.js:13
dispatch # jquery.js:3
r.handle # jquery.js:3
11:39:05.127 Navigated to file:///home/eth3r/Bureau/WaltTest/walt-e/log_in.html
and in ruby's console :
Started OPTIONS "/users/sign_in" for 127.0.0.1 at 2017-09-01 11:49:27 +0200
ActiveRecord::SchemaMigration Load (0.5ms) SELECT "schema_migrations".* FROM "schema_migrations"
ActionController::RoutingError (No route matches [OPTIONS] "/users/sign_in"):
routes.rb
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'sessions',
registrations: 'registrations'
}
resources :reminders, only: [:new, :create, :edit, :destroy, :index, :update]
root to: 'pages#home'
namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :reminders, only: [:new, :create, :edit, :destroy, :index, :update]
end
end
end
my ajax function :
function ajaxLogin(email, password) {
var data = {
"user": {
"email": email,
"password": password,
}
};
$.ajax({
type: "POST",
url: apiBaseUrl + "/users/sign_in",
headers: ajaxHeaders,
data: data,
dataType: "json",
contentType : "application/json",
success: function(data) {
console.log(data);
},
error: function(jqXHR, status, text) {
console.log(status);
console.log(text);
console.error(jqXHR.responseText);
}
});
};
I've been on the same problem for two days now, javascript is horrible!
following were my javascript where user post the updates:
$('.attachments-container').on('click', '.cover-attachment', function(event) {
var attachment_id = $(this).parent().find('input[name="product_attachment[id][]"]').val();
$.ajax({
type: "POST",
url: "/products/update_cover",
dataType: "json",
data: attachment_id,
complete: function(){
console.log('change completed');
}
});
event.preventDefault();
})
On my routes:
resources :products do
member do
match "update_cover", via: [:post]
post "update_cover" => 'products#update_cover'
end
end
On my controller:
class ProductsController < ApplicationController
skip_before_action :authenticate_user!, only: [:result, :show]
def update_cover
#attachment_id = params[:attachment_id]
render :json => {:status => 'success'}.to_json
end
end
I had no clue where this error comes from: ActionController::RoutingError (No route matches [POST] "/products/update_cover"): Thanks!!
If you run rake routes in your terminal you will see that you do not have a route for products/update_cover. You have - products/:id/update_cover. Since you have defined it as a member route, you need to pass the parent_id as part of the route. Try this
url: "/products/" + attachment_id + "update_cover",
And you dont need to pass attachment_id in the data hash.
Incidentally, the 2 routes you posted essentially do the same thing. You can lose
match "update_cover", via: [:post]
I'm building an app, using Rails and Backbone as my back-end, that requires users to login to access certain pages. On one of the user authenticated pages, I have it setup so they can create an entry in my database, by entering in data, which is then sent to the Google Maps API to retrieve the latitude and longitude.
Via a helper function, I'm checking if the user is authenticated or not, but when I send up the AJAX call to Google Maps API, the user token is also being sent up. Here's the code that I have set up right now.
In my api js file, which is ran first on load for my page
var token = $('#api-token').val();
$.ajaxSetup({
headers:{
"accept": "application/json",
"token": token
}
});
In my users_controller.rb
def profile
authorize!
#user = current_user
#bathrooms = Bathroom.all.sort_by { |name| name }
render layout: 'profile_layout'
end
def authorize!
redirect_to '/login' unless current_user
end
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
Here's my AJAX call
function getInfo(location) {
console.log('getInfo');
$.ajax({
method: 'get',
url: 'https://maps.googleapis.com/maps/api/geocode/json',
data:{address: location, key: 'API KEY GOES HERE'},
success: function(data) {
extractData(data);
}
})
}
You can try following steps:
function getInfo(location) {
console.log('getInfo');
delete $.ajaxSettings.headers["token"]; // Remove header before call
$.ajax({
method: 'get',
url: 'https://maps.googleapis.com/maps/api/geocode/json',
data:{address: location, key: 'API KEY GOES HERE'},
success: function(data) {
extractData(data);
}
});
$.ajaxSettings.headers["token"] = token; // Add it back immediately
}