Rails DELETE route not working properly / not calling the controller function - ruby-on-rails

I am using React and Rails API. To make a request from React I am using Axios library and the code looks like this:
const _deleteIssue = () => {
axios.delete(`${ROOT_API}/v1/issue/delete/${props.issue.id}`, {
headers: {
'Authorization': `Bearer ${authToken}`
}
}).then(res => {
props.updateProjectData()
}).catch(err => {
console.log(err)
})
}
In order to handle this request I have set up a route for it which looks like this:
Rails.application.routes.draw do
concern :base_api do
# other routes
post 'issues/create', to: 'issues#create'
delete 'issue/delete/:issue_id', to: 'issues#delete_issue'
end
namespace :v1 do
concerns :base_api
end
end
As you can see from the code snippet above, the route is set to call delete_issue function inside of the issues controller. I have created that function and it looks like this:
class V1::IssuesController < ApplicationController
# other functions
def delete_issue
Issue.find_by(id: params[:issue_id]).delete
render json: {}, status: 200
end
end
I am justing trying to find the issue with an id that is passed as params from Axios delete request.
It is supposed to delete it and return nothing with a status code of 200. What happens instead is that in my "Network" tab inside of developer tools in my browser(Firefox) shows the 200 OK request with the OPTIONS method. There is no DELETE method being sent or anything.
I even tried to comment out the delete_issue function from IssuesController and there was not 404 routing error. The result was the same. I can't find out what is wrong with it even though it is probably a pretty obvious error which I can't see.
Note that I am using Rails 6.

It seems you did not configure rack-cors. Simply add this to your cors.rb file:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'localhost:3001' # or you react app domain
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end

Related

Omniauth Steam with Rails 7

I am creating a new application with rails 7. I would like to add a way for the user to signup via steam. I used the code which works on rails 6, but on rails 7 I receive an error.
Access to fetch at 'https://steamcommunity.com/openid/login?openid.ax.theKeyIamHidingforStackOverflow'
(redirected from 'http://localhost:3000/auth/Steam')
from origin 'http://localhost:3000' has been blocked by
CORS policy: Response to preflight request doesn't pass access control
check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the
request's mode to 'no-cors' to fetch the resource with CORS disabled.
Clicking on the https://steamcommunity.com/openid/login?fooBar I get to stream and also redirected to my app and I am signed in.
I tried to set cors in config/initializers/cors.rb like:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'https://steamcommunity.com'
resource '*', headers: :any, methods: [:get, :post]
end
end
But this does not work. Do I need to allow the visit of third party websites before I try to redirect to them?
Did something change on rails 7 to protect redirect?
This is the post to the server
= form_tag '/auth/Steam', method: :post do
= submit_tag 'Steam'
Best Regards
Dennis
The answer to this, we need to disable turbo on making an Ajax request by using the form like this:
= form_tag '/auth/steam', method: :post, data: { turbo: false } do
= submit_tag 'Steam'
This Form contains data: { turbo: false } which disables turbo

Angular $http and Rails 4 params

