WESEEK Tech Blog

WESEEK のエンジニアブログです

初心者向け Rails Web アプリ開発でよく使う gem 一覧

この投稿は、弊社が提供するWESEEK TECH通信の一環です。
WESEEK TECH通信とは、WESEEKのエンジニアがキャッチアップした技術に関する情報を、techブログを通じて定期的に発信していくものです。

はじめに

はじめまして、システムエンジニアの蛸井です。
Rails での Web アプリケーション開発において欠かすことのできない gem について、必須級なものからマイナーなものまでよく使う順で一挙ご紹介します。

まず gem とは何か

gem とは Ruby で書かれたパッケージのことを指します。
パッケージとは、ある特定の機能を持ったコンピュータプログラムを他のプログラムから呼び出して利用できるように部品化し、そのようなプログラム部品を複数集めて一つのファイルに収納したものです。

一般的には bundler というパッケージ管理システムを用いて gem を管理します。
bundler は Node.js でいう npm に該当します。

パッケージを用いることで必要な機能を1から実装する必要がなくなるため、開発効率が大きく向上します。
多くの gem パッケージが RubyGems で管理されており、以下のサイトから gem の検索を行うことができます。 rubygems.org

ちなみに自分で作成した gem を公開することも可能です。

よく使う gem 一覧

rspec-rails

rspec-rails とは RSpec と呼ばれるテストフレームワークRuby on Rails に導入する gem です。
RSpec を用いることによりコマンドの実行でテストの実行を行うことができます。
クラスやメソッド単位でテストを行うことができるため扱いやすいです。

github.com

factory_bot_rails

factory_bot_rails はテストのサンプルデータを簡単に作成することができるメソッドを提供してくれる gem です。
そのため、rspec-rails とセットでよく使われます。

github.com

rubocop

rubocop は Ruby の静的コード解析をする gem です。
実行することで Ruby コードをチェックすることができ、コードを整形したり警告を出してくれます。

例えばインデントを空け忘れると実行時にこのような警告を出してくれます。

Gemfile:44:25: C: Layout/SpaceAfterColon: Space missing after colon.
  gem 'rubocop', require:false
                        ^

github.com

pry-rails

pry-railsRails 用に使われるデバックツールです。
コード内に binding.pry を記述した行で処理を中断させ、その行でコンソールと同じ操作を行うことができます。

github.com

activeadmin

activeadmin は簡単に管理画面を作りたいときに使える gem です。
activeadmin を用いることで、モデルの CRUD(Create, Read, Update, Destroy) 画面を非常に簡単に作成することができます。
デフォルトの設定だとこんな感じの画面を作成できます。 f:id:atsuki-t:20210717170317p:plain

github.com

cancancan

cancancan は権限周りの管理をする gem です。
特定のユーザーのアクセスを制限したり、画面ごとに表示可能な権限を設定することができます。

github.com

devise

devise はアカウント登録、ログイン、ログアウトなどの認証機能を追加できる gem です。
これにより簡単に安全な認証機能を実装できます。パスワード変更や、メール認証の機能もあります。

github.com

annotate

annotate はファイルにモデルの情報をコメントとして書き出してくれる gem です。
どんなカラム構成になっているかひと目で分かるため非常に便利です。

# == Schema Info
#
# Table name: line_items
#
#  id                  :integer(11)    not null, primary key
#  quantity            :integer(11)    not null
#  product_id          :integer(11)    not null
#  unit_price          :float
#  order_id            :integer(11)
#

class LineItem < ActiveRecord::Base
  belongs_to :product
end

github.com

bullet

bullet はアプリケーションの開発中にクエリを監視し、N+1 問題が発生した時に通知をします。
N+1 問題というのは、ループ処理の中で余分なクエリを発行してしまいパフォーマンスが低下してしまう問題のことです。 これを解消しアプリケーションが行うクエリの数を減らすことで、アプリケーションのパフォーマンスを向上させることができます。

github.com

rails-i18n

rails-i18nロケールファイルに翻訳ファイルを設置することで、 Web アプリケーションを国際化(internationalization)させることができます。

