Rails – 掲示板 – 第1段階

概要

掲示板を例にして、ユーザーの登録、サインインを実装する。サインイン済みの場合のみトップページを表示するアクセス制限も実装する。

掲示板の全体ページへ

要件

画面遷移

  • アクセス時に/topにルーティング
    • サインイン状態でなければ/sign_inにルーティング
    • 仮表示として登録されているユーザー名、メールアドレス一覧を表示
    • ログアウト
      /sign_in
  • /sign_in
    • リンクをクリックして/sign_up
    • ユーザー名、パスワードを入力
      /top
  • /sign_up
    • リンクをクリックして/sign_in
    • ユーザー名、メールアドレス、パスワードを入力してユーザー登録
      /top

データベース

登録ユーザーテーブル:users

カラム名 型(MySQL) 型(Rails) 内容
id BIGINT(AI) Rails生成
name VARCHAR(255) string ユーザー名
email VARCHAR(255) string メールアドレス
pasword VARCHAR(255) string パスワード
created_at DATETIME Rails生成
updated_at DATETIME Rails生成

検討

コントローラーとアクション

pages_controller.rb

  • トップページなどサイト全体に関するページのコントローラー
  • top:サインインユーザーに対するサイトのトップページをレンダリング

users_controller.rb

  • ユーザーの登録、サインインなどユーザー管理を担うコントローラー
  • sign_in:サインインページをレンダリング
  • sign_up:サインアップページをレンダリング
  • sign_in_process:サインインフォームのPOSTに対するサインイン処理
  • sign_up_process:サインアップフォームのPOSTに対するサインアップ処理

ビューファイル

pages

  • top.html.erb:サインインユーザーが最初に見るページ
    • BBSの記事などが載ることになるが、この時点では登録済みのユーザーリストを表示する
    • ヘッダーメニューを表示する

users

  • sign_up.html.erb:未登録ユーザーのためのサインアップページ
  • sign_in.html.erb:登録ユーザーのためのサインインページ
  • これらのページにはヘッダーメニューは表示されない

共通のビューファイル

共通のビューファイルはlayoutディレクトリーに置く。サインインの有無に対応したレイアウトを分け、デフォルトでない場合はコントローラーから明示的に呼び出して使い分ける。

  • application.html.erb:サインイン済みのユーザーに対しては登録やサインアウトといった処理のメニューをヘッダーに表示する
  • application_signed_out.html.erb:サインインしていないユーザーに対してはヘッダーメニュを表示しない

スタイルファイル

CSSのスタイルをリセットするファイルを準備。

  • reset.css

ヘッダーメニューのスタイルファイルを独立して準備。

  • header.scss

各ビューのスタイルファイルはコントローラー単位のファイル。

  • pages.scss
  • users.scss

実装手順

 

 

Rails – 画像ファイルの配置とパス指定

概要

Railsで画像ファイルを配置するのは以下の2箇所

app/assets/images
開発側で準備するロゴやアイコンなど
public
ユーザーのアップロード画像など

それぞれの下にディレクトリーを作って、その中の画像ファイルをimg要素、div要素の背景画像で読み込む場合のパス指定について整理した。

ビューファイル&img要素の場合

app/assets/images

サブディレクトリ―exampleの下にimage_assets.jpgを置いた場合。

example/ファイル 読み込めない
/example/ファイル 読み込めない
./example/ファイル 読み込めない

public

サブディレクトリ―exampleの下にimage_public.jpgを置いた場合。

example/ファイル 読み込める
/example/ファイル 読み込める
./example/ファイル 読み込める

ビューファイル&img_tagの場合

app/assets/images

サブディレクトリ―exampleの下にimage_assets.jpgを置いた場合。

example/ファイル 読み込める
/example/ファイル 読み込めない
./example/ファイル NoMethodError

public

サブディレクトリ―exampleの下にimage_public.jpgを置いた場合。

example/ファイル Sprockets::Rails::Helper::AssetNotFound
/example/ファイル 読み込める
./example/ファイル NoMethodError

SCSS&div要素の背景画像の場合

app/assets/images

サブディレクトリ―exampleの下にimage_assets.jpgを置いた場合。

example/ファイル 読み込める
/example/ファイル 読み込めない
./example/ファイル 読み込めない

public

サブディレクトリ―exampleの下にimage_public.jpgを置いた場合。

example/ファイル 読み込めない
/example/ファイル 読み込める
./example/ファイル 読み込めない

