Webとデザインのあれこれ

プログラミングとUIデザインの学習記録です。

deviseの導入について

deviseについて

deviseはユーザー認証用のgemです。こちらを利用して、ログイン・ログアウト機能やアカウントの登録機能をBookアプリに実装します!

devise利用の手順

導入の手順は意外とシンプルです。

  1. Gemfileに追加
  2. generatorを実行
  3. デフォルトURLの設定
  4. Userモデルのセットアップ
  5. テンプレート編集
  6. Controller編集

1. Gemfileに追加

# Gemfile
gem 'devise'

この後、bundle installを実行します。

2. generatorを実行

rails generate devise:installでインストールは完了。

3. デフォルトURLの設定

デフォルトURLのセットアップは、config/environments/development.rbに以下を追加。

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

4. Userモデルのセットアップ

ユーザー機能を実装するので、以下のコマンドのMODELの部分をUserに置き換えて実行します。モデル名はお好みで変更しましょう。

$ rails generate devise MODEL

以下のコマンドを忘れずに!

$ rails db:migrate

5. テンプレートの編集

成功した場合に表示されるnoticeと失敗した場合に表示されるalertを埋め込みます。

# app/views/layouts/application.html.erb

<% if notice %>
  <p class="alert alert-success"><%= notice %></p>
<% end %>

<% if alert %>
  <p class="alert alert-danger"><%= alert %></p>
<% end %>

また、ログインのリンクなども追加します。

# app/views/layouts/application.html.erb
<p class="navbar-text pull-right">
  <% if user_signed_in? %>
    Logged in as <strong><%= current_user.email %></strong>.
    <%= link_to 'Edit profile', edit_user_registration_path, class: 'navbar-link' %> |
    <%= link_to "Logout", destroy_user_session_path, method: :delete, class: 'navbar-link'  %>
  <% else %>
    <%= link_to "Sign up", new_user_registration_path, class: 'navbar-link'  %> |
    <%= link_to "Login", new_user_session_path, class: 'navbar-link'  %>
  <% end %>
</p>

こちらのテンプレートの内容はRails Girls Guideを参考にしております。 リンク先の名称や配置などはお好みで変更してください!

6. Controllerの編集

deviseでは、Controllerやviews内で複数のヘルパーを利用することが可能です。

ログインしていない場合、本の登録内容が確認できないように以下の記述をコントローラーに追加します。

# app/controllers/application_controller.rb
before_action :authenticate_user!

以上がデフォルトの利用手順となります。

言語化について

deviseで実装したログイン画面を日本語化したい場合におすすめのgemがあります。 それがこちら。

github.com

利用方法は、Gemfileに追加してbundle install実行。

gem 'devise-i18n'

基本はこれだけでOKです!(この記事はi18nの利用を前提としています。)

カスタマイズ方法

公式にも記載があるのですが、deviseではviewsやControllerを追加したり変更したりしてカスタマイズが可能です。 また、DBにカラムを追加することももちろん可能です。

例えば、UserモデルのControllerを追加したい場合は、以下コマンドを実行します。

$ rails g devise:controllers users

そうすると、app/controllers/users内にControllerが作成されます。

f:id:b_leiu:20190512194557p:plain

そして、対応するルーティングの設定を下記のようにconfig/routes.rbで設定します。

devise_for :users, :controllers => {
 :registrations => 'users/registrations',
 :sessions => 'users/sessions'
}

上記は、registrations_controller.rbとsessions_controller.rbのルーティングを記述しています。

同様にviewsも以下のコマンドで生成できます。

$ rails generate devise:views users

追記(2019/05/17)

カスタマイズしたviewsの翻訳について

以下のコマンドを実行すると、devise-i18nのviewsファイルをコピーしてくれるため、その内容を各自で修正することも可能です。

$ rails g devise:i18n:views 

注意点として、こちらのコマンドを実行すると将来的にviewsの内容が変更されたり、アップデートされた場合もその分が反映されないというリスクがあります。

デフォルトのdevise-i18nのviewsを使用するのが無難かと思います。


Strong Parametersについて補足

deviseでユーザーの認証機能を実装する際に、nameなどの新カラムをDBに追加したい場合があるかと思います。

ところがrails g migration AddNameToUsersを実行しようとすると、カラムを追加できない(エラーが発生する)場合があります。

