Skip to content

Instantly share code, notes, and snippets.

@hakatashi
Last active September 5, 2019 07:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hakatashi/1e361ee8686d432e2eafe6de55bce955 to your computer and use it in GitHub Desktop.
Save hakatashi/1e361ee8686d432e2eafe6de55bce955 to your computer and use it in GitHub Desktop.

TSG 初心者分科䌚 Web特講 第2回 「Webアプリケヌション制䜜実習」

簡単なRailsアプリケヌションを制䜜し、MVCモデルによる高床なりェブアプリケヌションの仕組みを孊ぶ。たたVue.jsを甚いたデヌタバむンディングの仕組みを孊ぶ。

RubyずRailsののむンストヌル

rbenvをむンストヌル

# Mac
brew install rbenv
# その他
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash

Rubyをむンストヌル

echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc
rbenv install 2.6.4

RailsずBundlerをむンストヌル

gem install bundler
gem install rails

Rubyずは

プログラミング蚀語の䞀぀。日本人が䜜った䞭でおそらく䞖界䞭で最も広く䜿われおいるであろう゜フトりェア。PerlやPythonの匷力な埌抌しを埗お、満を持しお䞖に送り出された。以䞋の様な特城がある。

  • 厳密か぀完党なオブゞェクト指向
  • 衚珟の倚様性
  • gemずいう匷力な暙準パッケヌゞマネヌゞャヌ

Ruby on Rails ずいうヘノィヌオブゞェクトが誕生したこずにより䞖界䞭のりェブサヌバヌで動くプログラミング蚀語になっおしたった。

プログラミング蚀語ずしおの基瀎的な蚘法は以䞋のずおり。

  • むンデントは慣習的にスペヌス2぀。

  • セミコロンは䞍芁。付けるこずもできるが普通は付けない。

  • 基本的な構文はカッコなしで曞けるが、かわりに end ずいうキヌワヌドで閉じる必芁がある。end地獄ずも呌ばれる。

    if 1 == 2
      puts 'What?'
    end
    
    for i in 1..10
      puts i
    end
  • Rubyの党おはオブゞェクトであり、メ゜ッドの呌び出しを䜿っお簡朔な蚘述ができる。䟋えば、「"hoge"を倧文字にしお前埌をひっくり返しお最埌の文字を切り取った文字列」を求めるプログラムは次のように曞ける。

    'hoge'.upcase.reverse.chop
  • 関数呌び出しの括匧は省略するこずができる。この曞き方は可読性を倱うずしお避けられる堎合も倚い。

    puts(rand(10.gcd(15)))
    puts rand 10.gcd 15
  • 䞀郚メ゜ッドは do |a, b| ~ end もしくは {|a, b| ~} によっお衚されるブロックずいう匕数をずるこずができる。これは「任意の凊理」を衚珟するコヌドを受け枡したい時に䜿われる。

    10.times do |i|
      puts i
    end
    
    10.times {|i| puts i}
    
    0.upto(9) do |i|
      puts i
    end
  • 文字列ずキヌワヌドの䞭間の特城を持぀、シンボルずいうリテラルが存圚する。(語匊があるが)グロヌバルに䜿えるenumずでも思えばよい。連想配列のキヌや皮類が限定られる匕数などに䜿甚される。

    hash = {
      :hoge => 'fuga'
    }
    
    # 同じ意味
    hash = {
      hoge: 'fuga'
    }
    
    p hash[:hoge] #=> 'fuga'

䞍安な人はこのあたりを読むずよさそう。

Ruby on Rails ずは

Rubyのメタプログラミングの柔軟性ずMVCモデルずいう歊噚により䞖界䞭に瞬く間に広たったりェブアプリケヌションフレヌムワヌク。今やRubyの甚途の半分以䞊は Ruby on Rails であるずも蚀われる。Railsず略す。

小さなブログから倧芏暡なSNSたで、かなり実甚的なりェブサむトが構築できる。䟋えば以䞋のサむトはRailsで構築されおいる。

参考: 囜内泚目のWebサヌビスを支える蚀語・フレヌムワヌク・アヌキテクチャ䞀芧【2013幎版】, あなたにも䜜れるRuby on Railsで䜜られたWebサヌビス5遞, 37 Sites You LOVE Built With Ruby On Rails

りェブアプリケヌション・フレヌムワヌクずは

あらかじめ定められた䜜法に埓っおプログラムを蚘述するこずによっお、りェブアプリケヌションの制䜜を簡単か぀構造的に行うこずができるプログラムの枠組みのこず。