まとめ

img要素はpublicの画像は読めるがassetsの画像は読めないので、img_tagヘルパーを使う方がよい。画像をimg_tagで配置する場合も、div要素の背景画像とする場合も、ファイルのパス指定は以下の通り。

パス指定
app/assets/images サブディレクトリ―/ファイル
public /サブディレクトリ―/ファイル

参考

確認に使ったアプリケーションファイル

pages_controller.rb

image_location.html.erb

pages.scss

 

Tips – ヘッダーメニュー

概要

HTMLのheader要素内に固定メニューを配置する。左端にロゴ画像を置き、メニューは右寄せで配置する例。

HTML/CSS

HTML

ヘッダーにdiv要素によるロゴ画像とulによるメニューを配置し、スタイルはCSSで設定する。

CSS

header内のロゴとメニューブロックをFlex-boxで配置し、左右に寄せている。メニューリストの水平配置にもFlex-boxを使っている。

なおheaderを固定してbodyのみをスクロールさせることもできる。

  • 最初のブロックでスタイルをリセット。
  • header要素
    • display: flex指定でコンテンツ(ロゴ、メニューブロック)をフロートさせて配置
    • justify-contentで2つのコンテンツを左端と右端に寄せる
    • 高さを指定
  • .header_logo
    • div要素に背景画像を指定
  • .header_menu
  • .header_menu li
    • 最初の3行はリストの中の文字を縦横センタリングする設定
  • .header_menu li + li

ロゴのサイズについて

  • div要素で背景画像のみを表示させるときはwidth/heightを明示的に設定しなければならない
  • 当初はheight: 100%headerの高さに合わせ、width: autoで表示されていた
  • ところがそこで親のheaderdisplay: flexを設定すると表示が消えてしまった
  • そこでここでは、グローバルなカスタムプロパティーを使っている

Rails/SCSS

HTML

  • 通常すべてのレンダリング時に使われる共通レイアウト
    • app/views/layouts/application.html.erb
  • これとは別にヘッダーメニューが必要な場合の共通レイアウトファイルを作成
    • app/views/layouts/application_with_header.html.erb

ヘッダーメニューが必要なアクションのみこのレイアウトを使うため、コントローラーでレイアウトファイルを指定。

レイアウトファイルが読み込むスタイルシートは標準と同じapplication.css

requireされるlayout.scssで、ヘッダーメニュー用のSCSSを読み込む(ヘッダーメニューがない場合も読み込む)。

SCSS

以下のSCSSファイルを作成して読み込ませる。リセットCSSは別に読み込んでいる。

 

Tips – フォームのデザイン

概要

  • テキストフィールドや送信ボタンなどを含むフォームのデザインについて
  • input要素などのコンテンツから組み上げる方法と、flex-boxを使った方法の2つ。
  • フォーム全体のページ内の位置設定についても含めた

共通事項

元になるHTML

3つのinput要素と1つのbutton要素を含むform要素。form_blockというクラスのdiv要素でラップする。

Railsのhtml.erbの場合は以下の様になる。

 

リセットCSS

CSSでは以下で関係要素のスタイルをリセットする。

Railsの場合は別にreset.cssを準備する(Eric Meyer’s “Reset CSS” 2.0)。

body要素

body要素は背景色だけを設定する。

方法1~要素スタイルの積み上げ

CSS

CSSの内容

CSSの全体は以下のとおり。以下、手順を分解して整理する。

div要素によるラップ

  • div要素で表題(h1)とform要素全体をラップする
  • 幅は400pxに設定
  • 高さ指定をしない(auto)なので、子要素に応じて全体の高さが変わる

表題

  • フォームの表題をh1要素で書いている

form要素

  • form要素のパディングと背景色を設定
  • 幅は親要素のdivにフィットし、高さは子要素群に合わせて変わる

input要素

  • インラインレベル要素のinputをブロックレベル要素に変更
  • box-sizingborder-boxに指定
    • これを指定しないとinput要素がはみ出てしまう
  • 幅(width)は親要素に合わせる
  • 高さは32px固定
  • マージン(下)を設定して間隔をあける

button要素

  • インラインレベル要素のbbuttonをブロックレベル要素に変更
  • 幅は親要素formの50%
  • margin-left: autoで右寄せ
    • 中央に置く場合はmargin-right: autoも加える

フォームの位置調整

  • もう一度全体をラップしているdiv要素に戻り、bodyに対する位置を指定する
    • フォームの左上隅が上端から20%、左端から40%

