60
48

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DMM WEBCAMPAdvent Calendar 2020

Day 11

Rails + React + GraphQL + ApolloClientで画面表示されるまでのハンズオン!

Last updated at Posted at 2020-12-10

最初に

こんにちは!初めまして!!
11日目のカレンダーを担当させていただく佐々木です。:sunny:

さて、今回は私自身バックエンドを学んだら、その後どうしよう?と考えたところ
フロントエンドもできればかっこよくね??みたいな安直な考えで最初勉強し始めたのですが、
つまずく点が個人的にとても多く、とても苦労したので少しでも参考になればと思います。

ぜひ、Railsを活用して見たいという人に見ていただきたいです。

使うものについてさらっと説明

Ruby on Rails

言わずと知れたスピーディーでweb開発ができる優れもの:star:
https://guides.rubyonrails.org/

React

モダンなフロントエンドのフレームワークの一つです。
hooksめちゃ楽しいです!!:hourglass:
https://ja.reactjs.org/
####GraphQL
RESTapiの代わりになるものという認識です。(間違っていましたら申し訳ありません。)
なんかすごい直感的にかけるイメージ強いです。
https://graphql.org/

ApolloClient

ReactとRailsをつなぐものです。
https://www.apollographql.com/docs/react/api/core/ApolloClient/

完成のファイル

実装

バックエンド編

railsアプリの雛形の作成

早速ターミナルに打ち込んで雛形を作成しましょう。
※今回はAPIモードを使用します

ターミナル
$ rails new demo --api

モデルの作成

早速cd demoを入力してdemoディレクトリに移動しましょー!
移動できたところで

ターミナル
$ rails g model User name:string age:integer
$ rails g model Book title:string body:text user:references
$ rails db:migrate RAILS_ENV=development

としてUserBookモデルを作成&反映させていきましょう。
referencesについてはこちらが参考になります。

リレーションの定義

モデルの作成ができましたら、Bookモデルの方はreferencesによって自動でリレーションできているので、Userモデルの方のみ設定していきましょう。

user.rb
class User < ApplicationRecord
  # 以下を記述
  has_many :books
end

各種gemのインストール

それぞれgemをインストールしていきます。
graphql → GraphQLの開発に必須
graphiql-rails → railsのdevelopment環境でGraphQLの動作確認をできるようにする
faker → ランダムなダミーデータの自動作成

Gemfile
group :development do
  gem 'listen', '~> 3.2'
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  # 追加
  gem 'graphiql-rails'
  gem 'faker'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
# 追加
gem 'graphql'

と記述できたら

ターミナル
$ bundle install

しておきましょう!

GraphQLのインストール

佐伯ほど追加したgraphqlを利用するために

ターミナル
$ rails g graphql:install

とすることでappファイルの直下にgraphql関連のものが追加され

routes.rb
Rails.application.routes.draw do
  # 以下の部分が自動で追加されている
  post "/graphql", to: "graphql#execute"
end

となります。
また、、以下のコマンドをコマンドをターミナル上で扱うことができるようになります。

Graphql:
  graphql:enum
  graphql:install
  graphql:interface
  graphql:loader
  graphql:mutation
  graphql:object
  graphql:scalar
  graphql:union

ダミーデータの作成

先ほどインストールしたfakerを利用して

seeds.rb
10.times do
  user = User.create!(name: Faker::Name.name, age: rand(1..100))
  10.times do
    user.books.create!(title: Faker::Lorem::sentence(word_count: 5),
                       body: Faker::Lorem::paragraph(sentence_count: 4))
  end
end

として

ターミナル
$ rails db:seed
$ rails c # コンソール画面へ
irb(main):001:0> User.all
   10個のUser情報の表示
irb(main):002:0> Book.all
   10個のBook情報の表示
irb(main):003:0> exit

と確認することができれば正しくデータが入っているかわかります!

GraphQLのオブジェクトの作成

最初にターミナルにてgraphqlのオブジェクトを作成していきます。

ターミナル
$ rails g graphql:object user
$ rails g graphql:object book

と記述することでapp/graphql/types直下にオブジェクト名_type.rb
作成されると思います。

タイプファイルの確認と追加

ここでの型定義はmigrateファイルに少し近い記述方法となります。
確認と追加を行いましょう」。

user_type.rb
module Types
  class UserType < Types::BaseObject
    field :id, ID, null: false
    field :name, String, null: true
    field :age, Integer, null: true
    field :created_at, GraphQL::Types::ISO8601DateTime, null: false
    field :updated_at, GraphQL::Types::ISO8601DateTime, null: false

    # ここから記述
    field :books, [Types::BookType], null: false
    field :books_object_count, Integer, null: false

    # ユーザーに紐づけられたBookオブジェクトの数を数える
    def books_object_count
      object.books.count
    end
  end
end
book_type.rb
module Types
  class BookType < Types::BaseObject
    field :id, ID, null: false
    field :title, String, null: true
    field :body, String, null: true
    field :user_id, Integer, null: false
    field :created_at, GraphQL::Types::ISO8601DateTime, null: false
    field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
  end