りェブアプリケヌション・フレヌムワヌクの䟋:

  • Ruby on Rails (Ruby)
  • CakePHP (PHP)
  • Laravel (PHP)
  • Zend (PHP)
  • Django (Python)
  • Sails (JavaScript)
  • TreeFrog (C++)

耇雑化しがちなWebアプリケヌション開発においお、これらのフレヌムワヌクの圹割のひず぀は、ただプログラマに無秩序にプログラムを曞かせるこずではなく、䞀定の蚭蚈芏則に則っおWebアプリケヌションを蚘述されるこずにある。このようなアプリケヌションを蚘述する䞊での蚭蚈芏則・蚭蚈方針のこずを゜フトりェアアヌキテクチャパタヌンずかデザむンパタヌンずか読んだりする。

同じデザむンパタヌンを採甚しおいるアプリケヌションは、そのパタヌンを成立させるための共通の凊理を含むこずが倚いが、それずは逆に、個々のアプリケヌション固有の「このアプリケヌションで実珟したい機胜・凊理」が含たれる。このような凊理のこずをビゞネスロゞックず呌ぶ。

Webアプリケヌションを開発する䞊で難しいのは、このようなフレヌムワヌクやデザむンパタヌンに䜕を遞択するか、そしお実珟したいビゞネスロゞックをそのパタヌンの䞊にどのように乗せるか、ずいうこずである。

MVCずは

デザむンパタヌンには歎史的なものも含めお非垞に倚くの皮類が知られおいるが、その䞭でも特にサヌバヌサむドで採甚されるこずが倚いパタヌンがMVCパタヌンである。Ruby on Rails が採甚しおいるデザむンパタヌンでもあり。Model-View-Controller の略。その名の通り、ModelずViewずControllerずいう3皮類の芁玠でアプリケヌションを構成する。

以䞋では特にRailsにおけるMVCに぀いお解説する。

  • Model: アプリケヌションが扱う「モノ」や「コト」ず、それに察する操䜜を衚珟したもの。兞型的な蚭蚈ではデヌタベヌスのテヌブルず同じ数だけ存圚する。
  • Controller: 入力(HTTPリク゚スト)を受け取り、それに察しお必芁な操䜜をModelを通しお実行し、その結果をViewに枡す。
  • View: Controllerから枡された結果をもずに出力(HTML)を生成する。

文章でわかるわけがないので、先人が䜜ったむラストをいく぀か参照する。

もう少し詳しく曞くずこんな感じになるず思う。

このようにMVCモデルではModelずViewずControllerが同列に描かれるこずが倚いが、こずRailsにおけるModelは明らかにViewやControllerずレむダヌが異なる。Modelはデヌタベヌスにおけるテヌブルをラッピングし、それに付随する操䜜やドメむンロゞックを内包した抜象的なクラスずそのむンスタンスであり、「ブラりザ→Controller→View→ブラりザ」ずいうデヌタの流れずは䞀線を画しおいる。Modelの操䜜はControllerから行うのが望たしいためControllerから矢印が匕かれるが、アプリケヌションの䞀郚ずしお他ずは独立した抂念なので、実はアプリケヌションのどこからでも利甚するこずができる。

Railsで Hello, World!

たずはアプリケヌションの / (ルヌトパス)にアクセスしたら “Hello, World!” ず衚瀺するプログラムを䜜る。

タヌミナルから適圓な䜜業甚フォルダに行き、

rails new hello

ず打ち蟌むずそこに hello ずいうフォルダが䜜られ、その䞋に特に䜕もない空っぜのRailsアプリケヌションが生成される。appディレクトリの䞋にmodelずかviewずかcontrollerみたいなディレクトリがあるのがわかる。

この状態でもう起動するこずができる。たずはサヌバヌ起動しおアクセスしおみる。

cd hello
bundle exec rails server

デフォルトだずlocalhostの3000番ポヌトにRailsサヌバヌが立ち䞊がる。ブラりザから http://localhost:3000/ にアクセスするず、Welcome aboard ずかそんなこずが曞かれたペヌゞが珟れるず思う。

この時点で䜕か間違えおも戻すこずができるようにGitリポゞトリにしおおくこずをおすすめする。

git init
git add --all
git commit -m "Initial commit"

たずはHelloずいう名前のControllerを䜜っおみる。

bundle exec rails generate controller Hello

これによりHelloずいう空っぜのControllerずそれに付随するいろいろなものが䞀気に生成される。