I'm using the rails-api gem to have just a Rails API and using Angular to power my frontend. Whenever I use $http, it will only work if I pass in params instead of data. Here's an example with trying to log in a user and create a new session:
'use strict';
app.controller('LoginCtrl', function($scope, $location, $http, tokenHandler) {
$scope.login = function() {
$http({
url: 'http://localhost:3000/api/admins/sign_in',
method: 'POST',
params: $scope.admin
}).success(function(data) {
if (data.success) {
$scope.ngModel = data.data.data;
tokenHandler.set(data.data.auth_token);
$location.path('/admin/blog');
} else {
$scope.ngModel = data;
$scope.user.errors = data.info;
}
}).error(function(msg) {
$scope.admin.errors = 'Something is wrong. Please try again.';
});
};
});
If instead of params I used data: { admin: $scope.admin }, Rails complains to me that params[:admin] is nil. It seems to not be coming through at all.
However, if I use params, I get this:
Started POST "/api/admins/sign_in?email=raderj89#gmail.com&password=[FILTERED]" for 127.0.0.1 at 2014-09-07 20:08:04 -0400
Processing by Admin::SessionsController#create as HTML
Parameters: {"email"=>"raderj89#gmail.com", "password"=>"[FILTERED]"}
Which I can work with. It's just weird that it seems to only work when the request is processed as HTML. When I use data, I get this:
Started OPTIONS "/api/admins/sign_in" for 127.0.0.1 at 2014-09-07 20:36:24 -0400
Processing by Admin::SessionsController#create as */*
Is it suppose to say processing by */*? I'd think it should understand it's supposed to process by json specifically.
My sessions controller looks like this:
class Admin::SessionsController < Devise::SessionsController
skip_before_filter :verify_authenticity_token
before_filter :authenticate_user!, except: [:create]
respond_to :json
# ...
end
The weird thing is I definitely got it working the first time just using data: { admin: $scope.admin }, but ever since, the params seem to never come through unless I use params: $scope.admin.
ALSO:
I'm using Devise for authentication, and I had to add this to my ApplicationController:
class ApplicationController < ActionController::API
include ActionController::MimeResponds
before_filter :set_cors_headers
before_filter :cors_preflight
private
def set_cors_headers
headers['Access-Control-Allow-Origin'] = AppConfig.client['origin']
headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS'
headers['Access-Control-Allow-Headers'] = '*'
headers['Access-Control-Max-Age'] = "3628800"
end
def cors_preflight
head(:ok) if request.method == :options
end
end
Anyone ever dealt with this before?
I've finally got it working and while I'm still confused, I think I've got somewhere close to what the problem was: My CORS configuration in my Rails API.
From what I've learned, Angular sends data in JSON format by default. This goes through as "Content-Type:application/json;charset=UTF-8", whereas in jQuery AJAX requests, it goes through as "Content-Type:application/x-www-form-urlencoded; charset=UTF-8", and is converted to a query string using $.param(). I'll admit, I've probably heard this before, but haven't truly registered this fact and its effects until now.
In my application controller, I configured my CORS settings like so:
def set_cors_headers
headers['Access-Control-Allow-Origin'] = AppConfig.client['origin']
headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS'
headers['Access-Control-Allow-Headers'] = '*'
headers['Access-Control-Max-Age'] = "3628800"
end
def cors_preflight
head(:ok) if request.method == :options
end
AppConfig is just an OpenStruct that tells my Rails API what origin to accept requests from. And then everything else was supposed to simply set the CORS headers.
For some reason of which I'm still not sure, this wasn't working for JSON requests. I got the above code from a tutorial using Angular and Rails, and in the case of the tutorial, they manually stripped out the asset pipeline, leaving everything else about Rails in, whereas rails-api strips out some Rails configuration. This may be why setting the CORS headers in ApplicationController wasn't working.
What did work was to use the rack-cors gem and then add this bit to development.rb:
config.middleware.use Rack::Cors do
allow do
origins 'localhost:9000'
resource '*', :headers => :any, :methods => [:get, :post, :options, :delete]
end
end
This tells my app to accept requests from localhost:9000, and to accept any headers. I thought I was accomplishing that with headers['Access-Control-Allow-Headers'] = '*' in my ApplicationController, but I guess not. Once I specified Rails to use those middleware settings, everything worked perfectly. My Rails API can now accept application/json from my Angular app.
If someone could fill in the gaps where I'm still confused, I'd appreciate it. But I hope this helps others.
You can send either :params or :data (or both, I guess). According to the angularjs docs at https://docs.angularjs.org/api/ng/service/$http
params – {Object.} – Map of strings or objects which
will be turned to ?key1=value1&key2=value2 after the url. If the value
is not a string, it will be JSONified.
data – {string|Object} – Data to be sent as the request message data.
The controller is expecting http-type parameters/form data, so passing the object via params works - it gets converted, whilst passing the same via :data doesn't because it doesn't get converted.
I don't know if there is a smart way to unpack the data format at the Rails Controller end, but you can convert the object within your $http request into serialized parameters using $.param(data)http://api.jquery.com/jQuery.param/
data: $.param($scope.your_data_object) e.g. $scope.admin
and then unpack params[:data] at the controller.

How can I rewrite a subdomain to another subdomain?

I have this simple rack middleware written to rewrite my subdomain :
def call(env)
request = Rack::Request.new(env)
if request.host.starts_with?("something-something")
[301, { "Location" => request.url.gsub('something-something','site-i-want') }, self]
else
#app.call(env)
end
And this works fine on development. But in production I get an error calling .each for TheNameOfMyRackMiddleware
Is there something that looks strangely syntactically incorrect about how I'm writing this?
I want this someting-something.mywebsite.com to go to site-i-want.mywebsite.com
I also tried it directly with my routes with this :
constraints :subdomain => 'something-something' do
redirect { |p, req| req.url.sub('something-something', 'site-i-want') }
end
Which works fine on development. But doesn't route before I get my failure saying that the site does not exist.
Entirely open to anyway of getting this accomplished.
How about trying this in your routes:
constraints subdomain: 'something-something' do
get ':any', to: redirect(subdomain: 'site-i-want', path: '/%{any}'), any: /.*/
end
It basically catches any request to the 'something-something' domain, and rewrites it with the existing path, but new subdomain.

