July 3, 2020
Flutter and Rails from Scratch
@anthonycorletti

I'm primarily a backend, cloud developer, so building frontend clients wigs me out. So in the spirit of learning, I have mustered enough fearlessness and courage to try and build an app with a brand new client framework that I hadn't used before

For a while I've wanted to build something with flutter - especially with flutter web being released – you can build a web, iOS, and Android app all in one go!

In this post, I'm going to quickly plug a Rails API and Flutter UI together and show just how fast, fun, and easy development with Rails and Flutter can be.

It's pretty simple to connect a Rails API to a Flutter UI in a snap, although there are a couple of considerations to make around state management, we'll refer to Google's recommendation to use the BLoC pattern as it works really well with Rails.

I'm not going to go into the details of BLoC but will leave more links and things at the end of this post for further reading.

The API

First step is to whip up our api – let's do that by installing rails and getting some modules created.

I'm using rbenv to manage ruby, you can install it with brew:

brew install rbenv
rbenv install 2.7.1  # this might take little while
ruby -v  # => ruby 2.7.1p83
gem install rails
rails -v  # => Rails 6.0.3.2
rails new --api postapi
cd postapi
rails g scaffold post title:string body:string
rails db:migrate

Nice, we've setup an api and db to test this out.

Now let's create some posts via the rails console, run rails c to enter your rails console.

Post.create(title: "Flutter and Rails from Scratch", body: "Lots of great content")
Post.create(title: "War and Peace", body: "Lots of great content")
Post.create(title: "Finite and Infinite Games", body: "Lots of great content")
Post.all().map { |p| p.attributes } # to make sure everything was created

The UI

Let's install flutter and get the UI going.

I'm taking the clone approach, and placing flutter in my home directory.

cd $HOME
git clone https://github.com/flutter/flutter.git
export PATH="$PATH:$HOME/flutter/bin"
flutter doctor

Here's where I hit some hiccups. I realized I haven't done Android development or iOS development on my machine in eons. So I had to install cocoapods and Android Studio (oof this is why I prefer backend and cloud software dev).

I'm using a Mac and the instructions I found for getting your Android system all squared away can be found here.

Cool - so let's install cocoapods.

gem install cocoapods

Basically keep running flutter doctor until everything checks out. You'll also have to install the flutter plugin and dart plugin if you're using Android Studio (installation instructions for those are here).

You should end up with something that looks like this:

$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[] Flutter (Channel master, 1.20.0-3.0.pre.126, on Mac OS X 10.15.5 19F101, locale en-US)
[] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
[] Xcode - develop for iOS and macOS (Xcode 11.5)
[] Android Studio (version 4.0)
[!] Connected device
    ! No devices available

! Doctor found issues in 1 category.

Now switch to flutter's beta channel and create your workspace for the flutter app.

flutter channel beta
flutter upgrade
flutter config --enable-web
flutter create postclient
cd postclient
flutter run

flutter run will not work (unless you've connected a device), so we'll just use an emulator.

flutter emulators --launch apple_ios_simulator

Now open up your favorite editor to start hacking on the app. I'm using atom but you can use whatever you like, there are instructions for a few different editors in Flutter's getting started guide.

I used apm install dart-atom to help with syntax highlighting. I don't quite have the time or patience to setup VSCode for myself - but eventually, well get there!

pwd     # => $HOME/postclient
atom .

In your pubspec.yaml you'll need to add a dependency for the http package.

Do that by adding http: ^0.12.1 under the dependencies: line, and install it by running flutter pub get.

Now, replace the contents of lib/main.dart with the following.

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Post> fetchPost() async {
  final response =
      await http.get('http://127.0.0.1:3000/posts/1');

  if (response.statusCode == 200) {
    // If the call to the server was successful, parse the JSON.
    return Post.fromJson(json.decode(response.body));
  } else {
    // If that call was not successful, throw an error.
    throw Exception('Failed to load post');
  }
}

class Post {
  final int id;
  final String title;
  final String body;

  Post({this.id, this.title, this.body});

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      id: json['id'],
      title: json['title'],
      body: json['body'],
    );
  }
}

void main() => runApp(MyApp(post: fetchPost()));

class MyApp extends StatelessWidget {
  final Future<Post> post;

  MyApp({Key key, this.post}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetch Data Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Fetch Data Example'),
        ),
        body: Center(
          child: FutureBuilder<Post>(
            future: post,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Text(snapshot.data.title);
              } else if (snapshot.hasError) {
                return Text("${snapshot.error}");
              }

              // By default, show a loading spinner.
              return CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}

Now run the api, the app, and checkout the simulator!

rails s
flutter run

You should see something like this!

simple_flutter

Cool right!

It does not take much to get going with Flutter and Rails. Especially since Rails development coincides nicely with BLoC pattens. Flutter and Rails make a great pair in quickly developing applications and platforms – a huge plus for startups.

To learn more about BLoC, Flutter, and Rails, checkout the links below.