SCSS

RailsなどでSCSSを使う場合の例。

 

方法2~flex-box

CSS

CSSの内容

flex-boxを使ったCSSの全体は以下のとおり。フォーム全体の位置設定は方法1と同じ。

div要素によるラップ

  • 幅は400px
  • 高さはautoとし、子要素のformの髙さに合わせる

form要素

方法1と違うのは以下の点。

  • display: flexで子要素へのflex適用を指定
  • flex-direction: columnで子要素を縦並びに
  • justify-content: space-aroundで子要素を均等に配置
  • 高さを200pxに固定

input要素

要素の間隔は自動的に決まるので、方法1で設定していたmragin-bottomを削除している。

button要素

  • button要素もマージンを削除している
  • 右寄せにするため、align-self: flex-endを設定
    • 中央に置く場合はcenterを指定

SCSS

RailsなどでSCSSを使う場合の例。

 

Tips – リストを横並びに

概要

デフォルトのHTML/CSSでは、リスト内の各要素(li)は縦に並べられ、各要素の先頭にマーカーが付される。

このスタイルを変更し、li要素を横に並べるスタイルを設定する。

HTML/CSS

HTML

以下のリストでulタグにクラスを指定し、スタイルを設定する。

CSS

CSSの例は以下のとおり。

冒頭のブロックは関係する要素のリセットCSS。

ulタグに設定したmenuクラスのスタイル

  • list-style-type: noneでリストのマーカー表示を抑止
  • display: flexは、この指定1つで子要素のボックス要素が横並びになる

menuクラスの下のli要素のスタイル

  • 親のulflexを指定しているので、個別要素としてのスタイルを設定
  • liを等幅に設定し、背景色を指定している

Rails/SCSS

HTML

HTMLの内容は同じ。

SCSS

リセットCSSはreset.cssファイルとして切り分けている。

考え方はCSSと変わらず、子要素liをブロック内に入れ子にしている。

 

Tips – アンカーをボタン風に

概要

アンカー要素(a)にスタイルを適用して、ボタンの様な形にする。

HTML/CSS

HTML

HTMLではa要素をdivタグで囲んでクラス定義している。

CSS

CSSの例は以下のとおり。

前段のブロックで関係要素のスタイルをリセットし、bodyの背景色をセットしている。

アンカーのスタイル設定については以下のとおり。

.button_like_anchorクラスの中のa要素のスタイル

  • marginpaddingの設定のためにdisplay: inline-blockを指定
  • box-sizingの設定はここでは影響しないが、サイズ指定してボタンを並べるときなどに関係
  • border-radiusで角を丸くしている
  • text-decoration: nonecolor設定でデフォルトのアンカーの装飾を変更

Hover時の変化

  • 元の背景をbackground-colorで設定
  • 疑似クラスhoverでカーソルが領域に入った時のスタイルを設定
    • 背景色を少し明るくしている
    • cursorでカーソル形状を変更(デフォルトがpointerのため、ここでは影響しない)

Rails/SCSS

html.erb

Railsではアンカータグをヘルパーで実装している。

SCSS

リセットCSSはreset.cssファイルとして切り分けている。

また、疑似クラスhoverの記述をSCSSに合わせて変更している。

 

CSS – リセットCSS

概要

ブラウザーによってデフォルトで設定されているスタイルをリセットしてシンプルにするためのCSS。

リセットに加えて単純のスタイルを設定するものもある。

各種リセットCSS

Eric Meyer’s “Reset CSS” 2.0

HTML5 Doctor CSS Reset

Yahoo! (YUI 3) Reset CSS

 

その他

Normalize.css

A Modern CSS Reset

 

Rails – スタイル設定

概要

Railsのプロジェクトにおけるスタイルシートの場所、スタイル設定について整理する。

デフォルトの状態

プロジェクト生成直後、app/assets/stylesheets/ディレクトリーにapplication.cssが生成され、以下の2行が記述されている。これらの行はディレクティブと呼ばれ、それぞれの意味については後述。

この段階でRailsの”Yay! You’re on Rails!”のページのソースを見ると、HTMLに直接styleタグが書かれている。

コントローラーとスタイルファイルの関係

以下のように2つのアクションを含むコントローラーを3つ生成する(出力は省略)。

その結果、コントローラー・ビューファイルとともに、app/assets/stylesheetsディレクトリーに3つのscssファイルが生成される。

