Ruby型チェッカーSorbetの話

Sorbetとは決済サービスで有名なStripeがRubyC++製の型チェッカーである
そもそもなぜRubyに型チェッカーが必要かというとRubyは動的型付け言語であるので実行前に型のチェックが出来ると便利である
動的静的型付けについて詳しく説明するとプログラムを実行前に型検査を行うのが静的な型付け、静的型付けであり、プログラムを実行しながら型検査を行うのが動的な型付け、動的型付けである、なので動的型付け言語に型チェッカーを使うと静的型付け言語のように実行前に型検査することが出来る
例えばRuby

puts "hello"+1

とすると文字列型と整数型で合体できないと怒られる
なので

puts "hello"+1.to_s
puts "hello"+"1"

とすると型的にOK
しかしRubyより弱い動的型付けのjavascriptでは

 <script>
    window.alert("hello" + 1);
  </script>

だとOKになってしまう、弱いと緩くて強いと厳しい
弱いと表面上はエラーが出ないが安全性に問題がでる、これを型安全という

ここからSorbetの話
rubyの2.5.2以上じゃないとダメっぽい

gem "sorbet", :group => :development  
gem "sorbet-runtime"
$budle install

もしくは

$gem install sorbet sorbet-runtime

これでSorbetが使えるようになる

$srb tc hoge.rb


で指定ファイルの型チェックが出来る
プロジェクト全体にソルベするには

$srb 

でできる

Reactした話

最近Reactの基礎を教えてもらいました
ReactはVueなどに比べて学習コストが高いと聞いていたのですが、やってみたら思ったより簡単でした(教え方が良かったのが大きいですが...)
今回はReactの基礎について書きたいと思います

今のJS界で勢いのある三勢力としてVue.js、Anguler.js、React.jsが挙げられます。
ただこの3つの中でもReactは異質でVue、Angulerがフレームワークなのに対し、Reactはライブラリであるのでフレームワークと違い型にハマった書き方ではなく純粋なJSに近くフレキシブルに書けるというメリットを持ちます
環境構築などは省いて書いていきたいと思います(実際教えてもらった時はcodesandboxで書きました)

Hello World
index.jsに

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
  return (
    <h2>Hello World</h2>
  )
}

ReactDOM.render(<App />, document.getElementById('root'));

まずライブラリーをimport
constで変更不可の変数Appを設定、returnで中身を返します
中にHTMLを記述します。この中にHTMLを記述する独特な記法をJSXと言います

・色変更とMsg
index.jsの他にcomponentというフォルダを作成します(名称は通例でこれにする)
componentフォルダにMsg.jsファイルを生成
Msg.js

import React from "react";

const Msg = () => {
  return (
    <>
      <p style={{ color: "blue" }}>React</p>
    </>
  );
};

export default Msg;

index.js

import React from "react";
import ReactDOM from "react-dom";

import Msg from "./components/Msg";