理由はStrong Parametersというセキュリティ機能があるからです。

Strong ParametersとはDBに登録できるパラメーターに制限をかける仕組みのことです。

ブラウザがHTMLのソースを書き換える機能を備えていることから、マスアサインメント脆弱性というセキュリティホールができる可能性を孕んでおり、この対策としてRails 4.0で導入された機能です。

では新しいカラムを追加したい場合どうすればいいのでしょうか?

公式に書かれていますね! f:id:b_leiu:20190517123629p:plain

フィルターを記述してあげればいいのですね。一件落着です。

メール認証機能の実装

ユーザーの新規登録が完了したら、メールアドレスに確認メールが送られる機能を実装しましょう。

  1. Userモデルにconfirmableを追加
  2. confirmableをDBに追加するためコマンドを実行
  3. マイグレーションファイル修正
  4. letter_openerの利用

1. Userモデルにconfirmableを追加

app/models/user.rb:confirmableを追加します。

f:id:b_leiu:20190512202335p:plain

2. confirmableをDBに追加するためコマンドを実行

$ rails g migration add_confirmable_to_devise

3.マイグレーションファイル修正

生成されたdb/migrate内のマイグレーションファイルに以下を追加して保存、rake db:migrateを実行。

class AddConfirmableToDevise < ActiveRecord::Migration[5.1]
  # Note: You can't use change, as User.update_all will fail in the down migration
  def up
    add_column :users, :confirmation_token, :string
    add_column :users, :confirmed_at, :datetime
    add_column :users, :confirmation_sent_at, :datetime
    # add_column :users, :unconfirmed_email, :string # Only if using reconfirmable
    add_index :users, :confirmation_token, unique: true
    # User.reset_column_information # Need for some types of updates, but not for update_all.
    # To avoid a short time window between running the migration and updating all existing
    # users as confirmed, do the following
    User.all.update_all confirmed_at: DateTime.now
    # All existing user accounts should be able to log in after this.
  end

  def down
    remove_columns :users, :confirmation_token, :confirmed_at, :confirmation_sent_at
    # remove_columns :users, :unconfirmed_email # Only if using reconfirmable
  end
end

4. letter_openerの利用

最後にメール送信に不可欠なSMTPサーバの設定が必須となります。

通常は、config/environments/development.rbに以下の内容を追記する必要があります。

# config/environments/development.rb

config.action_mailer.raise_delivery_errors = true

ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
  :enable_starttls_auto => false,
  :address => "smtp.gmail.com",
  :port => 587,
  :authentication => :plain,
  :user_name => "gmailのメールアドレス",
  :password => "メールのパスワード"
}

ただ、私はGitHubに自分のメールアドレスを公開するのに抵抗があったので、メール認証機能を追加するにあたり、letter_opener_webというgemを利用しました。

このgemを利用すると自分のメールアドレスを登録しなくても、ブラウザで送信したメールなどを確認できます。

利用方法は以下の手順を踏むだけです。

  1. Gemfileに以下の内容を追記
  2. app/config/routes.rbにルーティング設定を追記
  3. config/environments/development.rbにmailerの記載を追記

1. Gemfileに以下の内容を追記

group :development do #開発環境のみ
  gem 'letter_opener_web'
end

2. app/config/routes.rbにルーティング設定を追記

if Rails.env.development? #開発環境の場合
  mount LetterOpenerWeb::Engine, at: "/letter_opener"
end

3. config/environments/development.rbに以下を追記

config.action_mailer.delivery_method = :letter_opener_web

http://localhost:3000/letter_openerにアクセスすると、ブラウザ上から送信したメールが確認できます。

f:id:b_leiu:20190512203812p:plain

最後に

私はコントローラーを修正して、デフォルトの遷移先(localhost:3000)をログイン画面に変えたりしてアプリを実装しました。

ログイン画面

f:id:b_leiu:20190512201034p:plain:w300

ログイン成功

f:id:b_leiu:20190512201251p:plain

以上となります!

参考:

github.com

qiita.com

madogiwa0124.hatenablog.com

kaminari

kaminariについて

有名なGemパッケージの一つです(名前めっちゃかっこいいですよね)。