これら3つのscssファイルはコメントのみの空の内容。

ここでorangeビューファイルを表示させてみる。

localhost:3000/fruits/orange

表示されたページのソースのうちスタイルシートの読み込みに関する行を抜き出すと以下のとおり。

以下のことがわかる

  • applicationのほか、新たに生成されたfruits, vesitables, meatsに関するスタイルシートが全て読み込まれる
  • スタイルシートはcss拡張子を持つ
  • ファイル名の本体は、コントローラー名.self-ダイジェストの形式
  • URLクエリーパラメーターを持つ(body=1)
  • スタイルが読み込まれる順番は、application.cssが最後で、その前に他のファイルが辞書順で読み込まれる

これらのファイルは元のscssファイルからcssにコンパイルされた結果で、ファイルの内容のダイジェストが元のファイル名に付加されている。

この場合、application.cssと3つのscss全てのスタイルが適用される。たとえばいずれかのcss/scssファイルに* { color: red; }と記述するとfruits/orangeページの文字の色が赤くなる。

require_selfとapplication.css

無指定でもapplication.cssは読み込まれる

application.cssの以下の2行を削除し、何も指定されていない状態にする。

この状態でorangeページを表示させてソースを見ると、application.cssの読み込みだけ残っている。

require_selfの意味?

application.cssの2行の記述のうち*= require_tree .の行を削除し、ページを表示させてソースを見てみる。

*= require_selfの行に対応してapplication.cssのファイルが読み込まれているが、そもそもなにも指定しなくてもこの行は生成されていた。

次に*= require_selfの方を削除し*= require_tree .を残した結果を見てみる。無指定の時と同じく、ここでもapplication.cssが読み込まれている。

読み込み順の制御は可能

require_treeとrequire_selfの順番を逆にしてみる

そうすると、application.cssが最初に読み込まれるようになった。

ディレクティブ

require_tree

stylesheetsディレクtリーの構成を以下の様に変更する。

  • d:stylesheets
    • f:meats.scss
    • d:crops
      • f:vesitables.scss
      • d:fruits
        • f:fruits.scss

この状態でapplication.cssが初期設定のとき、ページを表示させてもスタイルファイルの読み込みは変わらない。

require_tree .はカレントディレクトリー以下のすべてのディレクトリをたどりながらすべてのファイルをCSSに含める。

次にapplication.cssの内容を以下の様に変更する。

この結果、指定したcropsディレクトリー以下のファイルが再帰的に読み込まれる(application.cssは読み込まれている)。

require_directory

require_directoryは、指定したディレクトリー下のファイルのみをCSSに含める。サブディレクトリー以下は無視される、

この結果は、cropsディレクトリー下のvesitables.cssファイルのみが読み込まれる(application.cssは読み込まれている)。

require ファイル

requireディレクティブにファイル名を指定して、特定のファイルのみを読み込める。

上記の指定で、HTMLファイルにはfruits.cssのみが読み込まれる(application.cssは読み込まれている)。

 

Rails – 基礎的なルーティング

概要

GETやPOSTなどのリクエストがあったときconfig/routes.rbの内容に従って各コードにルーティングされる。

このルーティングファイルの書き方を整理する。

前提

以下のような構成のアプリケーションを考える。

  • コントローラー:pages_controller.rb
    • アクション:top
    • ビュー:top.html.erb
  • コントローラー:users
    • アクション:sign_up、sign_in
    • ビュー:sign_up.html.erb、sign_in.html.erb

デフォルトのroutes.rb

設定と動作

ルーティングファイルはconfig/routes.rbにある。コントローラー生成直後のファイルの内容は以下のとおり。

初期状態では、GETメソッドで各ビューファイルがリクエストされたとき、ディレクトリー構成に従ってファイルを探すようルーティングされる。

たとえばブラウザーでhttp://localhost:3000/pages/topと入力するとpagesディレクトリー下のtop.html.erbが表示される。

このページに他のページからヘルパーでリンクを張る場合は以下の様に書く。

<%= link_to 'トップ', '/pages/top %>

ルーティング

ルーティングの設定状態はrails routesコマンドで確認できる。

Prefixの列はリンクのエイリアスに関する表示で、ヘルパー中でプレフィックスに'_path'を付けた名前でリンク先を表せる。

たとえばtop.html.erb中に以下の行を追加するとリンクが表示され、クリックするとsign_in.html.erbページに遷移する。