const App = () => {
  return (
    <>
      <h2>Hello World</h2>
      <Msg />
    </>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
  • Msg.jsより解説

importでライブラリ利用
constで変数定義
export default Msg;でMsg変数を別ファイルでも使えるように

  • index.js解説

import Msg from "./components/Msg";でcomponentフォルダのMsg.jsを読み込み(Flaskでの別ファイルimportみたいな)
でMsgをDOMに
f:id:yusukeisizaki:20190724183934p:plain
こんな感じなったら良き

・propsを使って色変更
現在DOMに直接styleから色を変更しているのがダサいため、propsを使って色を変更していきます
propsとは「親コンポーネントから渡されたプロパティ」のこと、要は親要素から渡されたpropsにより振る舞いが変わる
またもcomponentフォルダにCororfulMsg.jsファイルを作成
CororfulMsg.js

import React from "react";

const Msg = props => {
  return (
    <>
      <p style={{ color: props.color }}>{props.message}</p>
    </>
  );
};

export default Msg;

index.js

import React from "react";
import ReactDOM from "react-dom";

import ColorfulMsg from "./components/ColorfulMsg";

const App = () => {
  return (
    <>
      <h2>Hello World</h2>
      <ColorfulMsg color="blue" message="React" />
      <ColorfulMsg color="green" message="Vue" />
      <ColorfulMsg color="red" message="Angular" />
    </>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));

CororfulMsg.jsから解説すると
const Msg = props => {  = props =>の部分でpropsを変数として代入している、=>アローの前に変数をおく

{props.message}

で変数propsをDOMに反映、基本{}でDOM内に変数を埋め込める(jinaja2みたいな感じ)
index.jsでは
import ColorfulMsg from "./components/ColorfulMsg"; で読み込んでる

・stateを使ったカウントボタン
stateとはpropsと同じで変数のように使ってDOMに変化をつけるもの
propsとは違いstateは「そのコンポーネントが持っている状態を変化させる」
index.jsで

import React from "react";
import ReactDOM from "react-dom";

import ColorfulMsg from "./components/ColorfulMsg";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  handleClick = () => {
    const newcount = this.state.count + 1;
    this.setState({ count: newcount });
  };

  render() {
    return (
      <>
        <h2>Hello World</h2>
        <ColorfulMsg color="blue" message="React" />
        <ColorfulMsg color="green" message="Vue" />
        <ColorfulMsg color="red" message="Angular" />
        <button onClick={this.handleClick}>{this.state.count}</button>
      </>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

でカウントボタンの作成
{this.state.count}でstate変化させる

f:id:yusukeisizaki:20190724194655p:plain
最終的にこんな感じになっていればOK

RubyのAction Cableで簡易チャットの作成(Ruby関西)

Ruby関西というイベントに参加してきました

そこで講演の1つにActionCableを使ってライブ配信にチャット機能をつけた話があったのでそれについて

youtube.Liveやその他サービスではチャット付きライブ配信であんまり良くないらしい、なので配信システムを自作したというお話でした

概要としては

HLS + video.js で動画配信
RailsのActionCableを使いチャット機能を作る
という感じ

 

・環境構築
Rails6は正式リリースまだだけど使ってみる

$gem install rails --pre

yarnも入れておく

rails new

$rails new chat -$(date+%Y%m%d) --webpack=react

rails newの後で

$bin/rails webpacker:install:react

・埋め込みページ作成

$rails g controller pages index

routes変更

root to: 'pages/index'

app/views/pages/index.html.erbにReactの呼び出し埋め込み

<%= javascript_pack_tag 'hello react' %>

・channelの作成

$rails g channel chat

ChatChannelクラスができる

$rails g channel chat speak

などでメソッドも生成可能

・送受信準備(Rails)
ChatChannelに

def receive(data)

を追加

ActionCable.server.broadcast('chat_chnnel',data)

subscriveで

stream_from 'chat_channel'

・送受信準備(JS)
chat_channel.jsにて
received(data)に

console.log(data)

consoleから送信を確認できる

・アイコン表示
おなじみgravater

・モデル

$rails g model message name body sent_at:timestamp
$rails g job MessageBroadcast

broadcastをjob経由に

こんな感じ行けるらしい

LINEBot作成ハンズオンに行った話(LINEBot編)

前回でAmazonConnectの電話番号を取得したところからスタート

 

Lambda関数の作成

  1. AWSのサービスよりLambdaを選択
  2. Lambdaの関数作成をクリック
  3. 関数作成の項目を埋めていく(関数名:AmazonConnect-BMI、実行ロール:AWSポリシーテンプレートから新しいロールを作成、ロール名:AmazonConnect-Role、ポリシーテンプレート:基本的なLambda@Edge のアクセス権限) →右下の「関数の作成」をクリック
  4. Lambdaのindex.jsを以下のように書き換える
  5. exports.handler = async (event) => {
        // 身長と体重を取得する
        const heightVal = event.Details.ContactData.Attributes.HeightVal;
        const weightVal = event.Details.ContactData.Attributes.WeightVal;
        
        // BMI計算
        const bmiVal = (parseFloat(weightVal) / (parseFloat(heightVal)/100 * parseFloat(heightVal)/100)).toFixed(1);
    
        // 標準体重
        const stdWeight = (22 * (parseFloat(heightVal)/100 * parseFloat(heightVal)/100)).toFixed(1);
    
        var speechText = `あなたのBMIは${bmiVal}です。標準体重は${stdWeight}kgです。`;
    
        return {"BMI": speechText};
    };
  6. 以上でLambdaの作成は終了、次はLambdaをAmazonConnectに適応

 

LambdaをAmazon Connectに適用する

  1. AWSのサービスからAmazonConnectにいく
  2. 左サイドメニューより「問い合せフロー」
  3. AWS Lambdaの項目より「AmazonConnect-BMI」を選択し、[追加]ボタンをクリック →プルダウンメニューの下に追加される
  4. 左サイドメニューより「概要」
  5. [管理者としてログイン]をクリック→管理者ページへ
  6. 左サイドメニューより「問い合せフロー」
  7. [問い合わせフローの作成]をクリック→名前を「BMIフロー」
  8. [問い合せフローエディタ]の[設定]カテゴリより[音声の設定]→右マス目にドラッグ&ドロップ→ドロップしたブロックをクリック→エントリポイントの白丸と左半円を接続
  9. [音声の設定]クリック(言語:日本語、音声:Takumi)
  10. [問い合せフローエディタ]の[操作]カテゴリより[顧客の入力を保存する]→右マス目にドラッグ&ドロップ→ドロップしたフォルダをクリック→前回作成したブロックの成功白丸と左半円を接続
  11. [顧客の入力を保存する]クリック(テキスト読み上げ機能:テキストの入力:「あなたのBMIをお答えします。身長をセンチで入力してください。」、カスタム最大桁数:3)→左下Save
  12. [問い合せフローエディタ]の[設定]カテゴリより[問い合わせ属性の設定]→右マス目にドラッグ&ドロップ→ドロップしたフォルダをクリック→前回作成したブロックの成功白丸と左半円を接続
  13. [問い合わせ属性の設定]をクリック(宛先キー:HeghtVal、タイプ:システム、属性:保存済みのお客様の入力)→左下Save
  14. [問い合せフローエディタ]の[操作]カテゴリより[顧客の入力を保存する]→右マス目にドラッグ&ドロップ→ドロップしたフォルダをクリック→前回作成したブロックの成功白丸と左半円を接続
  15. [顧客の入力を保存する]クリック(テキスト読み上げ機能:テキストの入力:「続いて、体重をキログラムで入力してください。」、カスタム最大桁数:3)→左下Save
  16. [問い合せフローエディタ]の[設定]カテゴリより[問い合わせ属性の設定]→右マス目にドラッグ&ドロップ→ドロップしたフォルダをクリック→前回作成したブロックの成功白丸と左半円を接続
  17. [問い合わせ属性の設定]をクリック(宛先キー:WeightVal、タイプ:システム、属性:保存済みのお客様の入力)→左下Save
  18. [問い合せフローエディタ]の[統合]カテゴリより[AWS Lambda 関数を呼び出す]→右マス目にドラッグ&ドロップ→ドロップしたフォルダをクリック→前回作成したブロックの成功白丸と左半円を接続
  19. [AWS Lambda 関数を呼び出す]をクリックし[関数を選択する]で[AmazonConnect-BMI]設定→左下Save
  20. [問い合せフローエディタ]の[操作]カテゴリより[プロンプトの再生]→右マス目にドラッグ&ドロップ→ドロップしたフォルダをクリック→前回作成したブロックの成功白丸と左半円を接続
  21. [プロンプトの再生]をクリックし(テキスト読み上げ機能:テキストの入力:「
    $.External.BMI
    」)→左下Save
  22. [問い合せフローエディタ]の[終了/転送]カテゴリより[切断/ハングアップ]→右マス目にドラッグ&ドロップ
  23. 未接続ノード(今回は[エラー]ノード)を全て[切断/ハングアップ]に接続する
  24. 右上の[保存]と [公開] ボタンをクリック
  25. 左サイドメニューより[電話番号]を選択→[電話番号の管理]画面→電話番号をクリック
  26. 電話番号の編集→問い合せフロー[BMIフロー]→保存

 

以上で完成です

AmazonConnectで登録した電話番号に電話をかけて、身長と体重の値を入力すればBMI値が帰ってくれば成功です

以下問い合せフロー図

f:id:yusukeisizaki:20190716082116p:plain


 

LINEBot作成ハンズオンに行った話(AmazonConnect電話番号取得編)

先日さくらのVPSで有名なさくらインターネットさんにお邪魔してLINEBotハンズオンイベントに参加しました。このイベントはAWSとLINEデベロッパーを用いてLINEBotを作成してみようというイベントでした。LINEBotの作成は手順に沿って作成していけば簡単に作成でき、ほとんどコーディングもない(今イベントでは事前に見本が用意されていた)ので非エンジニアの方でもサクサク作成していた。

今イベントでは

・AmazonConnectを用いた問い合わせ対応Bot

・LINE Developersを組み合わせたチャット&問い合わせBot

の作成を行った

今記事では2つを作成する際の下準備と問い合わせ対応Botの作成について書いていこうと思う

 

<下準備編>

LINEBot作成に置いて必要になってくるのが

AWSアカウント

・LINEアカウント

・電話

の3つです。これを用意した後にBot作成に進む

 

Amazon Connectの電話番号を取得する

AWSよりConnectの電話番号を取得してその番号から電話がかかってくる様にする

以下の手順で取得を行う

まずはリソースの生成を行う

  1. AWSアカウントにログインする
  2. 左上のサービスから「Amazon Connect」と検索してページに
  3. 最初の画面の中央した[今すぐ始める]ボタンをクリック
  4. 右上のリージョンを[アジアパシフィック(東京)]を選択
  5. AmazonConnectリソース設定を行う(アクセスURLは好きなもの、管理者の作成は「これをスキップ」、テレフォニーオプションとデータストレージはそのまま、これで「インスタンスの作成」
  6. 1~2分で生成され「今すぐ始める」をクリック

次に電話番号の取得を行う

  1. 先ほどの[今すぐ始める]でAmazonConnectに遷移する
  2. また[今すぐ始める]
  3. [電話番号の取得]をクリック(国[日本]、タイプ[DirectDilal,TollFreeどちらでも良い]、電話番号は好きなものを)
  4. [次へ]→[continue]
  5. サイドメニューから[電話番号]をクリック(取得した電話番号を確認する)
  6. 電話番号の管理画面に先ほど取得した番号があればOK

 

これで下準備完了。この取得した電話番号を使ってBotの作成を行っていきます。問い合せBot、LINEBotについてはまた別の記事で、気が向いたら...

Rails新機能ActionText

Rails6より新機能としてActionTextが実装された。

内容としては入力フォームを作る際に斜体や太文字などリッチなフォーム、ちょうどHatenaBlogの入力画面の様なフォームを作成することができる。実際に作ってみたがとても簡単に実装することができた、ていうかRailsを6にすることの方がアホみたいに時間がかかった。今回はRailsのバージョンを6にするところから記事にしていきたいと思います。写真は完成形

f:id:yusukeisizaki:20190710163458p:plain

<Railsのバージョン上げ>

他のバージョンに上げる方法が自分はできなかったためRails6へのバージョンアップは別の方法をとりました

githubrails/railsより $git clone https://github.com/rails/rails.git もしくはgithubのホームページよりダウンロードzip

・$./rails/railties/exe/rails new アプリ名 --edge でアプリを作成する。このコマンドでrails関連のファイルの生成とRails6からのwebpackerのセットアップが完成する

・$bundle install

 

<Action Textを使う>

・$ ./bin/rails action_text:install でActionTextのインストールができる。

このコマンドで

  • app/assets/stylesheets/actiontext.scss
  • test/fixtures/action_text/rich_texts.yml
  • app/views/active_storage/blobs/_blob.html.erb
  • db/migrate/20191234567890_create_active_storage_tables.active_storage.rb
  • db/migrate/20191234567890_create_action_text_tables.action_text.rb

のファイルが生成される。ActionTextではActionTextエリアで編集される情報を別テーブルに切り分けて行う(ActiveStrageと似た考え)

・rake db:create でデータベース作成

・$rake db:migrate でマイグレーション

・$rails g scaffold モデル カラム:string でスキャフォールディングする。

今回は$rails g scaffold post title:string とする

・再び $rake db:migrate

 

・app/models/post.rb にActionText用のアソシエーションを書く

 >|ruby|

class Post < ApplicationRecord

 has_rich_text :content 

end

||<

 

app/controllers/posts_controller.rb コントローラーに追記

def post_params

 params.require(:post).permit(:title, :content)

end

ストロングパラメーターでtitleしか許可されていなかったものをcontentも許可する

 

app/views/posts/_form.html.erb 入力フォームを編集する

 

<div class="field">

  <%= form.rich_text_area :title %>

</div>

form.rich_text_areaで特殊編集可能なフォームができる

 

・viewに結果を表示させてみる

ActionTextの結果を反映させたい<%= @post.title %> を<%=@post.content %>に書き換える

 

以上でAction Textの実装が完成します。

思ったより簡単に実装できた様には感じましたが、正直なところブログくらいしか使い所なくないかとも思いました。Rails6による大幅改修はワクワクする様なよくわからない様な感じ

 

 

Rails6のバージョンアップについて

最近WEB+DB PRESS vol.111を読んで今さらながらRais6に気づいたので、Rails6の新機能をブログにまとめようと思います

ていうかバージョン上げよう...

 

・ActionMailbox

名前の通りメールができる機能、

メールの受信はもちろん転送や返信、

プロバイダの指定、

取得した情報をデータベースに保存などが出来る

 

・ActionText

テキストの編集機能を追加出来る新機能、

wordとかexcelとかhatenablogみたいな書式編集が出来る、

ドラッグアンドドロップで画像の追加が出来る、

form.rich_text_areaで簡単に作成、本当にリッチ

 

・複数データベース

database.ymlで指定することで指定された複数のデータベースに保存されるようになる

 

Zeitwerk

Zeitwerkという効率的で早いオートロードシステム

実行順序に依存するオートロード定数のエッジケースも解消

名前空間にあるものは遅延される

 

ActiveRecord: :Relation#pick

whereやlimitを使っていた検索をpickで行える

例えばUserテーブルからageが20より多いのもののidを取得する時rails6では

User.where("age>20").limit(1).plunk(:id).first が

User.where("age>20").limit(1).pick(:id) となる

 

・create_or_find_byメソッド

レコードがなければ作成を行い、レコードがあれば作成しないメソッドに従来は find_or_create_by メソッドを使っていたが、 find_or_create_by ではSQLのSELECTからINSERTを行う際に時間差があるため、その間にSELECTで取得したレコードが古くなってしまう問題があった

create_or_find_byメソッドではINSERTを行い、ユニーク制約のエラーが発生した場合は、SELECTでレコードを取得する

create_or_find_byの注意点としてメソッドを使用する際には、あらかじめユニーク制約を設定する必要があること、レコードの作成よりも参照が多い場合は処理自体が遅くなる可能性があること、また、レコードが作成できない場合の例外がある

 

 

・insert_allメソッド

複数件のレコードを一括でINSERTできるメソッド

今まではBULK INSERTという方法を使っていた

 

他にもまだまだアップデートした点はある様

変更点の多さから今回は特に大きなアップデートだったとわかる

Railsはどんどん便利になっていくと感じた