github.com

dotenv-rails

dotenv-rails を導入することで環境変数を扱えるようになります。
プロジェクトのルートディレクトリに .env ファイルを用意し、ここに変数を定義することで自動で読み込まれます。

github.com

kaminari

kaminari はページネーション機能を簡単に実装できる gem です。

github.com

whenever

whenever は crontab を管理する gem です。 whnever を使って cron を作成することで、rake task などのジョブを定期的に実行できるようになります。

github.com

まとめ

今回は 14 個の gem を紹介させていただきました。
どれも Web アプリケーション開発においてはよく使う gem となっていますので、是非使ってみてください。

企業を超えた アジャイル+Railsを 利用した開発の成功事例

この記事は、2021/7/21 に行われた WESEEK Tech Conference の内容です。

f:id:skomma:20210731055818j:plain

今回の WESEEK Tech Conference は、WESEEK が開発案件を担当させていただいている、インターネットマルチフィード株式会社(以下「MF社」と表記) 杉本氏を迎えて WESEEK 武井、今間の 3 人の対談形式で行いました。

社内に開発部隊が存在しなかった MF 社に存在していた課題から、WESEEK がジョインし開発部隊を作り、アジャイルRails を利用し、どのように課題を解決していったのかをご紹介します。

目次

  • 目次
  • MF と WESEEK
    • インターネットマルチフィード(株)とは?
    • IXP/JPNAP とは?
    • JPNAPにおける自動化のあらまし
    • (株)WESEEKとは?
  • 当時(2015年頃)のMFにおける課題
    • 社内ツール事情
    • 課題一覧
  • 課題へのアプローチ(序盤編)
    • 初期フェーズでやったこと
      • 技術選定
      • 開発/フィードバックをやり取りするためのツールを導入
      • 開発スタートアップの整備
    • 今までの開発してきたプロダクト一覧
  • WESEEK ジョイン後の課題
  • Rails を利用したチーム開発
    • 実際の開発における課題
    • 開発/リリースフロー
    • デプロイ先環境
    • 技術的負債を作らないために
      • 利用 gem の選択基準
      • ライブラリ/実行環境の継続アップデート実現
    • My.JPNAP 公開へ
  • 技術的負債への対応
  • まとめ
  • Appendix: 利用 gem ご紹介
    • 著者プロフィール
  • 株式会社WESEEKについて
    • GROWI
    • GROWI.cloud
    • WESEEK Tech Conference
  • 一緒に働く仲間を募集しています
続きを読む

VercelでNext.jsを簡単デプロイ

この投稿は、弊社が提供するWESEEK TECH通信の一環です。 WESEEK TECH通信とは、WESEEKのエンジニアがキャッチアップした技術に関する情報を、techブログを通じて定期的に発信していくものです。

今回は、 Next.js で開発したアプリケーションをデプロイする方法を紹介します。 Vercel を使用し、簡単にアプリケーションのデプロイを行ってみたいと思います。

Vercel とは

f:id:Aqutam:20210728002125p:plain

Next.js を開発している Vercel Inc. が提供しているサーバーレスプラットフォームです。 これを利用して手軽に Next.js アプリケーションをデプロイできます。 個人的な非営利目的の使用であれば、クレジットカードの事前登録は不要で、無料で利用できます。

詳しくは下記を参照してください。

続きを読む

CSS を JavaScript に記載する!Next.js で CSS-in-JS を使う方法

この投稿は、弊社が提供するWESEEK TECH通信の一環です。 WESEEK TECH通信とは、WESEEKのエンジニアがキャッチアップした技術に関する情報を、techブログを通じて定期的に発信していくものです。

前回までのおさらい

tech.weseek.co.jp

前回の記事では Next.js のセットアップと Build-in でサポートされている CSS の方法を紹介しました。

Next.js はセットアップすると煩わしい設定をすることなく CSS を書けます。
また、スコープを狭めた CSS Modules の記載方法もご説明しました。

今回の記事では前回の記事で実現する環境と同じ状況で CSS-in-JS の説明をします。

続きを読む

【React Hooks】今日から使える! useEffect について基礎から理解しよう

この投稿は、弊社が提供するWESEEK TECH通信の一環です。 WESEEK TECH通信とは、WESEEKのエンジニアがキャッチアップした技術に関する情報を、techブログを通じて定期的に発信していくものです。

はじめに

はじめまして、システムエンジニアの渡嘉敷です。株式会社 WESEEKでインターンを経て新卒で入社、普段の業務では OSSである GROWI の開発を行っています。どうぞよろしくお願いいたします。

記念すべき初稿は、React Hooksの中でも主要で使用頻度の高い useEffectについてまとめてみました!

useEffect とは

  • レンダーの結果が画面に反映された後に実行される関数です。

  • クラスコンポーネントにおけるライフサイクルメソッドにあたります。 componentDidMount / componentDidUpdate / componentWillUnmount

  • 関数コンポーネント内で、副作用(DOMの書き換え、変数代入、API通信などの処理など)を実行することができます

副作用に関してわかりづらい場合は、Reactにおける「副作用」とは?を一読しておくと良いでしょう

import React, {useState, useEffect} from 'react';

const UseEffectExample = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>The current count is {count}</p>
      <button onClick={() => setCount(count + 1 )}>+1</button>
      <button onClick={() => setCount(0)}>reset</button>
      <button onClick={() => setCount(count + 1 )}>+1</button>
    </div>
  )
}

export default UseEffectExample;

useStateを使ってcountのstate変数を設定しボタンをクリックする度にCount数が増えるコードを作成します。 変数countには初期値で0が指定されており、-1ボタンを押すとマイナス1、+1ボタンを押すとプラス1づつ増えていく。また、resetボタンを押すと0に戻るという仕組みのカウント機能を元に説明します。

1. 第二引数に何も渡さない場合

  useEffect(() => {
     console.log('useEffect ran');
  })

この場合、「毎回のレンダリング後」に実行されます。

2. 第二引数に空の配列を渡す場合

  useEffect(()=>{
    console.log('This should only run once')
  }, [])

第二引数に空の配列を記載した場合、「一番最初のレンダリング後」にのみ実行されます。

3. 第二引数に何らかの値(変数等)を渡す場合

  useEffect(() => {
     console.log('useEffect ran');
  },[count])

この場合、「一番最初のレンダリング後」と「第二引数に指定したstateもしくはpropsの値が変更した時」に実行されます。今回の例でいうと、最初のレンダリング後に加え、countの値に変更が生じた時に実行 されます。

第二引数の配列に具体的な値を指定してあげることで、実行されるタイミングを限定できます。これによって、不要なレンダリングが減るのでパフォーマンスの改善につながります!

クリーンアップ関数

クリーンアップ関数とはaddEventLitenerの削除、タイマーのキャンセルなどに使われます。

useEffectでクリーンアップ関数をreturnすることで、2度目以降のレンダリング時に前回の副作用を消すことができます。

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },
  [props.source],
);

(※ソースコードは、React 公式ドキュメントから抜粋しています)

useEffect を使用する際のTips!

クラスコンポーネントのライフサイクルでは、ライフサイクルメソッドに関係のないロジックが含まれてしまったり、関連のあるロジックが複数のメソッドに分離してしまったりすることがあります。 以下の例では、document.titleが ComponentDidMount と ComponentDidUpdateに分離してしまっています。

class FriendStatusWithCounter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0, isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }
  // ...

上記で述べた問題点は、フックを使用することで解決できます。

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  // ...
}

ライフサイクルではなく、何を行うのかによってコードを分割 できます。 関連のあるロジックで処理を分けるので、わかりやすいだけでなく無駄なレンダリングを減らすこともできます。

(※ソースコードReact 公式ドキュメントから抜粋しています)

おわりに

useEffectはReact Hooksの中でも特に使うシーンが多いので、しっかりと動作を理解して使用しましょう!

参考にさせていただいたサイト

Rails 6でBlocked hostエラーが発生したときの対処法

