{"id":14955429,"url":"https://github.com/johncorderox/rails-api-react-tutorial","last_synced_at":"2026-03-01T21:36:19.595Z","repository":{"id":40008278,"uuid":"154935834","full_name":"johncorderox/Rails-API-React-Tutorial","owner":"johncorderox","description":"📱 A Rails 6 API backend React JS + Webpacker guide. Includes API setup, serializers, and react integration in the frontend. 🌲 ","archived":false,"fork":false,"pushed_at":"2023-04-12T06:00:02.000Z","size":27724,"stargazers_count":74,"open_issues_count":3,"forks_count":17,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-14T11:20:45.456Z","etag":null,"topics":["api","downloading-react","rails-api","rails6","react","react-api-tutorial","react-js","scaffold","serializers","webpacker"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johncorderox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-27T07:00:30.000Z","updated_at":"2024-05-23T13:17:01.000Z","dependencies_parsed_at":"2024-05-28T07:39:07.537Z","dependency_job_id":null,"html_url":"https://github.com/johncorderox/Rails-API-React-Tutorial","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johncorderox%2FRails-API-React-Tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johncorderox%2FRails-API-React-Tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johncorderox%2FRails-API-React-Tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johncorderox%2FRails-API-React-Tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johncorderox","download_url":"https://codeload.github.com/johncorderox/Rails-API-React-Tutorial/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234737844,"owners_count":18879180,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","downloading-react","rails-api","rails6","react","react-api-tutorial","react-js","scaffold","serializers","webpacker"],"created_at":"2024-09-24T13:11:08.696Z","updated_at":"2025-09-30T13:30:43.299Z","avatar_url":"https://github.com/johncorderox.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rails-API-React-Tutorial 💻 ![GitHub last commit](https://img.shields.io/github/last-commit/johncorderox/Rails-API-React-Tutorial?style=flat-square) ![GitHub contributors](https://img.shields.io/github/contributors/johncorderox/Rails-API-React-Tutorial?color=blue\u0026style=flat-square)\n\nHey! This is a super-easy to follow Rails/React API tutorial that is fully in depth from start to finish. This guide shows you how to install a Ruby on Rails 6 API with React JS via Webpacker and connecting the frontend with the backend. \u003cbr\u003e\n\n\u003cb\u003eStack:\u003c/b\u003e Rails 6 API + React JS located in ```app/javascript``` + Webpacker\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" height=\"320\" src=\"https://media.giphy.com/media/14wHxi7D45grRK/giphy.gif\"\u003e\n\u003c/p\u003e\n\n## System Requirements \n```Ruby\nruby \"2.6.3\" +\n\ngem \"rails\", \"~\u003e 6.1.3\"\n\n```\n\n## Table of Contents\n- [Creating a Rails API](#rails-api-)\n- [Rails API Versioning](#rails-api-versioning)\n- [React Integration](#react-integration)\n- [Restructure our React Project](#restructure-our-react-project)\n- [Our First Component](#our-first-component)\n- [Rails Serializers](#rails-serializers)\n- [Contributing](#contributing)\n- [About the Author](#about-the-author)\n\n## Rails API 💎\n\nThe new rails api command scaffolds everything we need to get up and ready for our project. Let's start our rails server and being integrating the backend first.\n\n1.  Run the following: `rails new my_app -T --database=postgresql`\n\nWhat's going on here?  The `-T` command also tells rails that we don't want Minitest as our testing suite. You'll most likely be used to Rspec so we'll talk about that later in the guide. The ```--database=postgresql``` line is pretty much self explanatory!\n\n## Rails API Versioning\n\nVersioning is the process of seperating and creating new features/data/endpoints for your API. Since this is our first API, let's make our rails api v1.\n\n1.  Run the following in your terminal\n\n```shell\nmkdir app/controllers/api \u0026\u0026 mkdir app/controllers/api/v1\n```\n\n\n Now that our versioning is complete, let's test out a model and controller to work with our new url of `localhost:3000/api/v1`.\n\n2.  Let's scaffold a test model/controller and call it `movies`\n\n\n```ruby\nrails g scaffold Movies name:string rating:integer\n```\nDon't forget to ```rails db:create``` if it was not yet initialized!\n\nThen we can use ``` rails db:migrate``` for our scaffold.\n\nThe Rails engine creates your controller in the default `/controllers` directory but we need to move our new controller into the `api/v1` directory.\n\n3.  You can either move it manually or the following:\n\n\n```shell\nmv app/controllers/movies_controller.rb app/controllers/api/v1\n```\n\n4.  Update the Movies Controller\n\nOur newly generated controller does not properly inherit from the namespace api/v1 (We will update the routes later in the tutorial) so let's change our controller class from\n\n```ruby\nclass MoviesController \u003c ApplicationController\n```\n\nTO\n\n```ruby\nmodule Api\n  module V1\n    class MoviesController \u003c ApplicationController\n    # The scaffold ruby code is here~\n    end\n  end\nend\n```\n\nThis makes it so we can INHERIT from the application controller without any additional tinkering.\n\n5.  Update the Routes\n    Locate to your config folder and open your `routes.rb` file.\n\n```ruby\nRails.application.routes.draw do\n  resources :movies\nend\n```\n\nIf we go to `localhost:3000/movies` we will not call the controller. We must update our Routes to:\n\n```ruby\nRails.application.routes.draw do\n namespace :api do\n  namespace :v1 do\n   resources :movies\n  end\n end\nend\n```\n\nwhich allows us to call the json data from `localhost:3000/api/v1/movies`\n\n6.  Let's seed our PG database with some classic movies so we can practice getting data with GET requests to the API.\n\nCopy and paste the following data to your `db/seeds.rb` file.\n\n```ruby\nMovie.create(name: \"The Nightmare Before Christmas\", rating: 5)\nMovie.create(name: \"Titanic\", rating: 5)\nMovie.create(name: \"Venom\", rating: 4)\nMovie.create(name: \"A Quiet Place\", rating: 5)\nMovie.create(name: \"Nobody's Fool\", rating: 2)\nMovie.create(name: \"Suspiria\", rating: 4)\nMovie.create(name: \"Hereditary\", rating: 4)\nMovie.create(name: \"Office Space\", rating: 5)\nMovie.create(name: \"Elf\", rating: 4)\nMovie.create(name: \"Dawn of the Planet of the Apes\", rating: 3)\nMovie.create(name: \"Secret life of Pets\", rating: 4)\nMovie.create(name: \"Overlord\", rating: 3)\nMovie.create(name: \"Wonder Woman\", rating: 5)\nMovie.create(name: \"Bohemian Rhapsody\", rating: 4)\nMovie.create(name: \"Ocean's 8\", rating: 5)\n```\n\nSeed the DB using `rails db:seed`.\n\n7.  Test the API using a GET request.\n\nStart your Rails server `rails s` or ```rails s -b 0.0.0.0 ``` and navigate to `localhost:3000/api/v1/movies` and if it is successful you should see the following JSON output: \u003cbr\u003e\u003cbr\u003e\n\u003cimg src=\"https://i.ibb.co/KXPQ1cd/Screen-Shot-2021-04-06-at-12-58-12-PM.png\" /\u003e\u003cbr\u003e\n(Optional) I'm using a pretty JSON viewer for chrome which you can download.\n\nCongrats! You have successfully created a Rails API and completed your first GET request!\n\n## React Integration\n\nReact is a component based front end framework that makes it easy to make frontend calls to our Rails API. Let's make this organized as possible and add our react directory inside our rails ```app/javascript``` directory.\n\n1.  Open your terminal and run the following webpacker commands to init the React Process.\n\n```\nbundle exec rails webpacker:install:react\n```\n\nAnd wait for the ```Webpacker now supports react.js 🎉``` message to finally use React! Woah :) \n\n2. Locate the javascript directory inside /app and see the new file we have with React.\n\n\u003cb\u003eNote:\u003c/b\u003e Notice the H1 tag on the ```Hello {props.name}!```, this is so we can see it clearly. When intalling, the H1 tag will not be there. It is purely cosmetic for now. \n\n```js\n# app/javascript/packs/hello_react.jsx\nimport React from 'react'\nimport ReactDOM from 'react-dom'\nimport PropTypes from 'prop-types'\n\nconst Hello = props =\u003e (\n  \u003cdiv\u003e\u003ch1\u003eHello {props.name}!\u003c/h1\u003e\u003c/div\u003e\n)\n\nHello.defaultProps = {\n  name: 'David'\n}\n\nHello.propTypes = {\n  name: PropTypes.string\n}\n\ndocument.addEventListener('DOMContentLoaded', () =\u003e {\n  ReactDOM.render(\n    \u003cHello name=\"React\" /\u003e,\n    document.body.appendChild(document.createElement('div')),\n  )\n})\n```\n\nWe can hook this file into any view we want React to send, so lets try this out now and add this to a demo view.\n\n3. Let's create a Home controller + view so can we load React to it. Run the following \n\n```\nrails g controller Home index\n```\n\nand locate your routes in ```config/routes.rb```\n\nOpen the route file and ROOT your application to the home controller\n\n```\nRails.application.routes.draw do\n  root 'home#index'\n  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html\nend\n```\n\n4. We now need to load our ```hello_react.jsx``` file to the HOME view, so let's include that now.\n\n``` app/views/home/index.html.erb\n\u003c%= javascript_pack_tag \"hello_react\" %\u003e\n```\n\n5. Run the rails server, and check out the React magic at hand! YAHOO!!\n\n\u003cimg src=\"https://i.ibb.co/DLPVvXr/Screen-Shot-2021-04-09-at-3-11-22-PM.png\" alt=\"Screen-Shot-2021-04-09-at-3-11-22-PM\" border=\"0\"\u003e\u003c/a\u003e\u003cbr /\u003e\u003cbr /\u003e\n\nReact has been linked, successfully. \n\n## Restructure our React Project\n\nPersonally, I don't like the structure of React in this concept, so let's add something more \"neater\" so we can find our components easier. \n\n1. Delete all of the contents inside the javascript directory so we can start fresh. \n2. Create 2 new folders named ```components``` and `packs` inside the javascript folder.\n3. Inside your `packs` folder, create a file named ```application.js``` and add the following to it:\n4. \n```js\nimport Rails from \"@rails/ujs\"\nimport Turbolinks from \"turbolinks\"\nimport * as ActiveStorage from \"@rails/activestorage\"\n\nRails.start()\nTurbolinks.start()\nActiveStorage.start()\n```\n\nLet's also create a hello_react.jsx file and add the following:\n\n```js\nimport React from 'react'\nimport ReactDOM from 'react-dom'\nimport App from '../components/App'\n\ndocument.addEventListener('DOMContentLoaded', () =\u003e {\n  ReactDOM.render(\n    \u003cApp /\u003e,\n    document.body.appendChild(document.createElement('div')),\n  )\n})\n```\n\n4. Next, let's create a new folder named `components` and create a file named `App.js`\n\nAdd the following to `App.js`\n\n```js\nimport React, { Component } from 'react'\n\nclass App extends Component {\n  render(){\n    return(\n      \u003cdiv\u003e\n      \u003ch1\u003e React says Hello! \u003c/h1\u003e\n      \u003c/div\u003e\n\n    )\n  }\n}\n\nexport default App\n\n```\n\n5. You should now be able to see the structure better with a `components` folder and add any new component you wish!. Let's run the rails server to see if its calling our new H1 text.\n\n\u003cimg src=\"https://i.ibb.co/jT5Cq5c/Screen-Shot-2021-04-09-at-3-23-48-PM.png\" alt=\"Screen-Shot-2021-04-09-at-3-23-48-PM\" border=\"0\"\u003e\n\n6. Our new structure is complete! You can stop here and make your own API to your own liking. In the next section, we can create a new component and test the data being called!\n\n## Our First Component\n\nReact JS is all about components! Assuming we know basic React workflow, lets create a new component under the `component` direct named `MovieInfo.js`\n\n1. We can add the following to `MovieInfo.js` as the basic skeleton.\n\n```js\n# app/js/components/MovieInfo.js\n\nimport React from 'react'\n\nexport class MovieInfo extends React.Component {\n\n  constructor() {\n     super();\n   }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n      \u003c/div\u003e\n  )\n}\n\n}\nexport default MovieInfo;\n```\n\n2. Let us add a state method so we can fill the array with the API call. Add this under the export class line\n\n```js\n  constructor() {\n     super();\n     this.state = {\n       movies: []\n     };\n   }\n```\n\n3. We should ass add the `componentDidMount` function so the data can be created in the virtual DOM on page load.\n\n```js\n  componentDidMount(){\n    fetch(\"/api/v1/movies\")\n    .then(resp =\u003e resp.json())\n    .then(m =\u003e {\n      this.setState({\n        movies: m\n      })\n    })\n    .catch(error =\u003e console.log(error))\n  }\n```\n\n4. Our final file should look like this.\n\n```js\nimport React from 'react'\n\nexport class MovieInfo extends React.Component {\n\n  constructor() {\n     super();\n     this.state = {\n       movies: []\n     };\n   }\n\n  componentDidMount(){\n    fetch(\"/api/v1/movies\")\n    .then(resp =\u003e resp.json())\n    .then(a =\u003e {\n      this.setState({\n        movies: a\n      })\n    })\n    .catch(error =\u003e console.log(error))\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n      {this.state.movies.map(obj =\u003e\n        \u003cp key={obj.id}\u003e{obj.name}\u003c/p\u003e\n\n      )}\n     \u003c/div\u003e\n  )\n}\n\n}\nexport default MovieInfo;\n\n```\n\n5. Import the file to our `App.js` file.\n\n```js\nimport React, { Component } from 'react'\n// Here V\nimport MovieInfo from './MovieInfo'.\n\n\nclass App extends Component {\n  render(){\n    return(\n      \u003cdiv\u003e\n      // And Here V\n        \u003cMovieInfo /\u003e\n      \u003c/div\u003e\n\n    )\n  }\n}\n\nexport default App\n\n```\n\n\n6. Start the rails server! And Success!! We can now make API calls to our backend!\n\u003cimg src=\"https://i.ibb.co/ys2SQFd/Screen-Shot-2021-04-09-at-3-47-16-PM.png\" width=\"300\" alt=\"Screen-Shot-2021-04-09-at-3-47-16-PM\" border=\"0\"\u003e\n\n\n\n💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘💘 \u003cbr\u003e\u003cbr\u003e\nCongratulations! Our Rails API and React Client is done!  \u003cbr\u003e\u003cbr\u003e\nIf you enjoyed this API tutorial please give it a star and share it with your friends!\n\n## Rails Serializers\n\nWhat are Serializers? Well Rails API's returns JSON data in full, so serializers allows us to cherry pick the exact data we want in a much organized fashion. Instead of getting every column from the returned data, we can grab which ever we allow to pass through.\n\n| Normal Model        | Serializer Model    |\n| ------------- |:-------------:|\n| id, name, rating, director, score, actors_id, created_at, updated_at| id, name, rating|\n\nWe are able to tell the Rails API what to fetch rather than the frontend; making it much more simple and faster to scaffold your next project.\n\n1. Installation\n\nOpen your ```gemfile``` and add the serializer gem into your project. Don't forget to ```bundle install``` !\n```ruby\n# Serializer\ngem 'active_model_serializers', '~\u003e 0.10.0'\n```\n\nWe want to create a clone of any current model we have so when we make requests in the backend, the request will read the serializer file \u003cstrong\u003efirst\u003c/strong\u003e, then it will find the rails model/controller to finisht the request. We have a model called Movie so we'll duplicate that by running:\n\n```\nrails g serializer movie\n```\nYou can see that a new directory was made in the ```app/``` directory and we now have ```app/serializers/movie_serializer``` file in our project.\n\nLet's open that file and see what we have:\n```ruby\nclass MovieSerializer \u003c ActiveModel::Serializer\n  attributes :id, :name, :rating\nend\n\n```\n\nWe have our Movie Class inheriting from the serializer class on the first line, and the returned attribute on the second. So far the default returned attribute is just an ID, a name, and a rating. \n\n1a. Turn on your rails server and go to the url ``` localhost:3000/api/v1/movies ```\n\nYou should see that only the ```id``` and ```name``` attribute is being returned from the database.\n\n```json\n\n{ \"movies\":\n        [\n          {\n            \"id\": 1,\n            \"name\": \"The Nightmare Before Christmas\",\n            \"rating\": 5\n          },\n          {\n            \"id\": 2,\n            \"name\": \"The Titanic\",\n            \"rating\": 5\n          },\n          {\n            \"id\": 3,\n            \"name\": \"Venom\",\n            \"rating\": 4\n          }\n        ]\n }      \n```\n\nWe are done! What is the takeaway? \nReact will be fetching a lot of JSON data and we can reduce the uneeded attributes like `created_at` or `updated_at` that does not need to be displayed on the page.\n\n\n## Contributing\n- Fork it\n- Create your feature branch (git checkout -b my-new-feature)\n- Commit your changes (git commit -am 'Add some feature')\n- Push to the branch (git push origin my-new-feature)\n- Create new Pull Request\n\nI love collaboration! Please feel free to contribute or add your insights ✨ \n\n## About the Author\n\n**John Cordero** © [johncorderox](https://johncorderox.com), Released under the [MIT](./LICENSE) License.\u003cbr\u003e\n\n\u003e Blog [@jc](https://johncorderox.com) · GitHub [@johncorderox](https://github.com/metowolf) ·\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohncorderox%2Frails-api-react-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohncorderox%2Frails-api-react-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohncorderox%2Frails-api-react-tutorial/lists"}