<%= link_to('サインイン', users_sign_in_path) %>

まとめ

  • ルーティング設定で各アクションを呼ぶためのURLを設定できる
  • URLでルーティングする場合は文字列とする
  • Prefix_pathを組み合わせたエイリアスでもルーティングができ、その場合はコロンなしで書く

ルーティングの設定変更

設定と動作

コントローラー生成時のルーティングを変更して、それぞれのページがアプリケーションルートから直接呼び出せるようにする(たとえばlocalhost:3000/topなど)。

3つのルーティングとも同じ方法で指定している。

メソッド 'URL', to: 'コントローラー#アクション'

これでそれぞれのURL指定’/top’などに簡略化され、GETリクエストに対して対応するアクションが実行される。

この場合、トップページに以下のようなURL指定のリンクを追加すると、クリック時にサインインページに遷移する。

<%= link_to('サインイン', '/sign_in') %>

ルーティング

ルーティングの一覧は以下のとおりで、Prefixの列も簡略化されている。

Prefixも変更されているので、top.html.erb中に以下の行を追加するとリンクが表示され、クリックするとsign_in.html.erbページに遷移する。

<%= link_to('サインイン', sign_in_path) %>¥

まとめ

  • ルーティングの, to: 'controller#action'によって、設定したURLから指定したアクションにルーティングできる
  • カンマ、toキー(to:)、'コントローラー#アクション'の文字列

ルーティングの名前

設定と動作

routes.rbのsign_inの行に, as:を追加して以下の様に変更する。

get '/sign_in', to: 'users#sign_in', as: :sign_in_page

この場合、リンク先としてsign_in_page_pathを指定してルーティングできるようになる。

ルーティング

このときのルーティングは以下の様になっている。

この場合、linkt_toから呼び出す名前はsign_in_page_pathになり、従前のsign_in_pathを使うとエラーになる。

つまり、as:で指定された内容で元のPrefixがオーバーライドされ、以後はその内容の名前かURLで指定しなければならない。

まとめ

  • ルーティングの名前を', as: :name'で設定できる
  • 設定はカンマ、asキー(as:)、名前シンボル
  • 名前を設定すると、Prefixがそれに置き換えられる

 

Rails – 例題 – コントローラー・ビューを準備する

概要

Railsの例題・掲示板の第1段階のためのコントローラーとビューを生成する。

コントローラー・ビューの生成

プロジェクトディレクトリー下で、2つのコントローラー、pagesusersを生成する。

pagesコントローラーとビュー

生成コマンド

pagesコントローラーには1つのアクションtopを定義する。

rails generate controller pages top

コントローラー

上のコマンドによって、コントローラーファイルpages_controller.rb、ビューファイルtop.html.erbの2つのファイルが生成される。

app/controllers/pages_controller.rb

topアクションに対応する空のメソッドが定義されている。

ビュー

app/views/pages/top.html.erb

コントローラーと同名のディレクトリーがviewsディレクトリーに、アクションと同名のビューファイルがそのディレクトリーにつくられる。ビューファイルにはプレースホルダーの表示が書かれている。

usersコントローラーとビュー

生成コマンド

usersコントローラーには2つのアクションsign_upsign_inを定義する。

コントローラー

上のコマンドの結果、1つのコントローラーファイルusers_controller.rbと2つのビューファイルsign_up.html.erb、sign_in.html.erbが生成される。

app/controllers/users_controller.rb

2つのアクションに対応する空のメソッドが定義されている。

ビュー

コントローラーと同名(users)のディレクトリーがviewsディレクトリーの下につくられ、2つのビューファイルが生成される。

app/views/users/sign_up.html.erb

app/view/users/sign_in.html.erb

ルーティングの設定

基礎的なルーティングに従ってルーティングを設定していく。

デフォルトの設定

コントローラー・ビュー生成後のルーティングはconfig/routes.rbに書かれている。

初期状態では、GETメソッドで各ビューファイルがリクエストされたとき、ディレクトリー構成に従ってファイルを探すようルーティングされる。

たとえばブラウザーでhttp://localhost:3000/pages/topと入力するとpagesディレクトリー下のtop.html.erbが表示される。

ルーティングの設定変更

コントローラー生成時のルーティングを変更する。

  • ビューファイルのディレクトリー構成によらず、URLで/top、/sign_up、/sign_inと指定してアクションが呼ばれるようにする
  • ..._pathのリンク名を定義する

変更後のroutes.rbは以下のとおり。