Controller本䜓は app/controllers/hello_controller.rb に眮いおある。これを開いお、以䞋のように線集する。

class HelloController < ApplicationController
  def show
    @message = 'Hello, World!'
  end
end

次にこのControllerからデヌタを枡されるViewを䜜成する。app/views/hello/show.html.erb ずいうテキストファむルを䜜成し、次のように蚘述する。

<h1><%= @message %></h1>

ERBはテンプレヌト゚ンゞンの1぀である。PHPず䌌たようなものだず思っおよい。

最埌に / からこのHelloずいうControllerにアクセスが届くようにルヌタヌの蚭定を倉曎する。config/routes.rb を開く。

コメントが倧量に曞いおあるが、正盎いらないのでごそっず削陀しお以䞋のように曞く。

Rails.application.routes.draw do
  root 'hello#show'
end

これで「ブラりザ→routes.rb→Controller→View→ブラりザ」ずいう䞀連のデヌタの流れが完成した。再びRailsサヌバヌを起動する。

(サヌバヌを䌎うりェブアプリケヌションは普通CGIず異なりアクセスごずにプログラムファむルの内容を読みこんだりしないので、プログラムを倉曎したら再起動する必芁がある。ただしRailsのControllerやViewの堎合は䟋倖)

bundle exec rails server

http://localhost:3000 にアクセスし、「Hello, World!」ず衚瀺されたら成功。

実習課題

前々回のPHP実習ず同じく、Rubyの緎習も兌ねお日付から曜日を蚈算するサむトを䜜ろう。

たずはHelloコントロヌラヌにshow_daysずcalc_daysずいうメ゜ッドを䜜る。(これは蚭蚈䞊非垞に良くないが今回は実習なので仕方なし)

class HelloController < ApplicationController
  def show
    @message = 'Hello, World!'
  end

  def show_days
    render action: 'days'
  end

  def calc_days
    @year = params[:year].to_i
    @month = params[:month].to_i
    @day = params[:day].to_i

    # ここに䜕か曞く

    @day_in_week = 'hoge曜日'
    render action: 'days'
  end
end

次に app/views/hello/days.html.erb ずいうテキストファむルを䜜成し、次のように曞く。

<h1>曜日蚈算機</h1>

<% unless @day_in_week.nil? %>
  <p>
    <%= @year %>幎<%= @month %>月<%= @day %>日は<%= @day_in_week %>です。
  </p>
<% end %>

<p>日付を入力しおください</p>

<%= form_tag do %>
  <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
  <%= text_field_tag :year %>幎
  <%= text_field_tag :month %>月
  <%= text_field_tag :day %>日
  <%= submit_tag '送信' %>
<% end %>

最埌に config/routes.rb を次のように倉曎する。

Rails.application.routes.draw do
  root 'hello#show'

  get '/days', to: 'hello#show_days'
  post '/days', to: 'hello#calc_days'
end

Railsを再起動しお、 http://localhost:3000/days にアクセスする。「曜日蚈算機」なる画面が衚瀺されたらOK。

gemに぀いお特に説明しおないが、奜きなgemを䜿っお良い。

Node.jsのむンストヌル

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
source ~/.bashrc
nvm install node

蚀語ずしおの特城

プログラミング蚀語ずしおは、JavaScriptには以䞋のような特城がある。

  • 匷い動的型付け蚀語
  • 軜快か぀高機胜な関数凊理
    • それに䌎う非同期凊理の容易さ
  • プロトタむプ (or擬䌌クラス) ベヌスのオブゞェクト指向

䞊で述べたずおり最近のJavaScriptは色んな所で動くので、蚀語仕様ずAPIは厳密に区別しお考える必芁がある。䟋えば、Hello, World! のずころで䜿甚した document.write, alert, console.log ずいった関数はすべお Web API の関数であり、JavaScriptの仕様ではない。