Following a Typhoeus post in Rails/Sinatra

I have a scenario where I'm doing a post in Sinatra via Typhoeus in app.rb. It looks like this:
post "/send-data" do
...
request = Typhoeus::Request.new("http://localhost:4000/renders",
:method => :post,
:headers => { :Accept => "text/html" },
:followlocation => true,
:timeout => 100, # milliseconds
:params => params )
# Run the request via Hydra.
hydra = Typhoeus::Hydra.new
hydra.queue(request)
hydra.run
...
end
When I post to 'send-data' Typhoeus successfully does it's post and pushes the user to the view of the created record (http://localhost:4000/renders/34634646464), which is a rails app.
The problem is that the user is never redirected away from /send-data, so if you refresh the page it tries to do the post again. I guess this makes sense, but I really need the user to be redirected to the final (url) location of the record. In other words, the new record can be seen, but this method of redirecting does not actually move the user off of the sinatra app.
What would be the best way to handle this? The only one I can think of off the top of my head is to not use 'followlocation', but rather have the /send-data controller action do the redirect after getting the response location fron Typhoeus.
I tried my suggestion and it works... and does not look too bad.
request = Typhoeus::Request.new("http://localhost:4000/renders.json",
:method => :post,
:headers => { :Accept => "json" },
:timeout => 100, # milliseconds
:params => params )
hydra = Typhoeus::Hydra.new
hydra.queue(request)
hydra.run
response = request.response
redirect response.headers_hash['Location']
I did have to make a change on my rails server. The rails create action responds with json and 'Location' is it's return value. 'Location'is the location of where the newly created record resides. Then I just do a Sinatra redirect which will redirect to the new record on the rails app.

Routing in Ajax petition in Rails 2

I have the following in my view:
$('#anID tr').click(function () {
$.ajax({
type: 'GET',
url: '/tickets/extended_info',
dataType: 'script',
data: { id: $(this).find('td:first').html() }
});
});
and this in my tickets controller:
def extended_info(id)
puts ">>>>>>>>>>>>>>> " + id.to_s
end
But I always get 404 not found from the ajax request.
I think I'm missing something in my routes file... I tried several things, but nothing.
Any ideas?
>>>>>>>>>>>>>>>>>>>>> RESOLVED <<<<<<<<<<<<<<<<<<<<<<<<<
I had to add:
map.extendedInfo '/extended_info/:id', :controller => 'tickets', :action => 'extended_info'
to my routes file.
Also, I was using "GET" in my ajax call in my JavaScript ... I changed to POST and now it's working =)
Really seems like routing trouble. Do you have appropriate row for /tickets/extended_info path in your routes.rb? If so, can you post it here?
I suppose something like this
get "/ticket/extended_info", :to => "tickets_controller#extended_info"
in routes.rb and your action on controller should be just
def extended_info
puts params[:id].inspect
end

Resources