#CORS 🇬🇧
Send JSON using RACK-CORS gem and use it in a JS Frontend
Nikolaz Stacey
Nikolaz Stacey
6 min read
A bit like an API to your rails monolith app that can be used by another seperate app. In this case we will look at using it for a simple js front end. But it could be React, Angular or which ever. I used a React app with a useContext and useReducer hook. Worked perfectly!
As an aspiring developer, I have been working on a number of projects in my spare time. And I decided to develop websites for people for free. Well, one of these projects has become an enormous learning oppertunity…
Mainly because I didn’t know how to do the things I needed to, so I learnt them. This app is a classic React app that displays photos and information for a freelance artist/decorator I know. Previously, I set up the app to use a headless CMS and I managed all of the content for the artist. Until, one day, the artist wanted to be able to manage everything, but not through the headless CMS, because it wasn’t a solution they were willing to use anymore. They wished to manage the content through an admin site for the React app.
So, I decided to make another app that would be like an admin app and communicate JSON to the React app and so replacing the headless CMS. As a side note, I just recently completed the Le Wagon course and am now making web developpement my trade. So Rails seemed perfect for this. (Le Wagon uses Rails — it’s awesome!).
We will go through the steps needed to expose JSON mainly from the rails side, and then explain how you can retrieve the data from any JS front end. This assumes that you have some prior rails knowledge and that you already have an app in a repo (rails new new-app) with at least one model and one controller. If you are totally new to Rails, I recommend starting with the Odin Project and Le Wagon. As a side note, Le Wagon really is an amazing course, I can’t recommend it enough.
If you need a hand with setting up Rails, here is a good link to get a rails app all set up. With this article, I’m mainly thinking of people trying make a classic Rails monolith, exposing the JSON. There are plenty of other ressources for setting up a 100% Rails API backend, if that’s what you are trying to do.
Once you have an app running, what we are essentially trying to do is send some data stored in the database as json to whoever requested it. It’s important to understand that you can configure the end point to be accessible to everyone in the world, or only to certain users. If you try to access the endpoint and you haven’t declared the appropriate authorisations, you will get a CORS error on the client side. To fix this, you declare which URLs can make the requests to your app. What we are doing is the more restricted version where we will declare who can access the json. Either way, we need the rack-cors gem.
1- in the gemfile, add
gem 'rack-cors'
2-
bundle install
3- in the config/initializers a new cors.rb file should be there.
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'https://bikes4life.com'
resource '/my_json_function', headers: :any, methods: [:get]
end
end
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'https://bikes4life.com'
resource '/my_json_function', headers: :any, methods: [:get]
end
end
Here you are declaring that you are going to only accept get requests to the /my_json_function from bikes4life.com
When you are developing, you might be developing your rails on localhost:3000 and have another server running locally for your front end, so be sure to use * to allow anyone to access the my_json_function including localhost:3001 (you are probably running your rails app on port 3000 and your js app on 3001), in development, it is ok to do this like so:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: [:get]
end
end
When you are developing, you might be developing your rails on localhost:3000 and have another server running locally for your front end, so be sure to use * to allow anyone to access the my_json_function including localhost:3001 (you are probably running your rails app on port 3000 and your js app on 3001), in development, it is ok to do this like so:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: [:get]
end
end
You can make other declarations and add more methods, like update, post etc…
Restart your rails server after this.
It’s important to remember that when you push to production, you will have to change these URLs to point to the URLs you want to accept in requests from. Again, if you want to allow everyone access, use * .
4- Then you should declare a route in your config/routes:
Rails.application.routes.draw do
[...]
get 'my_json_function', to: 'my_controller#my_json_function'
[...]
end
5- Now its time to write the actual function that will do the hard work!
In your chosen controller, (in my case its a VehiclesController) we will send all the data from the bikes table in my DB. (this assumes that you have a Bike model).
def my_json_function
@bikes= Bike.all
render json: @bikes
end
And that’s pretty much it on the rails side. Pretty cool!
You will probably want to do much more, like change the data:
def my_json_function
@vehicles = {}
@vehicles[:two_wheels] = Bike.all
@vehicles[:four_wheels] = Car.all
render json: @vehicles
end
def my_json_function
@vehicles = {}
@vehicles[:two_wheels] = Bike.all
@vehicles[:four_wheels] = Car.all
render json: @vehicles
end
Add urls to images with a serializer and so on, however this will probably be outside of the scope of this article as you may want to create a proper api structure. You can do alot of fun stuff!
6- Finally, fetch on the front end.
const fetchDataFunction = () => {
fetch('https://bikes4life.com/my_json_function')
.then((data)=> data.json())
.then((response) => console.log(response))
.catch((error) => console.log(error))
}
From here, you will need to invoke the
fetchDataFunction
and probably add more functionality other than console.log.As mentioned, this is quite a simplified run through, however I think it could help others like me who had trouble bridging the two sides between Rails and JS.
You might not want to make many end points in this way but the advantage of this solution is you can also have your classic rails views doing things like managing uploads and so on like an admin type app, that feeds other apps through this method.
Here is another great article that talks about the cors gem implementation in Rails.
Thanks!