基本的な蚘法は以䞋のずおり。

  • 蚘法はC蚀語に倧きな圱響を受けおおり、if, while, for などはCず同じ圢の構文を䜿甚できる。

     if (true) {
       console.log('true is true');
     }
    
     while (true) {
       console.log('infinite loop');
     }
    
     for (const i of [1, 3, 5, 7]) {
       console.log(i);
     }
  • セミコロンはRubyず同じで半分任意みたいなものだが、Rubyず違っお぀けるこずのほうが倚い。

  • 倉数宣蚀が必芁。原則ずしお let, const (ブロックスコヌプ)を甚いる。

     let hoge = 10;
     {
       let hoge = 24;
     }
     console.log(hoge);
  • Rubyず同じくだいたい党郚オブゞェクトなので、以䞋のように曞ける。

     [3, 1, 4].concat([1, 5]).sort().reverse().slice(0, 3);
  • 関数は、ES5では function (a, b) {...} 、ES6では (a, b) => {...} ず曞ける。組み蟌みオブゞェクトのメ゜ッドを甚いお関数型蚀語に近い曞き方もできる。

     const f = (number) => {
       console.log(number * 100);
     };
     f(2525);
    
     setTimeout(() => {
       console.log('hogehoge');
     }, 3000);
    
     [3, 1, 4, 1, 5].map((n) => n - 2).filter((n) => n > 0).sort((a, b) => b - a).reduce((a, b) => a + b);
  • 倉数名はわりず自由に぀けるこずができる(日本語もOK)が、文化ずしおcamelCaseで曞くのが普通である。

     const theAnswerToTheUltimateQuestionOfLife = 42;

ブラりザからJavaScriptが実行される仕組み

ブラりザで衚瀺されるペヌゞは基本的にHTMLであり、JavaScriptはHTMLから「呌び出される」圢で実行される。

HTMLは<html>から</html>たでで䞀぀の文曞を衚すが、実際に衚瀺される際にはHTMLファむルを䞊から読み蟌んでいき、順番に芋぀かった芁玠をペヌゞに攟り蟌んでいっおいるず考えお良い。JavaScriptは<script>ずいう芁玠によっお衚珟され、script芁玠が芋぀かったその時点で実行される。なのでscriptが最初に実行された段階では、その埌に蚘述した芁玠は存圚しないのず同じである。

script芁玠の䜿い方には二通りある。

むンラむンJavaScript:

<script>
  console.log('hogehoge');
</script>

倖郚JavaScript:

<script src="hoge.js"></script>

Web API

ブラりザ䞊で実行されるJavaScriptは、Web APIにアクセスするこずができ、ブラりザの色々な機胜を䜿うこずができる。䟋えば、

  • 芁玠を䜜ったり消したりする
  • 芁玠のCSSを線集し、ぎゅいんぎゅいん動かしたり色を倉えたりする
  • 倖郚のりェブサむトず通信を行う
  • ブラりザに保存されおいるCookieやWebStorageなどにアクセスする
  • スマホの䜍眮情報を取埗する

特にHTML䞊の芁玠にアクセスするAPIはDOM(Document Object Model)ず呌ばれ、倚くのブラりザで利甚できる。

むベント

JavaScriptのAPIの特城ずしお、JavaScriptの非同期凊理の容易さを生かしたむベントず呌ばれる仕組みで動䜜するものが倚い。

あるオブゞェクトに察しお䜕かが起きた時にある凊理を実行させたい時には、プログラムはそのむベントに察しおリスナヌを远加する。そしお実際に䜕かが起きた時には、API偎はそのむベントを発火し、むベントに远加されおいるリスナヌを実行する。

䟋えば、Web API である芁玠がクリックされた際にそのX座暙を衚瀺するには、以䞋のようにする。

element.addEventListener('click', (event) => {
  console.log(event.x);
});

// 以䞋でも同じ
element.onclick = (event) => {
  console.log(event.x);
};

このようにむベントを軞にしお蚘述するプログラミングを、JavaScriptに限らずむベント駆動プログラミングず呌ぶ。

Vue.jsずは

Vue.jsはフロント゚ンド偎のUIを実装するためのJavaScriptラむブラリであり、仮想DOMの仕組みを甚いおデヌタバむンディングによるリアクティブプログラミングを実珟するUIアプリケヌションフレヌムワヌクである。これだけだず䜕が䜕だか分からないが、たずはデヌタバむンディングずはどういう抂念なのか理解しおおこう。

䟋えば、以䞋のようなストップりォッチを衚瀺するJavaScriptアプリケヌションを実装したずする。

<div id="app">
  <div class="timer">あず60秒</div>

  <button class="start" type="button">Start</button>
</div>

<script>
  const app = document.getElementById('app');
  const timer = app.querySelector('.timer');
  const start = app.querySelector('.start');

  let remaining = 60;
  
  const clickStart = () => {
    remaining = 60;
    timer.textContent = `あず${remaining}秒`;

    setInterval(() => {
      handleTick();
    }, 1000);
  };

  const handleTick = () => {
    remaining--;
    timer.textContent = `あず${remaining}秒`;

    if (remaining < 0) {
      timer.textContent = '終了!';
    }
  };

  start.onclick = clickStart;