end

Queryの定義

簡単にQueryの説明をしておくとデータを取得するものという認識で大丈夫だと思います。
※補足としてここの部分の詳細は一つのデータのみを取得するので配列で括らなくで大丈夫です。

query_type.rb
module Types
  class QueryType < Types::BaseObject
    # 全てのデータの取得
    field :users, [Types::UserType], null: false
    def users
      User.all
    end

    # 引数の番号のデータを取得
    field :user, Types::UserType, null: false do
      argument :id, ID, required: true
    end
    def user(id:)
      User.find(id)
    end
  end
end

railsでGraphqlを確認できるようにする

ここまで、できたら実際に確認してみましょう。
実際に``とアクセスしてGraphQLの画面を開けるように

routes.rb
Rails.application.routes.draw do
  # ここの部分を記述
  if Rails.env.development?
    mount GraphiQL::Rails::Engine, at: '/graphiql', graphql_path: "graphql#execute"
  end

  # 以下の部分が自動で追加されている
  post "/graphql", to: "graphql#execute"
end

と記述し

application.rb
require_relative 'boot'

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_mailbox/engine"
require "action_text/engine"
require "action_view/railtie"
require "action_cable/engine"
require "sprockets/railtie" # ここの部分のコメントアウトを取る
require "rails/test_unit/railtie"

さらに
appフォルダの直下にassets/config/manifest.jsを作成し

manifest.js
//= link graphiql/rails/application.css
//= link graphiql/rails/application.js

とすることでdevelopment環境でのみアクセスが可能となります。

スクリーンショット 2020-12-03 8.39.51.png
このような画面になればOKです!!

データを確認する

ここまでできたら実際にデータを確認してみましょう!

全てのデータ

ここでのデータは
Userは10人(IDは全部で10)
1人のUserに紐づけられている本は10冊なので合計で100冊(IDは全部で100)
となります。
スクリーンショット 2020-12-03 11.28.05.png

指定されたデータ

スクリーンショット 2020-12-03 11.30.02.png
となります。

フロントエンド編

フロント部分の雛形を作成

では、reactの雛形を作成していきましょう。
今回はcreate-react-appを使用してお手軽reactアプリケーションを作成します。

ターミナル
$ yarn global add create-react-app #create-react-appコマンドをグローバルで使用できるようにする
$ create-react-app front-demo #雛形を作成

CORSの設定

CORSとはCRUDリクエストをサーバーがフィルターするものという認識です!
参考サイトとしてこちらをご参照ください
デフォルトでコメント状態となっているのでコメントアウトしてあげましょう!

Gemfile
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
gem 'rack-cors' #コメントアウト

としてbundle installしましょう!
続いて

cors.rb
# Be sure to restart your server when you modify this file.

# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.

# Read more: https://github.com/cyu/rack-cors

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

としましょう。

画面に表示させる

雛形で作成したものから
スクリーンショット 2020-12-10 17.28.47.png

以上のようなものをそれぞれインストールのほどお願いします。
そしてデフォルトで作成されているApp.jsファイルを

App.js
import React from 'react';
import ApolloClient from 'apollo-boost'
import { ApolloProvider } from "@apollo/react-hooks"
import Demo from "./Demo";
const client = new ApolloClient({
  uri: 'http://localhost:3000/graphql'
})

const App = () => {
    return (
        <ApolloProvider client={client} >
            <div className="App">
                <Demo/>
            </div>
        </ApolloProvider>
    );
}

export default App;

としていき、srcファイル内にDemo.jsというファイルを作成していただき

Demo.js
import React from 'react';
import {useQuery} from '@apollo/react-hooks';
import gql from 'graphql-tag';

const GET_USERS = gql`
    {
        users{
            id
            name
            age
            books{
                id
                title
                body
            }
        }
    }
`;

const Demo = () => {
    const {loading, error, data} = useQuery(GET_USERS);
    const style = {
        color: "red"
    };

    if (loading) return 'ロード中....';
    if (error) return `Error ${error.message}`;
    return (
        <React.Fragment>
            {data.users.map(user => (
                <div key={user.id}>
                    <h1>{user.name}</h1>
                    <h2>{user.age}</h2>
                    {user.books.map(book => (
                        <div key={book.id}>
                            <h1>{book.title}</h1>
                            <h2>{book.body}</h2>
                        </div>
                    ))};
                    <h1 style={style}>ここまでが{user.id}回目!</h1>
                </div>
            ))}

        </React.Fragment>
    )
};

export default Demo;

としましょう!

画面で確認する

スクリーンショット 2020-12-10 17.26.39.png
と表示されれば完璧です!
文字の部分はFakerの文字になるのでランダムです。

以上が実装の一例となります!

ここからさらにGET_USERやユーザーの作成などの拡張ができると思うのでお手隙の際にぜひ試してみてください:runner_tone1:

記事を見てくださりありがとございました!!!:new_moon:

60
48
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
60
48

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?