|
1 | 1 | # Rails-API-React-Tutorial 💻 [](https://github.com/ellerbrock/open-source-badges/)
|
2 | 2 |
|
3 | 3 | Hey! 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 Ruby
|
4 |
| -and Rails 5 in a Virtual Box, React JS via create-react-app and connecting the frontend and backend. |
| 4 | +and Rails 5 in a Virtual Box, React JS via create-react-app and connecting the frontend and backend.<br> |
| 5 | + |
| 6 | +<p align="center"> |
| 7 | + <img width="460" height="320" src="https://media.giphy.com/media/oZKuC9DJUK2yc/giphy.gif"> |
| 8 | +</p> |
5 | 9 |
|
6 | 10 | ## Table of Contents
|
7 | 11 | * Downloading Virtual Box
|
@@ -150,3 +154,276 @@ class Application < Rails::Application
|
150 | 154 | ```
|
151 | 155 |
|
152 | 156 | Since this tutorial is mainly for testing and toy projects, we are allowing ALL methods from another domain. You should tailor the header and methods to your liking.
|
| 157 | + |
| 158 | +## Rails API Versioning |
| 159 | + |
| 160 | +Versioning is the process of seperating and creating new features/data/endpoints for your API. Since this is our first API, let's make our ```test-api``` v1. |
| 161 | + |
| 162 | +1. Run the following in your terminal |
| 163 | +```shell |
| 164 | +mkdir mkdir app/controllers/api && mkdir app/controllers/api/v1 |
| 165 | +``` |
| 166 | +If everything looks right you should see your directory identical as below. <br><br> |
| 167 | +<a href="http://tinypic.com?ref=3589c11" target="_blank"><img src="http://i67.tinypic.com/3589c11.png" height="280" width="280" border="0" alt="Image and video hosting by TinyPic"></a> |
| 168 | + |
| 169 | + 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```. |
| 170 | + |
| 171 | + 2. Let's scaffold a test model/controller and call it ```movies``` |
| 172 | + |
| 173 | + ```ruby |
| 174 | + rails g scaffold Movies name:string rating:integer |
| 175 | + |
| 176 | + rails db:migrate |
| 177 | + ``` |
| 178 | + |
| 179 | + The Rails engine creates your controller in the default ```/controllers``` directory but we need to move our new controller into the ```api/v1``` directory. |
| 180 | + |
| 181 | + 3. You can either move it manually or the following: |
| 182 | + |
| 183 | + ```shell |
| 184 | + mv app/controllers/movies_controller.rb app/controllers/api/v1 |
| 185 | + ``` |
| 186 | + 4. Update the Movies Controller |
| 187 | + |
| 188 | + Our 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 |
| 189 | + |
| 190 | + ```ruby |
| 191 | + class MoviesController < ApplicationController |
| 192 | + ``` |
| 193 | + TO |
| 194 | + |
| 195 | + ```ruby |
| 196 | + class Api::V1::MoviesController < ApplicationController |
| 197 | + ``` |
| 198 | + |
| 199 | +5. Update the Routes |
| 200 | +Locate to your config folder and open your ```routes.rb``` file. |
| 201 | + |
| 202 | +```ruby |
| 203 | +Rails.application.routes.draw do |
| 204 | + resources :movies |
| 205 | +end |
| 206 | +``` |
| 207 | + |
| 208 | +If we go to ```localhost:3000/movies``` we will not call the controller. We must update our Routes to: |
| 209 | +```ruby |
| 210 | +Rails.application.routes.draw do |
| 211 | + namespace :api do |
| 212 | + namespace :v1 do |
| 213 | + resources :movies |
| 214 | + end |
| 215 | + end |
| 216 | +end |
| 217 | +``` |
| 218 | +which allows us to call the json data from ``` localhost:3000/api/v1/movies``` |
| 219 | + |
| 220 | + |
| 221 | +6. Let's seed our sqlite database with some classic movies so we can practice getting data with GET requests to the API. |
| 222 | + |
| 223 | +Copy and paste the following data to your ```config/seeds.rb``` file. |
| 224 | + |
| 225 | +```ruby |
| 226 | +Movie.create(name: "The Nightmare Before Christmas", rating: 5) |
| 227 | +Movie.create(name: "Titanic", rating: 5) |
| 228 | +Movie.create(name: "Venom", rating: 4) |
| 229 | +Movie.create(name: "A Quiet Place", rating: 5) |
| 230 | +Movie.create(name: "Nobody's Fool", rating: 2) |
| 231 | +Movie.create(name: "Suspiria", rating: 4) |
| 232 | +Movie.create(name: "Hereditary", rating: 4) |
| 233 | +Movie.create(name: "Office Space", rating: 5) |
| 234 | +Movie.create(name: "Elf", rating: 4) |
| 235 | +Movie.create(name: "Dawn of the Planet of the Apes", rating: 3) |
| 236 | +Movie.create(name: "Secret life of Pets", rating: 4) |
| 237 | +Movie.create(name: "Overlord", rating: 3) |
| 238 | +Movie.create(name: "Wonder Woman", rating: 5) |
| 239 | +Movie.create(name: "Bohemian Rhapsody", rating: 4) |
| 240 | +Movie.create(name: "Ocean's 8", rating: 5) |
| 241 | +``` |
| 242 | + |
| 243 | +Seed the DB using ``` rails db:seed && rails db:migrate ``` |
| 244 | + |
| 245 | +7. Test the API using a GET request. |
| 246 | + |
| 247 | +Start your Rails server ```rails s``` and navigate to ```localhost:3000/api/v1/movies``` and if it is successful you should see the following JSON output: <br><br> |
| 248 | + |
| 249 | +(Optional) I'm using a pretty JSON viewer for chrome which you can download [here.](https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc) |
| 250 | +<a href="http://tinypic.com?ref=2m60ahx" target="_blank"><img src="http://i63.tinypic.com/2m60ahx.png" width="450" height="450" border="0" alt="Image and video hosting by TinyPic"></a> |
| 251 | + |
| 252 | +Congrats! You have successfully created a Rails API and completed your first GET request! |
| 253 | + |
| 254 | +## Downloading React into our Project |
| 255 | + |
| 256 | +React 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. |
| 257 | + |
| 258 | +1. Open your terminal and create a new project inside your API. |
| 259 | +``` |
| 260 | +create-react-app client |
| 261 | +``` |
| 262 | +<br> |
| 263 | +<a href="http://tinypic.com?ref=1zya22t" target="_blank"><img src="http://i64.tinypic.com/358xiu0.png" border="0" height="300" width="280" alt="Image and video hosting by TinyPic"></a> |
| 264 | +<br> |
| 265 | + |
| 266 | +2. Download Boostrap into the react directory: |
| 267 | + |
| 268 | +``` |
| 269 | +npm install --save reactstrap bootstrap@4 |
| 270 | +``` |
| 271 | + |
| 272 | +Then open your ```index.js``` file inside the ```/src``` directory and add the following import line: |
| 273 | +```javascript |
| 274 | +import React from 'react'; |
| 275 | +import ReactDOM from 'react-dom'; |
| 276 | +import './index.css'; |
| 277 | +import App from './App'; |
| 278 | +import * as serviceWorker from './serviceWorker'; |
| 279 | +// Import goes below for Bootstrap |
| 280 | +import 'bootstrap/dist/css/bootstrap.css'; |
| 281 | +``` |
| 282 | + |
| 283 | + |
| 284 | +3. Let's proxy our client so we know where to get the requests from! |
| 285 | + |
| 286 | +Open ```package.json``` from our react folder and add the following json code to your package. |
| 287 | + |
| 288 | +```javascript |
| 289 | + "proxy": "http://127.0.0.1:3000", |
| 290 | +``` |
| 291 | + |
| 292 | +Heres mine as an example! |
| 293 | +```javascript |
| 294 | +{ |
| 295 | + "name": "client", |
| 296 | + "version": "0.1.0", |
| 297 | + "private": true, |
| 298 | + "proxy": "http://127.0.0.1:3000", |
| 299 | + "dependencies": { |
| 300 | + "bootstrap": "^4.1.3", |
| 301 | + "react": "^16.6.3", |
| 302 | + "react-dom": "^16.6.3", |
| 303 | + "react-scripts": "2.1.1", |
| 304 | + "reactstrap": "^6.5.0" |
| 305 | + }, |
| 306 | + |
| 307 | +``` |
| 308 | +
|
| 309 | +4. We'll make a default Component directory inside the ```/src``` folder and create our first component. |
| 310 | +
|
| 311 | + ``` |
| 312 | + cd client/src && mkdir components && cd components && touch Button.js |
| 313 | + ``` |
| 314 | + 5. Open your ```Button.js``` file and lets create a sample button to activate our call function to the API. |
| 315 | +
|
| 316 | +```javascript |
| 317 | +import React, { Component } from 'react'; |
| 318 | + |
| 319 | +class Button extends Component { |
| 320 | + render() { |
| 321 | + return ( |
| 322 | + <div> |
| 323 | + <div class="card container mt-3"> |
| 324 | + <div class="card-body"> |
| 325 | + <div class="row"> |
| 326 | + <center> |
| 327 | + <button class="btn btn-primary">Test Call!</button> |
| 328 | + </center> |
| 329 | + </div> |
| 330 | + </div> |
| 331 | + </div> |
| 332 | + </div> |
| 333 | + ); |
| 334 | + } |
| 335 | +} |
| 336 | + |
| 337 | +export default Button; |
| 338 | + |
| 339 | + ``` |
| 340 | + |
| 341 | +6. Start your server `npm start` and check if your bootstrap import works as well as the test button! If all is displaying then we are almost done. We are sooooo close! |
| 342 | +
|
| 343 | +We want our button to actually call the API now so lets create the function with the appropriate call. We want to add an onclick event to the button html like so: |
| 344 | +
|
| 345 | +```javascript |
| 346 | +<button class="btn btn-primary" onClick={this.callApi}>Test Call!</button> |
| 347 | +``` |
| 348 | +
|
| 349 | +and our custom function PLUS the initial state set to null |
| 350 | +
|
| 351 | +```javascript |
| 352 | + |
| 353 | + state = { |
| 354 | + |
| 355 | + results: [] |
| 356 | + } |
| 357 | + |
| 358 | + callApi = async() => { |
| 359 | + |
| 360 | + const api_call = await fetch('http://localhost:3000/api/v1/movies'); |
| 361 | + |
| 362 | + const data = await api_call.json(); |
| 363 | + |
| 364 | + this.setState({ |
| 365 | + |
| 366 | + results: data |
| 367 | + }); |
| 368 | + |
| 369 | + } |
| 370 | + |
| 371 | +``` |
| 372 | +
|
| 373 | +After copying and pasting both snippets inside the `Button.js` file, we fetch from the url `http://localhost:3000/api/v1/movies` in a json format and once we return a true response we will set the response to the data variable and console log the results into the browser. |
| 374 | + |
| 375 | +This should be the complete Button.js file below! |
| 376 | + |
| 377 | +```javascript |
| 378 | +import React, { Component } from 'react'; |
| 379 | +
|
| 380 | +class Button extends Component { |
| 381 | +
|
| 382 | + state = { |
| 383 | +
|
| 384 | + results: [] |
| 385 | +} |
| 386 | +
|
| 387 | +
|
| 388 | + callApi = async() => { |
| 389 | +
|
| 390 | + const api_call = await fetch('http://localhost:3000/api/v1/movies'); |
| 391 | +
|
| 392 | + const data = await api_call.json(); |
| 393 | +
|
| 394 | + this.setState({ |
| 395 | +
|
| 396 | + results: data |
| 397 | + }); |
| 398 | + } |
| 399 | +
|
| 400 | +
|
| 401 | + render() { |
| 402 | +
|
| 403 | + return ( |
| 404 | + <div> |
| 405 | + <div className="card container mt-3"> |
| 406 | + <div className="card-body"> |
| 407 | + <div className="row"> |
| 408 | + <center> |
| 409 | + <button className="btn btn-primary" onClick={this.callApi}>Test Call!</button><br /> |
| 410 | + </center><br /><br /><br /><br /><br /> |
| 411 | + <p className="m-5">{this.state.results.map((obj) => <li>{obj.name}</li>)}</p> |
| 412 | + </div> |
| 413 | + </div> |
| 414 | + </div> |
| 415 | + </div> |
| 416 | + ); |
| 417 | + } |
| 418 | +} |
| 419 | +
|
| 420 | +export default Button; |
| 421 | +
|
| 422 | +
|
| 423 | +``` |
| 424 | + |
| 425 | +This should be everything we need to setup the API. Simply click our test api call button and see the magic work! |
| 426 | + |
| 427 | +<a href="http://tinypic.com?ref=ere5n5" target="_blank"><img src="http://i68.tinypic.com/ere5n5.png" height="300" width="310" border="0" alt="Image and video hosting by TinyPic"></a> |
| 428 | + |
| 429 | +### Congratulations! Our Rails API and React Client is done! |
0 commit comments