ウェブページなどで大量の項目を一覧表示する場合などに、項目を複数のページに分けて表示しますよね。 f:id:b_leiu:20190509175641p:plain

例えば、Googleの検索結果が良い例ですね。

通常webページで大量の項目を表示する場合、1ページに表示する項目数が決まっています。ページ下部のリンク(「1,2,3」など)をクリックすると該当するn番目の検索結果のページに飛ぶことができます。 このような仕組みをページネーションと呼びます。

そして、一覧表示を複数のページに分けるこの仕組みを簡単に実装できるのがkaminari⚡️なのです。 Rails自体にページネーションの機能はありませんので、上手にkaminariを利用しましょう!

kaminariの導入

今回も引き続き、bundlerを用いてkaminariを利用します。 導入方法は非常にシンプルです!

Gemfileの編集

# Gemfile
gem 'kaminari'
gem 'kaminari-i18n'

Gemfileに上記の指定を加えて、bundle installを実行します。

kaminariを導入すると、モデルのクエリーメソッドにpageメソッドが追加されます。

pageメソッドはActiveRecord::Relationオブジェクトを受け取り、該当するオブジェクトを返すため、whereメソッドなどで絞り込んだ結果に対してpageメソッドを実行したり、pageメソッドで得られた結果に対してさらに操作したりできます。

現在のページ数を指定するのに使うメソッドと考えるとわかりやすいかと思います。

コントローラーのアクションの修正

def index
    @books = Book.page(params[:page]).per(3)
end

リンクにはpageパラメータがつきます。コントローラの中でpageメソッドにpage(params[:page])と指定すれば、ユーザーがクリックしたページ番号に応じたページネーションが動作するのです。

per(3)は1件辺りの表示数を指定しています。

テンプレートファイルの修正

# index.html.erb
省略
<%= paginate @books %>

各アクションのテンプレートではpaginateメソッドを使用します。paginateメソッドを利用することで、ページネーションのリンクを埋め込むことが可能となります。 pageメソッドで取り出したオブジェクトがpaginateメソッドに渡されるのです。

ページネーション機能の実装は以上となります。

f:id:b_leiu:20190509183755p:plain

デフォルトの表示件数について補足

デフォルトで1ページあたり25件のレコードが取り出されます。この数字を変更したい場合、以下の2種類の方法があります。

  1. 上記の例のように、都度コントローラーで指定(per(3))
  2. モデル内で一括指定

モデル内で指定

paginates_per 10

最後に

短いですが、以上となります。 kaminari、簡単にページネーション機能が実装できるのでとても便利でした。

参考文献:

qiita.com

www.amazon.co.jp

i18nについて

i18nとは

Railsの国際化機能をi18nと呼びます。この機能を用いることで、複数の言語に合わせてテキストを切り替えたり、地域ごとに日付や数値の書式を切り替えたりすることが可能になります。

本記事の目的

Railsの教科書で作成した簡単なbookアプリを多言語化するプラクティスに取り組みました。その際の気づきをまとめております。

i18nの設定

ざっくりまとめると、

  1. I18nというクラスにロケール(言語+地域の種類)を設定する
  2. 1.で設定したロケールに合わせてYAML形式のロケールテキスト(翻訳ファイル)から文字列を読み込み、表示する

以上のプロセスを踏むだけで、簡単に多言語化対応が可能となります。

ロケールの設定

まず、config/application.rbI18n.localeロケールを表す文字列またはシンボルを指定します。 デフォルトのlocaleは:enのため、他のロケールを設定したい場合は必ず記述する必要があります。

  1. config.i18n.default_locale = :jaを追加
  2. config/locales以下に翻訳用のファイル(YAML形式)を追加する場合はconfig.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] を追加する

f:id:b_leiu:20190508191422p:plain

翻訳ファイルの構成について

github.com

上記のリンクを確認すると、日本語の翻訳ファイル(ja.yml)のテンプレートが確認できますね。 f:id:b_leiu:20190508192323p:plain

モデルの記述 f:id:b_leiu:20190508193502p:plain

ActiveRecordを起点として(必ず!!)、モデル名: book 、モデル名とその属性に対する翻訳を記述しています。 全モデルで共通の属性であればattributesの直下に記述をするだけでOKです。

Viewsの記述 f:id:b_leiu:20190508194041p:plain