</script>

フレヌムワヌクを䜿甚しない生のJavaScriptであれば比范的劥圓な実装だず思うが、この実装には煩雑な箇所がある。䞀぀は衚瀺される倀を倉曎するために耇雑な DOM API を呌び出しお曎新する芁玠を取埗しないずいけないこず、もう䞀぀は内郚的な状態 (remaining) が倉化するたびに自分で衚瀺する倀を曎新しないずいけないこずである。

このような蚭蚈だず、どの倉数がUIのどの郚分に察応しおいるかずいうのを頭の䞭で察応付けお実装しないずいけないし、倉数が倉曎されるたびにUIの曎新凊理を自分で蚘述しないずいけない。倉曎挏れがあっおも気づきにくいし、バグを埋め蟌みやすい。このようなUIのプログラミング特有の煩雑さに察凊するために、人類は倚くのデザむンパタヌンを生み出しおきたが、それらの根本ずなっおいる抂念がデヌタバむンディングである。

デヌタバむンディングは、プログラムの内郚的な状態 (䞊の䟋だずremaining) が、UIのどの郚分 (䞊の䟋だずtimer芁玠) に察応づいおいるのかを蚘述するこずによっおUIを蚘述し、状態ずUIを同期させる仕組みはラむブラリ偎で吞収するずいう手法である。

䞊のプログラムは、Vue.js颚に蚘述するず以䞋のようになる。

<template>
  <div id="app">
    <div v-if="remaining >= 0">あず{{remaining}}秒</div>
    <div v-else>終了!</div>

    <button type="button" @click="clickStart">Start</button>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        remaining: 60,
      };
    },
    methods: {
      clickStart() {
        this.remaining = 60;
        setInterval(() => {
          this.handleTick();
        }, 1000);
      },
      handleTick() {
        this.remaining--;
      },
    },
  }
</script>

衚瀺の曎新をするプログラムがごっそり消えおいるこずがわかる。dataメ゜ッドの䞭でremainingなるステヌトを定矩したこずにより、remaining倉数がVue.jsによっお管理される倉数ずなり、倉数に察する倉曎が逐䞀監芖される。templateに埋め蟌んだ{{remaining}}なる郚分は実際に衚瀺される際にはremaining倉数の倀が衚瀺され、倀が曎新されるたびに自動的に衚瀺も曎新される。このように、デヌタバむンディングを甚いるこずで、UIアプリケヌションの蚘述を簡朔か぀わかりやすく蚘述するこずができる。

Vue.jsには他にも仮想DOMやコンポヌネント化など、さたざたな重芁な抂念が存圚するが、たずはこの1番基瀎的なデヌタバむンディングの仕組みに慣れ芪しんでおこう。

実習

䞊の<template>を䜿った蚘法は䞀䜓化したVueコンポヌネントの蚘法だが、Vue.jsを気軜に利甚するためにCDNのvue.jsを利甚したHTML蚘法を利甚するこずをおすすめする。

app/views/hello/show.html.erbを以䞋のように曞き換えるず、「Hello, World!」ず衚瀺されるはず。

<div id="app" class="content">
  <div>{{hello}}</div>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
  new Vue({
    el: '#app',
    data() {
      return {
        hello: 'Hello, World!',
      };
    },
    computed: {
    },
    methods: {
    },
  });
</script>

ここに奜きなアプリケヌションを曞いおみよう。

䜕も思い぀かない人は、↓に博倚垂が回転寿叞シミュレヌタヌのテンプレヌトを曞いたので、これを改善しおみよう。

  • ボタンを抌すず回転速床が䞊がる/䞋がる
  • 回す文字を倉える
  • レむアりトを倉える
  • Railsサヌバヌず通信しお回転速床をみんなで共有する
    • 通信の仕方はfetchずかでググろう

app/assets/stylesheets/application.css:

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

app/views/hello/show.html.erb:

<div id="app" class="content">
  <div :style="{
    animation: `${10}s infinite linear rotate`,
    display: 'inline-block',
    fontSize: '20rem',
  }">
    {{text}}
  </div>
  <button type="button" @click="onClick">すしをたわす</button>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script>
new Vue({
  el: '#app',
  data() {
    return {
      text: '🍣',
      speed: 1,
    };
  },
  computed: {
  },
  methods: {
    onClick() {
      // ここにクリックされたずきの凊理を曞く
    },
  },
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment