PoC RoR React and CSV 07 / 08 / 2018
Has been a while without writing a technical post. Looking at startups I see often a webstack made out of Ruby on Rails (RoR) and React. With the facilities that RoR gives to create a REST API and the popularity of React, I understand the reasons.
To make a small PoC, I decided to import a random CSV to sqlite3 (why bother to use mysql/postgres for this example right?) so I can build a small backend with a service to find information easily.
Let’s start bottom up.
Model creation and importing the data
Download from this url the file 2019_domicilis_sexe.csv
. It’s open data from Barcelona, identifiying “Homes of the city of Barcelona according to the sex of the people who live in them.” It’s just an example. Any other CSV file should be good as well, but you’ll need to change the mapping of the fields and the types.
How to import this data into sqlite3 using Rails, and seeds?
- Copy
2019_domicilis_sexe.csv
into./lib/seeds/
directory (if not exists create it) -
Modify
./db/seeds.rb
and add the following coderequire 'csv' csv_text = File.read(Rails.root.join('lib', 'seeds', '2019_domicilis_sexe.csv')) csv = CSV.parse(csv_text, :headers => true, :encoding => 'ISO-8859-1') csv.each do |row| sd = SexDatum.new sd.year = row['Any'] sd.district_code = row['Codi_districte'] sd.district_name = row['Nom_districte'] sd.neighbourhood_code = row['Codi_barri'] sd.neighbourhood_name = row['Nom_barri'] sd.sex = row['Sexe'] sd.number = row['Nombre'] sd.save puts "Entry saved" end
- Let’s create the model for this table using:
rails g model SexData year:integer district_code district_name neighbourhood_code:integer neighbourhood_name sex number:integer
By default Rails uses
strings
as type for db fields. Just be explicit onintegers
on this case. - If the model was successfully created, you should see
./app/models/sex_datum.rb
on your filesystem. A migration then, should be executed for the creation of the table:rake db:migrate
. - Now with the model, the csv data and the seeds, let’s import the data:
rake db:seed
- To check that the model was created and the data imported, let’s use rails console:
rails c
- Once there, let’s find records:
SexDatum.all
Check names, types and values. All set!
Writing the Controller and handling the routes
Let’s create the namespace for the routes, so we can handle versions in the future.
- Create the directory
./controllers/api/v1/
-
And the file
sex_datum_controller.rb
in the same directory containing two methods: one to return all the records (just a test) and another one that will filter records bydistrict_code
(as an example)class Api::V1::SexDatumController < ApplicationController def index render json: SexDatum.all end def show datum = SexDatum.where district_code:params[:id] render json: datum end end
-
Rewrite the contents (asumming that we have a project from scratch) of
routes.rb
so we can hit two urlshttp://localhost:3000/
andhttp://localhost:3000/api/v1/sex_datum/2
. The number 2 is thedistrict_code
and is just an example.Rails.application.routes.draw do namespace :api do namespace :v1 do resources :sex_datum, only: [:index, :show] end end root to: 'home#index' end
Writing the View in React.js
-
An empty file should be created in
./app/views/home/index.html.erb
. This file should act as a placeholder. The real content will be on./app/javascript/components/App.jsx
served by webpack. Remember to install the gem and configure the path onwebpacker.yml
(sorry, maybe a long topic for the same post) The tileApp.jsx
will have the following content:import React from 'react' import InputDistrictCode from './InputDistrictCode' const App = () => { return ( <div> Hello, I am a react component rendered via rails webpacker <InputDistrictCode /> </div> ) } export default App
-
Now defining
InputDistrictCode.jsx
import React, {Component} from 'react'; import Result from './Result'; class InputDistrictCode extends Component { state = { code : '', result : [], } handleClick = (event) => { event.preventDefault(); fetch(`http://localhost:3000/api/v1/sex_datum/${this.state.code}`) .then(response => response.json()) .then(data => this.setState( {result : data})) } handleChange = (event) => { const {name, value} = event.target this.setState({ [name] : value }) } render() { return( <div> <input name='code' onChange={this.handleChange}> </input> <button onClick={this.handleClick}> Find it </button> <Result data={this.state.result} /> </div> ) } } export default InputDistrictCode;
-
And the last component,
Result.jsx
import React from 'react' const Result = ({data}) => ( <> {data.map( item => ( <div key={item.id}> {item.district_name} - {item.id} </div>))} </> ) export default Result;
Run the rails server with rails s
and the webpack sever ./bin/webpack-dev-server
. Heading now to http://localhost:3000/
you should see something like this:
Writing an integer in the input field and then hitting the button, some results from the database will be retrieved.
Hope it helps! If you need the code let me know in the comments.