スクショのように、RailsのViewsファイルのディレクトリ構造と翻訳ファイルの階層構造を合わせることで、実はViewsファイルにフルパスを書かなくてもよくなります。

この仕組みを遅延参照(lazy lookup)と呼びます。

例えば、index.html.erbを見てみると・・・・

f:id:b_leiu:20190508194735p:plain

.Showと記載するだけで、該当する翻訳(この場合「詳細画面」)を引っ張ってくれるのです。また、変換にはtメソッドを使用します。

この他にも、flashのメッセージの翻訳なども記述できます。テンプレートをチェックしてみてくださいね。

ロケールの切り替えについて

上記のように複数方法がありますが、私はサブディレクトリからロケールの情報を取得して表示する方法を選択しました。

手順としては、

  1. config/routes.rbにscopeメソッドを記述
  2. app/controllers/application_controller.rbにdefault_url_optionsメソッドを記述してオーバーライドする
# config/routes.rb
scope "(:locale)" do
  resources :books
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  ...
  before_action :set_locale
  def set_locale
    I18n.locale = params[:locale] || I18n.default_locale
  end

  #URLのロケールについては、`params[:locale]`で取得。
  def default_url_options(options = {})
    { locale: I18n.locale }.merge options
  end

end

default_url_optionsをオーバーライドして、すべてのリンクに現在のロケールを反映することができます。

最後に、app/views/layouts/application.html.erbに下記の記述を足すことで、全画面に切り替え用のリンクがつきます。

<%= link_to_if params[:locale].present?, '日本語',  url_for(controller: controller.controller_name, action: controller.action_name, locale: 'ja') %> |
<%= link_to_if params[:locale] != 'en',  'English',  url_for(controller: controller.controller_name, action: controller.action_name, locale: 'en') %>

以上の手順を実行すると、下記のように多言語の設定が可能となります。

英語バージョン f:id:b_leiu:20190508195259p:plain

日本語バージョン f:id:b_leiu:20190508195402p:plain

YAMLとは

ロケールテキスト(翻訳ファイル)の記述にYAMLを使用しています。YAMLとはデータ形式の1種で、配列やハッシュなどのデータを人間にわかりやすいように 記述できるのが最大の特徴です。

# YAMLの例
# キー: 値でハッシュを表しています。
member1:
      number: 11
      name: Taro

入力する際の注意点として、下記の3つが挙げられます。

  1. インデントはタブではなく半角空白で入力すること
  2. number: 数字のようにコロンの後は必ず半角空白を入力
  3. ファイルを保存する場合は、文字コードUTF-8とする

最後に

以上となります。参考文献は以下となりますので、適宜ご参照ください。

ruby-rails.hatenadiary.com

ariarichan.hateblo.jp

改訂4版 基礎 Ruby on Rails (IMPRESS KISO SERIES)

Ruby on Railsの基本の基本

参考書籍「Railsの教科書」を読んで、実装する

フィヨルドブートキャンプでRailsの教科書を読んで、Ruby on Railsの基本を理解するというプラクティスに取り組んでいました!

Railsの教科書」の構成について

  • はじめに
  • Webアプリをまずはつくってみよう
  • 一番小さなRailsアプリづくり
  • CRUDの基礎とindexアクション
  • new, create アクション
  • モデル
  • Gemライブラリ
  • 画像アップロード機能の追加
  • あとがき

ご存知ない方のためにご紹介しますが、書籍は上記のような構成になっています。

私はこの書籍に取り組む前にProgateのRailsチュートリアルを2周程繰り返していたのですが、それでも色々と学びがありました。 本記事はその新たな学びを中心にまとめた記事になります。

MVCフレームワークの基本などについては本記事では触れませんのでご了承ください。

CRUDについて

CRUDとはそれぞれ、Create(作成)、Read(読み込み)、Update(更新)、Destroy(略称)を指し、Webアプリの基本となる機能を表しています。

以前の記事で登場した「Webを支える技術」の中でも、HTTPメソッドの開設時にCRUDとの対応について触れられていました。

 
CRUDとHTTPメソッドの対応関係
CRUD 意味 HTTPメソッド
Create ページの新規作成 POST/PUT
Read 読み込み GET
Update 更新 PUT
Delete 削除 DELETE

scaffoldについて