この投稿は、弊社が提供するWESEEK TECH通信の一環です。 WESEEK TECH通信とは、WESEEKのエンジニアがキャッチアップした技術に関する情報を、techブログを通じて定期的に発信していくものです。

エラーの内容

Rails 6 で、任意の host 名を指定してアクセスをしようとしたとき、下記のようなエラーが表示されることがあります。

Blocked host: hogehoge-host.com
To allow requests to hogehoge-host.com, add the following to your environment configuration:
    config.hosts << "hogehoge-host.com"

原因

Rails 6 から追加された、DNSバインディング攻撃を防止する ActionDispatch::HostAuthorization middleware によるものです。

下記の Pull Request で実装されました。

Guard against DNS rebinding attacks by permitting hosts by gsamokovarov · Pull Request #33145 · rails/rails · GitHub

DNSバインディング攻撃とは

攻撃者が、悪意のある Web サイトにユーザーを訪問させ、クライアント側でスクリプトを実行させます。 このとき、攻撃者は短時間にドメイン (FQDN) に対する IP アドレス (Aレコード) を脆弱性のある Web サイトに変更します。 FQDN は変化していないため、同一生成元ポリシーは保たれ、攻撃者の用意したスクリプトで、脆弱性のある Web サイトに対して攻撃を仕掛けることができます。

DNS rebinding - Wikipedia

対処法

1. Rails.application.config.hosts に接続先として許可する Host を追加する

development 環境では、 default で Rails.application.config.hosts に下記の Host が登録されています。 これ以外の Host 名として接続しようとすると、ブロックされるため、必要な Host 名を追加します。

 Rails.application.config.hosts = [
   IPAddr.new("0.0.0.0/0"), # All IPv4 addresses.
   IPAddr.new("::/0"),      # All IPv6 addresses.
   "localhost"              # The localhost reserved domain.
 ]

追加方法は、 development 環境であれば、 config/environments/development.rb に下記のように記述します。

Rails.application.configure do
    config.hosts << "hogehoge-host.com"
end

2. Rails.application.config.hosts の設定を clear する

Rails.application.config.hosts は、空の場合は Host ヘッダーのチェックが行われないため、ブロックされなくなります。 development 環境以外の環境 (たとえば production ) では、 Rails.application.config.hosts は default で空のため、チェックは行われません。

development 環境で Host ヘッダーのチェックを行わないようにするには、 config/environments/development.rb に下記のように記述します。

Rails.application.configure do
    config.hosts.clear
end

なお、アプリケーションの前段に Host ヘッダーを識別して振り分けを行う LB 等がない場合は、DNSバインディング攻撃が防止できなくなるため、 development 環境以外では Rails.application.config.hosts を適切に設定されることをおすすめします。

3. ActionDispatch::HostAuthorization middleware を使わないようにする

アプリケーションの前段に Host ヘッダーを識別して振り分けを行う LB 等があり、アプリケーション自体でDNSバインディング攻撃を防止する必要がない場合は、 ActionDispatch::HostAuthorization middleware 自体をロードされないように設定します。

config/application.rb に下記のように記述します。

module HogeApp
  class Application < Rails::Application
    onfig.middleware.delete ActionDispatch::HostAuthorization
  end
end

まとめ

アプリケーションの前段に、 DNSバインディング攻撃を防ぐ機構がある場合は、対処法 2 or 3 を、そうではない場合は対処法 1 を実施します。

煩わしい設定は一切なし!Next.js で CSS を使う方法

この投稿は、弊社が提供するWESEEK TECH通信の一環です。 WESEEK TECH通信とは、WESEEKのエンジニアがキャッチアップした技術に関する情報を、techブログを通じて定期的に発信していくものです。

はじめに

今、フロントエンド界隈では、Next.js が流行っています。 その原因の一つに圧倒的な開発体験の良さがあります。 Next.js では開発環境を整えるための設定は全く必要ありません。

今回の記事では、そんな開発体験の良さを感じてもらうべく、Next.js で CSS を使う方法を説明したいと思います。

Next.js のバージョンを v11.0.1 で説明していきます。

続きを読む