この主要な4機能を一度に作成するコマンドがrails g scaffoldです。

scaffoldコマンドで生成したファイル群を編集して、自分たち用にアプリケーションを作成するイメージです。

f:id:b_leiu:20190427193326p:plain

一覧、新規作成ページ、詳細画面、編集画面に対応するerbファイルも自動で生成されているのがわかりますよね。

もちろん、RouteやControllerのファイルの中身を自ら記述しないといけないですが、以前使用したSinatraと比べるとかなり便利ですね。

Model(モデル)について

Progateのチュートリアルに取り組んでいる際などに少し疑問に感じていたのが、Rails内で定義される変数のスコープです。

ローカル変数はメソッド内、インスタンス変数についてはインスタンスオブジェクト内でしか使用できないはずです。

複数のリクエスト(ブラウザによるリクエストのこと)を実行するにも関わらず、以前のリクエストで実行した際の変数(データ)が参照できるのは、 実はある仕組みのお陰です。

それがModel(モデル)です!

Model(モデル)クラスの定義とファイルの生成について

Modelが定義されているファイルが存在するのはapp/models内です。

実は先程のscaffoldコマンドを実行する際に、モデルとDBの設計図も同時に生成されています。

f:id:b_leiu:20190427194953p:plain

scaffoldコマンドで、以下の2種類のファイルが生成されているのがわかります。

  • app/models/book.rbというModelファイル
  • db/migrate/20190427072108_create_books.rbというMigrationファイル(DBの設計図)

Modelファイルの中を確認すると以下のような記述があります。

f:id:b_leiu:20190427195144p:plain

モデル(クラス)は①英語の単数形②大文字始まりで定義されます。

上記のようにApplicationRecordのクラスを継承しているため、定義していないsaveやallなどのメソッドが実行できるという訳です。

Rubyを学習している際に継承について習いましたが、このように使われていたのですね!

Modelの使い方

  • Modelオブジェクトの生成
book = Book.new(title: "シャイニング", memo: "スティーブン・キングの同名ホラー小説")

クラス.newでモデルオブジェクトを作ります。

  • Model(モデル)オブジェクトの保存
book.save #saveメソッドの実行により保存

定義したモデルオブジェクトをsaveメソッドで保存します。

では、オブジェクトのデータを読み込みたいときは、どうするのでしょうか?

  • Modelオブジェクトの読み込み
books = Book.all #全データ取得

to_aメソッド(配列への変換メソッド)を用いてBook.all.to_aとすると、配列で全データが取得可能となります。

DBとの関連について

rails g scaffold book title:string memo:textのコマンドでは、DBのテーブル名(book)とカラム名(titlememo)、そしてカラムのデータ型(stringtext)を宣言しています。

実は、ApplicationRecord(クラス)はDBから情報を得て、定義したBookモデルにtitle、memoという項目があることを把握しているのです。

したがって、ApplicationRecordを継承しているモデル(Book)はbook.titlebook.memo といったDB内の項目を利用したメソッドの実行が可能なのです。

以上のことから、

  • ModelはDBに簡単にアクセスできる仕組み
  • Modelの仕組みを利用することで、Railsの利用者はDBからデータを比較的簡単に取得できる

DBは通常セキュリティの観点から簡単にアクセスすることが難しく、また通常SQLなどDBの専用言語を用いてデータを取得するのですが、 Modelを利用することでRubyを用いながらDBのデータを取得して利用することが可能となるのです。

メソッドなどをどこから利用しているのか疑問でしたが、やっと理解できました。

最後に

以前からRails内で利用する変数のスコープとメソッドについて疑問を感じていたのですが、今回のプラクティスにより解消されて理解が深まりました!

今後Railsに本格的に取り組むため、記事の中で色々学びをご紹介できればと思います。

以上となります!

DB設計

データベース設計の基本について

本ブログについて

現在、Railsエンジニアを目指してFjord Boot Campで学習しています。 スクールの課題や自己学習の気づきをこちらのブログで掲載しています。

データベース設計(以下、DB設計と略)とは

システム開発において、業務を抽象化し、どのような情報をデータベース上で管理すべきかを設計すること。 そして、このDB設計のプロセスの中核をなすのが「正規化」です。

正規化とは何か

データの重複を排除し、整合的にデータを取り扱えるようにDBを設計することを、データベースの正規化と呼びます。

例えば、普通の伝票などをイメージしてみてください。

1つの仕入先に対して複数の商品が繰り返し存在していたり、必ず重複があるはずです。このようなテーブルは非正規形に該当します。

非正規形のデータから重複を排除していくプロセスを正規化と呼び、通常は以下のように3段階のプロセスで構成されます(本記事では説明を割愛します)。

  • 第1正規形

    • 繰り返し項目を持たないようにレコードを分割する
  • 第2正規形

    • 第1正規形を満たしている
    • 主キーになっている項目の一部だけで決定される項目を分割する
  • 第3正規形

    • 第2正規形を満たしている
    • 主キー以外の項目によって決定される項目を分割し、計算て求められる項目を削除する

DB設計の構成要素(ざっくり)

DB設計における重要な要素は以下の4つです。

  1. エンティティ(箱)
  2. 属性(アトリビュート)
  3. リレーションシップ
  4. カーディナリティ(関連の多重度)

まず、エンティティについて。エンティティとはデータベースのモデリング(ここではDB設計)における管理対象のことです。 以下のように、人や物、場所などのリソースから注文や販売などイベントまで様々な物を表します。

  • 顧客
  • 売上
  • 発注
  • 商品
  • 学生

エンティティの種類については様々な分類が存在しますが、代表的なものが独立エンティティ依存エンティティです。

データベース設計の対象を中学校と仮定します。エンティティは「クラス」と「生徒」です。

クラスは単独で存在しますが、生徒は必ずクラスに所属しており単独では存在しません。この場合のクラスを独立エンティティ、生徒を依存エンティティと呼びます。

また、この場合クラスと生徒は「親子関係にある」とも言います。

2.の属性(アトリビュート)とは、エンティティの構成要素のことを指します。データ項目と考えるとわかりやすいかもしれません。

属性は大きく、キー属性非キー属性に分類されます。キー属性は更に細かく分類できますが、主要な項目は以下の2種類です。

  • 主キー(primary key)
  • 外部キー(foreign key)

主キーはエンティティ内でデータを一意に識別できる属性のことです。生徒の例でいうと、生徒番号や学籍番号です。 生徒番号が分かれば、その生徒の情報が一意に取り出せるという訳です。

外部キーは、親にあたるエンティティを参照するための属性です。先程の例で言うと、親エンティティであるクラスの主キー(「クラスコード」)が子エンティティ(生徒)の外部キーとして表示されます。

非キー属性はキー属性以外のデータ項目のことです。

3.のリレーションとはエンティティ間の関係を表すもの、4.のカーディナリティはリレーションにおいて、親と子がそれぞれ何対何の関係であるかを定義したものです。カーディナリティは以下のように分類されます。

  • 1対1
  • 1対n
  • 多対多(m:n)

先程の中学校の例では、クラスは通常複数の生徒を持つため、クラス対生徒の関係は「1 : n」と言えます。

これらの要素を用いて、データベースの関連を表した図を「ER図」と呼びます。ER図はEntity Relationship Diagramの略で、データベース設計には欠かせない設計ツールです。

f:id:b_leiu:20190423193514p:plain

ER図の種類について

  • IE記法(リレーションが鳥の足のような形をしている)
  • IDEF1X記法(リレーションを●で表現する)

代表的な種類は上記の2種類です。直感的に理解しやすいと言われているのはIE記法の方です。ER図の作成ツールなどによっても種類が異なります。

無料の作成ツールがたくさん存在しますので、検索してみてください(上の例では ERDPlusを使用しました)。

twitterのER図を書こう

BootcampのプラクティスではSNSのER図を作成する課題が出題されました。カンニング防止のため、成果物は載せられないのですが、 理解する上で参考になった内容をご紹介します。

twitterのサービスの中でも代表的な機能がフォロー機能です。

ブロックされていない限り、ユーザーは好きなアカウントをフォローできます。そして、お互いをフォローし合っている状況を「相互フォロー」と呼んだりしますね。

このフォロワーとフォロイーの関係は、1対nの関係で定義することができないため、どうER図で定義するかが非常に難しく感じるポイントでした。

カーディナリティで言うと、フォローは多対多の関係(m:n)を表していると言えます。

そこで、重要になるのが中間テーブルの考え方です。

フォローの申請元ユーザーとフォローの申請先ユーザーの間にもう一つテーブル(Relationshipテーブル)を挟み、そこでお互いのid(外部キー)を保存してあげるのです。

そうすることでお互いの結びつきを正しくDBに記録することができ、検索も容易になります。

この中間テーブルについては、RailsのDB設定・作成において多対多の関係を「関連付けする」際に非常に重要な概念になるため、理解が必須となります。

中間テーブルを理解するには??

非常に参考になる記事を載せましたので、興味のある方はご一読ください。

www.coma-tech.com

qiita.com

railstutorial.jp

最後に

DB設計を学ぶことで、後のクラス図作成やオブジェクト指向の理解へと繋がるため、この段階でしっかり理解できるようしたいですね。

参考文献:

www.amazon.co.jp

www.amazon.co.jp

Sinatraについて

Sinatraで簡単なアプリを作る

Sinatraとは

Sinatraは、Rubyで簡単にWebアプリケーションが作成できるDSLです。

RubyといえばRuby on Railsですが、多機能のため初心者には厳しいということもあり、 Fjord Boot CampではまずSinatraで簡単なアプリを作成するという課題が設けられています。

簡単に作れる?

まず、先に述べると簡単には作れないです(人によりますが)。簡単というよりも、機能がRailsに比べてシンプルで軽量ということみたいです。 また厳密にMVCフレームワークに沿っているわけではないので、初心者にも親しみやすいという特徴があります。

Sinatraの使い方

具体的な手順に関しては、以下の公式ドキュメント(日本語)にほぼ全て書かれてあります。

sinatrarb.com

ただ、いきなりこちらを参照するのはきついのでこちらの記事がおすすめです。

また、Paizaラーニングやドットインストールにも講座があるので確認してみてください。

前提知識について

個人的に難しく感じた点を以下に整理します。

  1. HTTPメソッドとHTMLのフォームの仕組みを理解しないとURLの設定ができないこと
  2. 本課題に関してはDB使用禁止だったため、CGI・標準入出力・JSONなどの理解が必須であったこと

過去記事にも記載しましたが、HTTPの主なメソッドは6つ存在します。ただ、HTMLのフォームで指定できるメソッドがGETとPOSTの2種類しか存在しないため、 現実的に一番利用されるのが以下のGETメソッドとPOSTメソッドの2つだけになります。

メソッド

名称 説明
GET 最も一般的に使用されるメソッドです。ブラウザはサーバに対してページ(リソース)の取得を要求します。
POST CGI でよく使用されるメソッドです。method="POST" を指定したフォームに入力したデータをサーバに転送する際に使用されます。

フォームを利用しながらリソースを更新(PUT)したり、削除(DELETE)するためにはどうしたら良いのでしょうか?

_methodパラメータの利用

フォームの隠しパラメータに_methodというパラメータを用意し、そこに本来送りたかったメソッドを指定してあげる方法です。 Ruby on Railsはこの_methodパラメータを採用しています。

X-HTTP-Method-Overrideという方法もありますがXMLをPOSTする場合などに限定されるため割愛します。

<form method="POST" action="/list/1">
  <input type="hidden" id="_method" name="_method" value="PUT" />
  <textarea id="body" >...</textarea>
</form>

上記はPUTメソッドを実装するために、隠しパラメータを利用している例です。Webサーバーは_methodパラメータを見て、PUTメソッドとしてリクエストを扱っています。

ちなみにRails4以降では、リソースの更新(updateアクション)にPATCHを利用しています。

注: PUTも使えますがリソースの一部更新を意味するPATCHの方がよりふさわしいという理由です。

上記を踏まえた上でのフォームによる値の更新やボタンを利用した削除の実装が個人的に難しく感じました。

2.の条件(DB禁止)については、かなり苦戦しました。DBを利用できれば削除などの処理はそれほど難しくないのですが、データをファイルに保存して読み込む処理をRubyで記述する必要があり、理解に時間がかかりました。

最終的に、ファイルにデータを保存する処理をJSONというデータフォーマットを利用して行うことで対応できました。CGIに対する理解を深めるためにこのような条件が課されていたようです。

@json_data = File.open('memo.json') do |file|
    JSON.parse(file.read)
  end

RubyJSONを扱う際には下記の記事が参考になりました。 uxmilk.jp

短いですが、以上となります。Sinatraを利用することでHTTPメソッドやルーティングに対しての知識が深まったので、 今後のRailsの学習に繋げたいと思います。

最後に

HTTPメソッドやHTMLの形式、JSONを理解する上で以下の書籍がとても参考になりました。Railsについて学ぶ方にも参考になるかと思います。

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

RESTの概念などについてまだまだ理解が不十分ですが、繰り返し再読することで理解を深めたいと思います。

HTTPの基本の基本3

HTTPヘッダについて

HTTPヘッダの役割

ヘッダの重要性

  1. メタデータの表現
  2. リソースへのアクセス権を設定する認証
  3. クライアントとサーバの通信回数を減らすキャッシュの機能

メッセージのボディに対する付加的な情報、いわゆるメタデータを表現する役割を果たす。 クライアントやサーバはヘッダを見てメッセージに対する挙動を決定する。

ヘッダの中身

  • 日時 値に日時を持つヘッダ。
Date: Tue, 06 Jul 2010 03:21:05 GMT
  • MIMEメディアタイプ
    メッセージでやりとりするリソースの表現の種類を指定する。
    • Content-Type(メディアタイプを指定する)
Content-Type: application/xhtml+xml; charset=utf-8  

text, image, audio, video, application(その他のデータ)などを指定する。

Content-Type: application/xml; charset=utf-8

上記のようにメディアタイプとcharsetパラメータを指定する記述が推奨される。

  • 言語タグ(Language Tag)
Content-Language; ja-JP

メディアタイプや文字のエンコーディング、言語タグをサーバーが一方的に決定するだけでなく。クライアントと交渉して決定することも可能。

Accept: application/xml, application/msword;q = 0.9 #メディアタイプを指定
  • Content-Lengthとチャンク転送

    • Content-Length(ボディの長さを指定する)
    • チャンク転送(ボディを分割して転送する)
Content-Length: 5538

動的に画像を生成するようなWebサービスの場合など、ファイルサイズが決定されるまでレスポンスが返せないので応答性能が低下する。 そのようなケースでは、Transfer-Encodingヘッダを用いると最終的なサイズがわからないボディを少しずつ転送できる。

Transfer-Encoding: chunked

ユーザのアクセス認証について

HTTP認証方式には、主にBasic認証とDigest認証がある。

  • Basic認証:ユーザ名とパスワードによる認証方式。

ユーザ名とパスワードをAuthorizationヘッダでリクエストごとに送信する。ユーザ名とパスワードが平文でネットワーク上を流れるため、HTTPS通信などの検討が必要となる
。

  • Digest認証:Basic認証よりもセキュアな認証方式。

Digestとはメッセージダイジェストの略で、あるメッセージに対してハッシュ関数を適用したハッシュ値のこと。

流れとしては、

  1. クライアントはまず認証情報なしでリクエストを送信する
  2. そのレスポンスの情報・ユーザ名・パスワードを使ってダイジェストを生成して、それをリクエストとして送信して送信する。

メリット

  • パスワードを盗まれる危険性がない
  • サーバ上にハッシュ値のみを保管しておけば良いのでセキュリティリスクが低い

デメリット

  • メッセージ自体が平文でネットワーク上に流れる(メッセージ自体を暗号化したければHTTPSを利用するべき)
  • 毎回はじめに認証情報なしでリクエストを送信して、401 Unauthorizedレスポンスを得なければいけない

キャッシュについて

HTTPの重要な機能の一つで、サーバから取得したリソースをローカルストレージに蓄積して再利用すること。

クライアントに蓄積したキャッシュは、そのキャッシュが有効な間、クライアントが再度リソースにアクセスしようとした時に 再利用する。

有効期限がいつまでなのかについては、以下の3種類のヘッダを用いてサーバが指定する。

  • Pragma(キャッシュを抑制する)
  • Expires(キャッシュの有効期限を示す)
  • Cache-Control(詳細なキャッシュ方法を指定する)
Pragma: no-cache #リソースをキャッシュしてはならないことを示す
Cache-Control: max-age: 86400 #86400秒、つまり24時間キャッシュが新鮮であることを示す

最後に

以上です!

参考資料

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)