DIVE INTO CODE

人材紹介会社と連携した本気のカリキュラムと手厚いサポートを提供するプログラミングスクール。
最短わずか6ヶ月でRailsエンジニアとしての独立・転職を支援します。

DIVE01

DIVE01のゴール

DIVE01は、Ruby on Railsを使用して、achieveのブログ機能を作成していきます。
ブログ機能を学びながら、Ruby on Railsの基礎、そしてWebアプリケーションについて学びましょう。

Ruby on Railsとは

Ruby on Rails(以降、Rails)はRubyのWebアプリケーション・フレームワーク(以降、フレームワーク)です。
フレームワークとはエンジニアがよく使うプログラムやアプリケーションの仕組みをまとめたものです。
フレームワークを使用することでWebアプリケーションを簡単に素早く作成することができます。

Webアプリケーションとは

Webアプリケーションとは、ブラウザで使用するアプリケーションのことです。
代表的なWebアプリケーションの例として、Amazonや楽天などのECサイト、FacebookやTwitterが挙げられます。
一方でExcelやWordはコンピュータのデスクトップ上で動作します。そのためWebアプリケーションではなく、デスクトップアプリケーションと呼ばれます。

Rails基礎

Webサイトを見るには、ブラウザからサーバにリクエストを送信する必要があります。
Webサーバは、リクエストに含まれるHTTPメソッドとURLをもとに、レスポンス(HTMLとCSS)を返します。
そのレスポンスをブラウザが読み込むことで、Webサイトを見ることができます。
Railsは、このレスポンスをWebサーバで生成するという役割を担っています。
ここからは、Railsでどのようにレスポンスを生成するかを学んでいきましょう。

https://diveintocode.gyazo.com/f63cece64e8d39a46886732a841e01e3

なぜRailsが必要なのか

通常、リクエストがWebサーバに送られてくると、WebサーバはHTMLとCSSを返します。
一般的なWebページを表示する場合はリクエストに対して同じレスポンスを返せば問題ありません。
しかし、下図のようにユーザーのマイページを表示するといった場合は、それぞれのユーザに合わせた情報を返す必要があります。
それを可能にするのがRailsです。

(例) ログインしてマイページを表示した場合

https://diveintocode.gyazo.com/aaacc6f7ce67ece7627eb786a446caba

Railsは、Webサーバでレスポンスを生成するのが役割です。実際にどのように、レスポンスを返しているのかを学びましょう。

MVCについて

Railsは、Model, View, Controller の3つの重要な機能から成り立っており、これらの頭文字をとって、MVC フレームワークと呼ばれています。
ModelはControllerの指令を元にデータ操作を行います。Viewは、Controllerから渡された情報を元にHTMLを生成します。Controllerは、データ操作の指令や、Viewにデータを渡すなど、Railsの中心的役割を果たします。

Check Point !!

Rails は、Model View Controller の3つの重要な要素で構成されている。

https://diveintocode.gyazo.com/30af74bd8b5d5a913d31bd947dda9757

それでは、MVCを含め全体の流れを図を参照しながら学びましょう。

https://diveintocode.gyazo.com/99fb83b9a6af2c95edec9adc6c524977

:pencil2: ブラウザからリクエストが送られると、リクエストはRouterに送られます。

リクエストの中には、URLとHTTPメソッドが含まれています。

https://diveintocode.gyazo.com/f5d89c5ecb9ae26b725bd2648932c26f

:pencil2: RouterはURLとHTTPメソッドを元に、どのコントローラのアクションを実行するか選択します。

https://diveintocode.gyazo.com/77fed57e06058ca40daa01cca98e3d18

:pencil2: 選択されたコントローラのアクション内に、データ操作に関する記述があった場合、Modelにデータ操作をさせる命令を出します。

ここでいうデータ操作とは、データを取得したり、削除命令、作成命令などを指しています。

https://diveintocode.gyazo.com/bdf2868c3cc0c20deb12a228a13528f1

:pencil2: 命令を受けたModelはデータベースにデータ操作の命令を出します。

この時、コントローラから出された、Rubyで書かれた命令をデータベースを操作するための言語であるSQLに翻訳をします。

https://diveintocode.gyazo.com/c627b24f122d55a3eba951b82b7d0620

:pencil2: データベースは、データ操作の命令を実行し、得られた結果をModelに返します。

https://diveintocode.gyazo.com/d60af838440ceffbf331b7e9c45e52fc

:pencil2: Modelは得られた結果をControllerに返却します。

https://diveintocode.gyazo.com/25c63b354c4d8ca94c1e856aaee86b78

:pencil2: Controllerは、得られた結果をViewに渡します。

https://diveintocode.gyazo.com/d03902edf5b493e761da6e86aaa20531

:pencil2: Viewは得られた結果を元にHTMLを生成し、Controllerに返します。

https://diveintocode.gyazo.com/401fd3d989c4df49a5d453f41086706f

:pencil2: Controllerは、返却されたHTMLをレスポンスとして返します。

https://diveintocode.gyazo.com/5d4e8e36ce87169df37e668332164ab2

以上が、リクエストを受けてからRailsがレスポンスを返すまでの流れです。
この流れは、Railsを学ぶ上で必ず理解しなければなりません。

実際に開発する

それでは、実際にRailsを使用して、achieveにブログ機能をつくっていきましょう。

:pencil2: rails newコマンドを使用して、アプリの土台を作成しましょう。

まずはターミナルで、以下のコマンドを実行します。

gem install rails -v 4.2.3
cd ~/workspace #現在のディレクトリが~/workspaceではない場合実行しましょう。
rails _4.2.3_ new achieve -d postgresql

_4.2.3_とすることでrailsのバージョンを指定しています。achieveはアプリ名を指定しています。また、-d postgresqlとすることでデータベース管理システムの種類をPostgreSQLに指定しています。

https://diveintocode.gyazo.com/810c9460c04ee4cadd5a7c9c4128eb40

(注) 途中bundle install で止まりますが、installが完了するまで待ちましょう。

rails newコマンドを完了すると、Webアプリケーションを作成していく上で必要なファイルが大量に作成されます。
作成されたすべてのファイルについて理解しておく必要はありませんが、どのようなものが作られるのか、概要を理解しておきましょう。

Check Point !!

`rails new` はアプリケーションの土台を作成するコマンドである。

:pencil2:bundle installコマンドをターミナルで実行する

rails newコマンドを実行すると、通常bundle installコマンドが実行されますが、
通信状況によって途中で停止してしまう場合もあるため、手動でbundle installコマンドを実行します。

cd achieve
bundle install

Routerを設定する

それでは、先ほどのMVCの流れに則って、最初にリクエストを受ける場所はRouterであるため、Routerから設定しましょう。
Routerはachieve/config/routes.rbファイルを編集することで設定することができます。

:pencil2: ブログの一覧画面のroutingの設定を行いましょう。

Rails.application.routes.draw do
  get 'blogs' => 'blogs#index'
  # The priority is based upon order of creation: first created -> highest priority.
  # See how all your routes lay out with "rake routes".
  #省略

get 'blogs' => 'blogs#index' を二行目に追加しましょう。

これはリクエスト(HTTPメソッドがget、URLが/blogs)のものが来た場合、blogsコントローラのindexアクションを実行するという意味になります。

:pencil2: Routerの次はコントローラを作成しましょう。

ターミナルで以下のコマンドを実行しましょう。

rails g controller はコントローラを作成するコマンドです。

cd achieve
rails g controller blogs index

また、rails g controllerの後には、コントローラの名前を指定しています。ここでは、blogsとしています。コントローラ名の後には、アクション名を指定します。上記のプログラムは、ブログの一覧を表示するindexアクションを作成しています。

:pencil2: 作成されたコントローラを確認してみましょう。

コントローラは、app/controllers/blogs_controller.rbにあります。

また、コントローラを作成する際に、アクションを指定すると、そのアクションのrouteとViewファイルが自動的に作成されます。

Check Point !!

`rails g controller` はコントローラを作成するコマンドである。

:pencil2: Routerを修正します。

Controllerを作成すると、自動的にRouterの設定も行われます、既にRouterの設定は行っているのでconfig/routes.rbを修正します。

Rails.application.routes.draw do
  get 'blogs' => 'blogs#index'

  # The priority is based upon order of creation: first created -> highest priority.
  # See how all your routes lay out with "rake routes".

get 'blogs/index'を削除します。

:pencil2: コントローラを作成することができたので、モデルを作成する。

rails g modelコマンドでModelを作成することができます。コマンドでは、小文字になっていますが、railsが自動的に大文字に変換します。
rails g model blogとすることで、作成するモデル名をBlogに指定しています。

rails g model blog

:pencil2: app/models/blog.rbを開いて、モデルの中身を確認してみましょう。

class Blog < ActiveRecord::Base
end

モデルにクラス名とendのみが書かれていることを確認できます。
初期のモデルがここまでシンプルなのは、継承により必要な機能が利用できるためです。
上記の例で言うと、ActiveRecord::Base に数多くの機能を備えており<とプログラムすることでBlogクラスは、ActiveRecord::Baseにプログラムした機能を使えるようになります。

https://diveintocode.gyazo.com/4d12da4356287238d0215a5116830843

またモデルを作成すると、同時にマイグレーションファイルが作成されます。

:pencil2: マイグレーションファイルが作成されていることを確認してみましょう。

 create    db/migrate/xxxxxxxxxxxx_create_blogs.rb
 create    app/models/blog.rb

以下がマイグレーションファイルです。モデルを作成するとマイグレーションファイルは自動的に作成されます。xxxxxxxxxxxxの部分には作成した日時が付与されます。

db/migrate/xxxxxxxxxxxx_create_blogs.rb

「マイグレーション」は、イメージしづらいため図を用いながら理解していきます。

マイグレーションファイルについて

Webアプリケーション上で扱われるデータの多くは、データベース管理システム(RDBMS)内に保存されます。

データベース管理システム内では、データベースというWebアプリケーションごとに区切られた場所と、ブログやユーザなど個々の情報を保存するためのテーブルという場所があります。

これらはExcelに構造が似ています。Excelのファイルがデータベース管理システムでいうデータベースにあたり、Excelのシートがデータベース管理システムでいうテーブルにあたります。

つまり、データベースの中にはたくさんのテーブルが存在し、そのテーブルの中でデータを管理しているのです。

https://diveintocode.gyazo.com/c8c86d1957b931d21f14abd550efc75b

では、そのテーブルはどのようにして作られるのでしょうか?そこで登場するのが マイグレーションファイル なのです。
マイグレーションファイルとは テーブルを作成するための設計図 です。

マイグレーションファイルには以下のような内容を記述します。
* なにテーブルを作成するか?(blogsテーブルなのか、usersテーブルなのか)
* どんなデータを管理したいのか(email、title、contentなど)

「どんなデータを管理したいのか」は カラム と言います。

https://diveintocode.gyazo.com/274b49d2ad0a1a7013fba8d24b775133

マイグレーションファイルはdb/migrate/の下に配置されているので早速見てみましょう。

db/migrate/◯◯◯◯◯◯◯◯◯◯_create_blogs.rbを開いて編集します。

class CreateBlogs < ActiveRecord::Migration
  def change
    create_table :blogs do |t|

      t.timestamps null: false
    end
  end
end

マイグレーションファイルの中身はこのようになっています。
カラムを作成する場合は、この中に欲しいカラムを追加します。

(例)

create_table :blogs do |t|
  t.欲しいカラムのデータ型 :カラムの名前
  t.欲しいカラムのデータ型 :カラムの名前

  t.timestamps null: false
end

データ型によって、どのような値を入れることができるかが決まります。
例えば、integerとすると数字しかいれることができませんし、stringとすると文字列のみ入れることができます。
t.timestamps null: falseは、新しくテーブルを作成するために、作成したマイグレーションファイルには、この文が自動的に挿入されます。

:pencil2: マイグレーションファイルを編集する。

t.string :titleとすることで、string型のカラムtitleを生成させます。
t.text :contentとすることで、text型のカラムcontentを生成させます。

class CreateBlogs < ActiveRecord::Migration
  def change
    create_table :blogs do |t|
      t.string :title
      t.text :content

      t.timestamps null: false
    end
  end
end

マイグレーションファイルを元にテーブルを作成するには、マイグレーション という処理を実行する必要があります。マイグレーションを行わない限りテーブルは作成されません。
ただし、Cloud9でマイグレーションをするにはCloud9の固有の設定をする必要があります。

Cloud9の固有の設定を行う

Cloud9では、他の開発環境と違って個別のデータベースの設定を行う必要があります。

:pencil2: データベースを起動する。

ターミナルで以下のコマンドを実行しましょう。

sudo service postgresql start

上記コマンドを実行して、データベース管理システムであるPostgreSQLをスタートさせます。

(注)
今後、カリキュラムを進めていく上で、

PG::ConnectionBad: could not connect to server: Connection refused
         Is the server running locally and accepting
         connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

このようなエラーがでる場合が、あります。その場合もsudo service postgresql startをターミナルで実行しましょう。

https://diveintocode.gyazo.com/bdc1b9fece0ca5a386ea8df670310a1b

:pencil2: PostgreSQLにフル権限ユーザとして接続する

sudo sudo -u postgres psql

実行後にpostgres=# と表示されればOKです。

:pencil2: PostgreSQLにOSのユーザ名と同名のユーザを登録する。

CREATE USER ubuntu SUPERUSER;

*(注)*
ERROR: role "ubuntu" already exists と表示されても大丈夫です。既にユーザが作成されていただけです。
この手順は、万が一ユーザが作成されていないと後の手順でエラーとなるために行っています。

完了したらPostgreSQL実行モードから抜け出します。

\q

:pencil2: 次に、config/database.ymlファイルを編集しましょう。

#省略
default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see rails configuration guide
  # http://guides.rubyonrails.org/configuring.html#database-pooling
  pool: 5
  template: template0

development:
#省略

template0と指定することで、独自のエンコーディング設定を行うことができます。

以上が、Cloud9の固有の設定です。
この時点で必要な知識では、ありませんので、特に理解する必要はありません。

:pencil2: マイグレーションを実行しましょう。

マイグレーションにより、未実行のマイグレーションファイルが実行されます。

rake db:create
rake db:migrate

rake db:createでデータベースを作成することができます。
アプリ(achieve)を作成した時点で、データベースは作成されていないので、このコマンドを実行する必要があります。
実行するのは、アプリごとに1回で良いです。

rake db:migrateでマイグレーションを実行します。また、これらのコマンドをまとめてrake db:create db:migrateとすることもできます。

https://diveintocode.gyazo.com/0b40379c438ec19835da1a6622d7be28

マイグレーションが完了するとこのような画面が出るはずです。

:pencil2: 実際にテーブルが作られたか、schemaファイルとデータベースにアクセスして確認してみる。

###schemaとは

schemaはマイグレーションの実行履歴が自動的に記述されるところです。

schemaは、db/schema.rbにあります。
実際に開いて確認しましょう。

省略
  create_table "blogs", force: :cascade do |t|
    t.string   "title"
    t.text     "content"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
省略

以上のように記述されていれば、テーブルが作成されています。
schema.rbを開くと、このように、blogsテーブルが作成されたことを確認することができます。

:pencil2: データベースにアクセスして、存在するテーブルを確認しましょう。

直接データベースのターミナルを起動して、SQL(データベースに命令を出す言語、モデルはRubyからSQLに翻訳している)を実行しましょう。

rails db

rails dbコマンドを実行すると、データベースのターミナル(console)を開くことができます。
ターミナルを開くと、このようにターミナルが起動されるはずです。

lasershow:~/workspace/achieve $ rails db
psql (9.3.11)
Type "help" for help.

achieve_development=#

それでは、ターミナルに命令を記述して実行しましょう。

\d

\dで現在存在しているテーブルを確認することができます。

achieve_development=# \d
               List of relations
 Schema |       Name        |   Type   | Owner  
--------+-------------------+----------+--------
 public | blogs             | table    | ubuntu
 public | blogs_id_seq      | sequence | ubuntu
 public | schema_migrations | table    | ubuntu
(3 rows)

q # endが表示されて、\dを打てない場合、qを押します

コマンドを実行するとこのように表示されます。きちんとblogsテーブルが作成されていることを確認できます。

Viewを確認する

データベースとテーブルを作成することができたので、次はViewです。
railsのMVC構造の話に戻りますが、ControllerはデータをViewに渡します。
この時、Controllerは何も指定がない場合、Controllerのアクション名と同じViewを指定します。

blogsコントローラのindexアクションが実行されていた場合、app/views/blogs/index.html.erbが指定されます。

:pencil2: app/views/blogs/index.html.erb を確認しましょう。

app/views/blogs/index.html.erbは、このような記述がされているはずです。

<h2Blogs#index</h2>
<p>Find me in app/views/blogs/index.html.erb</p>

つまり、blogs/indexアクションが実行された場合、レスポンスとしてこのViewに記述されているHTMLが返却され、ブラウザ上に表示されます。

###Webサーバを起動する

:pencil2: レスポンスを返すことができるか、Webサーバを起動させて確認しましょう。

Webサーバを起動させるためには、rails sコマンドを使用する必要があります。

rails s -b $IP -p $PORT

通常はrails sのみでWebサーバが起動しますが、Cloud9の仕様上後ろに-b $IP -p $PORTと追記する必要があります。

lasershow:~/workspace/achieve $ rails s -b $IP -p $PORT
=> Booting WEBrick
=> Rails 4.2.3 application starting in development on http://0.0.0.0:8080
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2016-04-05 03:53:18] INFO  WEBrick 1.3.1
[2016-04-05 03:53:18] INFO  ruby 2.3.0 (2015-12-25) [x86_64-linux]
[2016-04-05 03:53:18] INFO  WEBrick::HTTPServer#start: pid=4328 port=8080

Webサーバを起動させることができたら、このようにWEBrick::HTTPServer#startとでます。(Rails バージョン5以降では、WebサーバがWEBrickからPumaへ変更されています。)
では、Webサーバを起動させることができたので、実際にブラウザでリクエストを送って、レスポンスが返ってくることを確認します。
Cloud9では、予めWebサーバへアクセスするURLがはいったブラウザを起動させることができます。

:pencil2: Webサーバを起動させた後に、ポップアップされるURLをクリックしましょう。

(注)

ポップアップは、消してしまっても、再度`rails s -b $IP -p $PORT`を実行すれば表示されます。
命令を出すためには、control + cを押してWebサーバの起動を終了させる必要があります。

https://diveintocode.gyazo.com/6149ab6396c2a7728a628a4e609d6a91

URLをクリックすると自動的にWebサーバへのURLが実行されているブラウザのタブが起動します。

https://diveintocode.gyazo.com/9afe70840de02c539b84d779ebae3c65

ブラウザが起動すると、このような画面が表示されます。
これは、rootに何も指定していない場合、railsがこの画面を表示させてくれるためです。
rootとは、サーバだけのURLのことを示します。

Cloud9の場合、Webサーバのrootは、https://ide.c9.io/ユーザ名/workspace名です。
rootに何を表示させるかは、設定することができます。

:pencil2: URLにblogsを追加して、blogsのindexアクションを実行しましょう。

https://diveintocode.gyazo.com/4464148d00c553b66a62072a6fb8ea43

https://diveintocode.gyazo.com/0ec6ff0b3b082fca76f1ada3abfafc2f

このように、先ほどのblogs/index.html.erbが表示されました。

これで、MVCの流れについては、一通り学ぶことができたので、次からは実際にブログの機能を実装していきましょう。

CRUDについて

ブログの機能を作成する前に、CRUD( "クラッド" と読みます。)について知る必要があります。

CRUDとは、Webアプリケーションには基本となる4つの機能のことです。
ページの新規作成(Create)、表示(Read)、更新(Update)、削除(Destroy)です。それぞれの頭文字を取ってCRUDと呼ばれています。
大規模なWebアプリケーションも、このCRUDを基礎として作られます。

つまり、ブログもこのCRUDの機能を持ったものを作成していくことになります。

ブログ作成機能を実装する

ここからは、ブログを作成する機能を作成します。まず、どのようにブログを作成するのか流れを確認しましょう。
ブログを作成するためには、

  • ユーザにブログの内容を入力してもらう
  • 内容をデータベースに保存する

以上の内容が必要になります。
つまり、

  • ユーザに編集画面を提供するアクション
  • 入力されたデータをデータベースに保存するアクション

以上の二つのアクションが必要になります

https://diveintocode.gyazo.com/f86993245e6b829ba77a183af2c46edc

Routingを編集する

それでは、config/routes.rbを編集して、newアクションとcreateアクションに必要なroutingを編集します。
先ほどは、独自にroutingを設定しましたが、今回はrailsに予め用意されている、resourcesメソッドを使用して、routingを生成しましょう。

resoucesメソッドを使用することで、CRUD(作成・読み取り・更新・削除)を実現するためのroutingが、
適切なHTTPメソッド(get/post/patch/delete)と組み合わされた上で自動的に生成されます。

:pencil2: resourcesメソッドを使用して、routingを使用しましょう。

config/routes.rb

Rails.application.routes.draw do
  resources :blogs

  # The priority is based upon order of creation: first created -> highest priority.
  # See how all your routes lay out with "rake routes".

:pencil2: rake routesコマンドでルーティング定義を確認しよう。

ターミナルで rake routesコマンドを実行すると以下のように、実際に設定されているroutingを確認することができます。

lasershow:~/workspace/achieve $ rake routes
   Prefix Verb   URI Pattern               Controller#Action
    blogs GET    /blogs(.:format)          blogs#index
          POST   /blogs(.:format)          blogs#create
 new_blog GET    /blogs/new(.:format)      blogs#new
edit_blog GET    /blogs/:id/edit(.:format) blogs#edit
     blog GET    /blogs/:id(.:format)      blogs#show
          PATCH  /blogs/:id(.:format)      blogs#update
          PUT    /blogs/:id(.:format)      blogs#update
          DELETE /blogs/:id(.:format)      blogs#destroy
lasershow:~/workspace/achieve $

このように、index/create/new/edit/show/update/destroyへのroutingが生成されているのが分かります。
updateへのroutingが2個生成されているのは、後の仕様でpatchが追加されたためです。特に気にする必要はありません。

URL                     アクション名 HTTPメソッド 説明
/XXXs(.:format)         index     GET         一覧画面を生成
/XXXs/:id(.:format)     show        GET       詳細画面を生成
/XXXs/new(.:format)     new       GET         登録画面を生成
/XXXs(.:format)         create    POST      登録処理をする
/XXXs/:id/edit(.:format)edit        GET       編集画面を生成
/XXXs/:id(.:format)     update    PUT         更新処理を行う
/XXXs/:id(.:format)     destroy   DELETE      削除処理を行う

(参考) http://railsdoc.com/references/resources より

また、prefixとありますが、prefixを利用すると、Viewで利用するlink_to メソッドや、redirect メソッドなどで必要とするパスの指定を簡単に書くことが出来ます。

これで、ブログのCRUD機能に必要な、routingを実装することができました。
しかし、今回必要なのは、これまでに実装していたindexアクションと、これから実装するnew・createアクションだけです。

/rails/info/routesにアクセスしてroutingを確認する方法

サーバーを起動した状態であれば、以下のように(サーバーのアドレス)/rails/info/routesにアクセスすることでroutingを確認する方法もあります。

https://diveintocode.gyazo.com/4d6dc9f5c9a69aaff3cc401776071c60

サーバーを起動した状態でないと使用できませんが、こちらの方が早い場合があるので、試してみてください。

:pencil2: onlyオプションを使用して、これらのroutingを実装しましょう。

config/routes.rb

Rails.application.routes.draw do
  resources :blogs, only: [:index, :new, :create]

  # The priority is based upon order of creation: first created -> highest priority.
  # See how all your routes lay out with "rake routes".

編集することができたら、rake routesコマンドで必要なroutingだけを実装することができているか確認しましょう。

lasershow:~/workspace/achieve $ rake routes
  Prefix Verb URI Pattern          Controller#Action
   blogs GET  /blogs(.:format)     blogs#index
         POST /blogs(.:format)     blogs#create
new_blog GET  /blogs/new(.:format) blogs#new

このように、onlyオプションを使用すると必要なroutingだけを生成することができます。
Webアプリケーションはブログ機能だけでは終わらないので、当然ながらルーティングはこれから膨大な量になっていきます。
なのでできるだけonlyオプションを使用して、不要なルーティングを定義しないようにします。

Check Point !!

`rake routes` により定義したルーティングを確認することができる。

アクションを作成する

:pencil2: コントローラを編集しましょう。

アクションはコントローラにメソッドとして定義します。
アクションが実行されるとアクションと同名のメソッドが実行されます。
メソッドは、day00-2でも学びましたが、def と endを記述することで宣言することができます。

def メソッド名
end

app/controllers/blogs_controller.rb

class BlogsController < ApplicationController
  def index
  end

  def new
  end

  def create
  end
end

Viewを作成する。

Blog機能に必要なモデルやテーブルは既に実装してあるため、newアクションのViewファイルを作成しましょう。

まずnewアクションでは、ユーザにブログの内容を入力させる欄(フォーム)が必要になります。
Railsでは、HTMLを自動的に生成してくれる、ビューヘルパーというものが用意されています。

今回は、ビューヘルパーの一種である、form_forを使用して、フォーム作成します。これを使用することで、モデルに関連づいたフォーム(HTMLのformタグ)を作成することができます。
入力されたデータをモデルと結び付けられるフォームを作成することができます。

:pencil2: form_forを使用してフォームを作成します。

app/views/blogs/new.html.erb
以上のファイルを作成して、下記に編集しましょう。

<%= form_for do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <br>
  <%= f.label :content %>
  <%= f.text_field :content %>
  <br>
  <%= f.submit %>
<% end %>

form_forとすることで、フォームであることを宣言しています。
f.label :カラム名とすることで、指定したモデルカラムへのラベルを作成することができます。
f.text_filed :カラム名とすることで、指定したモデルカラムへのテキスト欄(フォーム)を作成することができます。
また、brタグを使用することでそれぞれの入力欄を改行しています。
endはform_forを終わりを宣言しています。
それぞれRuby文が<%= %>で囲われているのは、erbの中でRuby文を使用するためには、<%= %>で囲うというルールがあるためです。
<% end %>が=がないのは、終了を宣言するendは画面に出力させる必要がないからです。
<% %>と=をつけないと、Ruby文は実行するが、画面には出力しなくなります。

変数を定義する

フォームをViewに記述することができましたが、form_forはこれだけでは、使用することができません。
form_forはモデルと結びつくフォームを作成するビューヘルパーです。従って、モデルのデータをコントローラから渡して上げる必要があります。

:pencil2: blogsコントローラに変数を定義してViewファイルにデータを渡しましょう。

class BlogsController < ApplicationController
  def index
  end

  def new
   @blog = Blog.new
  end

  def create
  end
end

@blogとすることでインスタンス変数を定義しています。通常の変数と異なりインスタンス変数は、Viewファイルに渡されます。
通常の変数の場合、Viewファイルには渡されません。
この場合、データをViewファイルに渡したいので、@をつけることでインスタンス変数であることを宣言しています。

Blog.newとすることでBlogモデルのインスタンスを生成しています。newメソッドをすれば、レシーバのモデルの情報を引き継いだインスタンスを生成することができます。

form_forに生成した変数を渡す

さきほど,@blog変数をblogsコントローラのnewアクションに定義できたことで、new.html.erbファイルに@blog変数が自動的に渡されます。
しかし、まだViewに渡されている状態にすぎないため、自分でform_forに変数を渡す必要があります。

:pencil2: @blogをform_forに渡す。

<%= form_for(@blog) do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <br>
  <%= f.label :content %>
  <%= f.text_field :content %>
  <br>
  <%= f.submit %>
<% end %>

これでform_forがフォームを出力するために必要な情報を与えることができました。

:pencil2: フォームを作成することができているか、newアクションにアクセスして確認しましょう。

事前にWebサーバを起動している場合は、control + cで停止してからもう一度起動させましょう。

rails s -b $IP -p $PORT

起動したらURLに/blogs/newを追記しましょう。
※このようなエラー画面がでたら、一度Webサーバを停止して以下のコマンドを実行しましょう。

https://diveintocode.gyazo.com/919342c3aa7dfcc4ee09b066a75bee97

sudo service postgresql start

https://diveintocode.gyazo.com/d7b312a2df38514792219bf62831c74c

フォームを作成することができると、このような画面が表示されるはずです。

:pencil2: フォームに値を入力して、送信してみましょう。

https://diveintocode.gyazo.com/7ce3f5385deae449195a8b926bd14d6d

フォームをこのように記述して送信すると、

https://diveintocode.gyazo.com/88758f1552715095ae1a0a58177f8fc0

このようなエラーが表示されます。
これは、form_forで自動的にcreateアクションへのリクエストが起動しますが、createアクションのViewがまだ作成されていないためです。

この状態で、Cloud9内のWebサーバを立ち上げているターミナルを確認しましょう。
ログを遡ると、このような記述を発見することができるはずです。

https://diveintocode.gyazo.com/3e1948fc76399ce2762e4341bdc05773

Started POST "/blogs" for 222.150.216.98 at 2016-04-08 02:15:27 +0000
Cannot render console from 222.150.216.98! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by BlogsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"k+sOu9TE/6X6/8zT034kz+kEBs6A0t+a0ZxXe57eRUn1qyhZGuQfbo8Fu0SlO4drxLg5sdAl2M6hZ+9QZL6izw==", "blog"=>{"title"=>"ブログ始めました!", "content"=>"冷やし中華始めました!"}, "commit"=>"Create Blog"}
Completed 500 Internal Server Error in 9ms (ActiveRecord: 0.0ms)

ActionView::MissingTemplate (Missing template blogs/create, application/create with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}. Searched in:
  * "/home/ubuntu/workspace/achieve/app/views"
):

Started POST "/blogs"これは、rake routesコマンドを実行して確認すればわかるのですが、
createアクションを起動させるためのリクエストが送信されたことを意味しています。

フォームで入力されたものは、parametersという箱のような物の中に入れられて次のアクションに送信されます。

  Parameters: {"utf8"=>"✓", "authenticity_token"=>"k+sOu9TE/6X6/8zT034kz+kEBs6A0t+a0ZxXe57eRUn1qyhZGuQfbo8Fu0SlO4drxLg5sdAl2M6hZ+9QZL6izw==", "blog"=>{"title"=>"ブログ始めました!", "content"=>"冷やし中華始めました!"}, "commit"=>"Create Blog"}
Completed 500 Internal Server Error in 9ms (ActiveRecord: 0.0ms)

さきほど、私が送信した内容が、parametersになって次のアクションに渡されているということが確認できるかと思います。

従って、createアクションでは、このparametersを取得して、値を保存させるということが必要になります。

createアクションを完成させる

送信されてきたparametersを取得するためには、paramsメソッドを使用する必要があります。

  Parameters: {"utf8"=>"✓", "authenticity_token"=>"k+sOu9TE/6X6/8zT034kz+kEBs6A0t+a0ZxXe57eRUn1qyhZGuQfbo8Fu0SlO4drxLg5sdAl2M6hZ+9QZL6izw==", "blog"=>{"title"=>"ブログ始めました!", "content"=>"冷やし中華始めました!"}, "commit"=>"Create Blog"}
Completed 500 Internal Server Error in 9ms (ActiveRecord: 0.0ms)

例えば、このようなリクエストが送られてきた場合、params[:blog]とすれば、

"blog"=>{"title"=>"ブログ始めました!", "content"=>"冷やし中華始めました!"}

を取得することができます。
このparamsメソッドを駆使すれば、newアクションで入力された値を保存することができます。

データベースに値を保存させるためには、以下の2つの方法があります。

・createメソッドで値を保存する
・newメソッドで、空のインスタンスを作成し、値を代入した上で保存する。

createメソッドまたは、newメソッドで空のインスタンスを作成した後に、saveメソッド使用する必要があります。
その際に、特定の値を引数としてメソッドに渡してあげれば、データベースに保存することができます。
例えば、titleが"ブログ始めました!",contentが"冷やし中華始めました!"のブログを作成したい場合は、このようにします。

(例)

Blog.create(title: "ブログ始めました", content:"冷やし中華始めました!")

new/saveメソッドを使用するためには、一度newメソッドで生成したインスタンスを変数に入れる必要があります。

(例)

blog = Blog.new(title: "ブログ始めました", content:"冷やし中華始めました!")
blog.save

:pencil2: createアクションにブログを保存する処理を定義する。

先ほど学んだ、paramsメソッドと、createメソッドをもとにブログを保存する処理を作成しましょう。

app/controllers/blogs_controller.rb

class BlogsController < ApplicationController
  def index
  end

  def new
   @blog = Blog.new
  end

  def create
    Blog.create(params[:blog])
  end
end

Blog.create(params[:blog])とすることで、createメソッドに,newアクションから渡された値(params[:blog])を渡し、ブログの保存を試みています。
しかしながら、これではブログを保存できません。これはrails内でparamsメソッドを使用する場合は、ストロングパラメータを使用する必要があるためです。

ストロングパラメータとは

ストロングパラメータを使用すると、parametersから取得することができる値を制限することができます。

具体的には、Railsのセキュリティ上の問題として、Mass-assignment(マス・アサインメント脆弱性)があります。
Mass-assignmentとは、parametersから送られてきたデータに、意図せず悪意のあるデータが送られてきた時に、そのデータも一緒に取得してしまうという問題です。

例えば、あるツールを使用すれば、フォームを送信するときに、自分でフォームにはない値を紛れ込ませることが可能になります。その時に、自分は管理ユーザであるという値を渡せることもできます。
ストロングパラメータを使用していないアプリケーションの場合、この管理ユーザであるという値が送信されてしまい、なりすますことが可能になります。

これが、Mass-assignmentであり、ストロングパラメータを使用する理由です。

しかしながら、現在のRailsアプリケーションでは、ストロングパラメータを使用しないとアプリケーションを構築できないような設定になっています。
(ストロングパラメータを設定しないとエラーが、発生する)

:pencil2: ストロングパラメータを使用して値を取得しましょう。

app/controllers/blogs_controller.rb

class BlogsController < ApplicationController
  def index
  end

  def new
   @blog = Blog.new
  end

  def create
    Blog.create(params[:blog])
  end

  private
    def blogs_params
      params.require(:blog).permit(:title, :content)
    end
end

ストロングパラメータ用のメソッドとして、blogs_paramsを定義しています。

params.require(:blog)とすることで、paramsメソッドで取得したものの中のblogに関する情報だけを許可します。
params.require(:blog).permit(:title, :content)とすることで、更に、titleとcontentだけを許可しています。

例えば、"blog"=>{"title"=>"ブログ始めました!", "content"=>"冷やし中華始めました!","tag"=>"food"}というparametersが送られてきたとしても、
tagという値は取得されないということになります。

また、blogs_paramsメソッドは外部から読み込まれないように、privateを定義して、その中に入れています。
private内に定義する理由は、他のコントローラなどからメソッドを呼び出せないようにするためです。
例えば、blogs_controllerで定義したblogs_paramscontacts_controllerで呼び出せてしまうと、contacts_controllerで意図していないパラメータを受け取ることができてしまいます。
上記のようなことを防ぐために、他から参照する必要のないメソッドはprivate下に定義しましょう。

https://diveintocode.gyazo.com/e0a9225476538490aea1bd863404dee5

ちなみにprivateendで囲う必要はなく、privateより下に定義したメソッドは全て外部から読み込めなくなるため、アクションは定義しないようにしましょう。
ex) ダメな例

private
 def edit
 end

Check Point !!

`ストロングパラメータ`により不正なパラメータを排除することができる。

parametersをもとに、createする

:pencil2: paramsメソッドとストロングパラメータでパラメータを取得することができたので、createメソッドに取得したパラメータを渡して、保存しましょう。

app/controllers/blogs_controller.rb

class BlogsController < ApplicationController
  def index
  end

  def new
    @blog = Blog.new
  end

  def create
    Blog.create(blogs_params)
  end

  private
    def blogs_params
      params.require(:blog).permit(:title, :content)
    end
end

これで、ブログを作成するロジックを作成することができました。

redirect_to メソッドとは

redirectto メソッドを仕様することで、redirectto メソッドで指定したURLに、その時点でHTTP通信を発生させます。

redirect_to :action => "show" # showアクションにリダイレクト
redirect_to 'http://diveintocode.jp/' # diveintocode.jpページにリダイレクト
redirect_to controller: :blogs, action: :new #blogsコントローラのnewアクションにリダイレクト

https://diveintocode.gyazo.com/433eea51258d0befe72cbdefaa4c23dc

現在のブログ機能では、createアクションに対してのViewがないために、エラーが起こってしまいます。
そこで、ブログを作成するcreateメソッドを実行した後は、indexアクション(一覧画面)が起動するようにしましょう。

:pencil2: コントローラで、違うアクションを実行するためにredirect_to メソッドを記述します。

app/controllers/blogs_controller.rb

class BlogsController < ApplicationController
  def index
  end

  def new
    @blog = Blog.new
  end

  def create
    Blog.create(blogs_params)
    redirect_to blogs_path
  end

  private
    def blogs_params
      params.require(:blog).permit(:title, :content)
    end
end

redirect_to blogs_pathとすることで、blogsコントローラのindexアクションにリダイレクトすることができます。

それでは、実際にうまく機能するか確かめましょう。
まず、フォームを送信して、index画面に切り替われば、redirectto メソッドが機能していることを確認できます。
この`blogs
pathというのは,rake routes`コマンドのprefixで確認することができます。

:pencil2: rails consoleコマンドを使用して、データベースに値が保存されているか確認しよう。

rails c

rails cを実行すると、railsコンソールが起動するので、データベースにデータを取得させる命令を出しましょう。

Blog.all

allメソッドを使用すると、テーブルにあるデータすべてを取得することができます。
この場合、blogsテーブルのすべてのデータを取得することができます。

lasershow:~/workspace/achieve $ rails c
Running via Spring preloader in process 4114
Loading development environment (Rails 4.2.3)
2.3.0 :001 > Blog.all
  Blog Load (0.6ms)  SELECT "blogs".* FROM "blogs"
 => #<ActiveRecord::Relation [#<Blog id: 1, title: "aa", content: nil, created_at: "2016-04-05 03:38:07", updated_at: "2016-04-05 03:38:07">, #<Blog id: 2, title: "こんにちは", content: "", created_at: "2016-04-08 11:24:42", updated_at: "2016-04-08 11:24:42">, #<Blog id: 3, title: "こんにちは", content: "", created_at: "2016-04-08 11:24:45", updated_at: "2016-04-08 11:24:45">]>
2.3.0 :002 >

このように送信した値を取得することができたら成功です。

indexアクションで保存した、値を表示させる

ブログ保存機能を実装することができたので、indexアクションで、ブログ一覧画面を表示させましょう。
一覧画面表示させるために、allメソッドでデータをすべて取得し、eachメソッドでひとつずつ表示させるという形をとります。

:pencil2: indexアクションを定義する。

すべてのブログを取得する処理をindexアクションに定義します。

app/controllers/blogs_controller.rb

class BlogsController < ApplicationController
  def index
    @blogs = Blog.all
  end
#省略

:pencil2: ブログ一覧表示用のViewを定義する。

indexアクションで定義した@blogsを表示するためのViewを定義します。

app/views/blogs/index.html.erb

<h2>ブログ一覧</h2>

<% @blogs.each do |blog| %>
  <p>タイトル:<%= blog.title %></p>
  <p>本文:<%= blog.content %></p>
<% end %>

:pencil2:実際に機能しているか確かめてみましょう。

https://diveintocode.gyazo.com/0b495460f23196de04ad5e9d40d6dc02

このように、ブログ投稿しているものが表示されたら成功です。

リンクを作成しましょう。

ブログの一覧表示機能、作成機能は作成することができましたが、一覧機能から作成機能に移るときに、いちいちURLを打ち込む必要があります。
そこで、リンクを作成してindexとnewを行き来できるようにしましょう。

リンクを作成するためには、ビューヘルパーであるlink_toメソッドを使用します。

:pencil2:link_toメソッドを定義してリンクを作成しましょう。

app/views/blogs/index.html.erb

<h2>ブログ一覧</h2>

<% @blogs.each do |blog| %>
  <p>タイトル:<%= blog.title %></p>
  <p>本文:<%= blog.content %></p>
<% end %>

<%= link_to "ブログを作成する", new_blog_path %>

link_toメソッドの最初の引数には、どのような名で表示させるかを渡します。この場合"ブログを作成する"と表示されます。
次の引数には、リンクを踏むとどこに移動するかを渡します。この場合、ブログ作成画面(newアクション)に移動して欲しいのでnew_blog_pathとしています。

このnew_blogというのは、rake routesを確認した時に現れる、prefixを利用したものです。urlを指定せずとも、prefixを指定することで自動的に、URLを展開してくれます。
urlを指定しなくてもよいため、どの機能に移動させているのかが、分かりやすくなっています。

https://diveintocode.gyazo.com/15ab9df57d00fe1eaa26710835b3a487

これで、リンクを作成することができました。
次にnew画面からも移動できるようにしましょう。

:pencil2: new画面にもindex画面へのリンクを設定する。

app/views/blogs/new.html.erb

<%= form_for(@blog) do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <br>
  <%= f.label :content %>
  <%= f.text_field :content %>
  <br>
  <%= f.submit %>
<% end %>

<%= link_to "ブログ一覧画面にもどる", blogs_path %>

同じようにprefixのblogs_pathを使用しています。

DIVE01課題

・テキストで作成した、ブログ機能が正常に動作すること
・DIVE01では、ブログ作成画面、作成機能をもったブログ機能を作成しました。これと同じような機能を持ったお問い合わせ機能を作成すること。(詳細は以下)

満たすべき要件

お問い合わせに一覧画面は必要ない

1. お問い合わせ機能のコントローラ(contacts controller)を作成する。
2. アクションはnewとcreate
3. newアクションでフォームを作成し、createで保存する、保存したらnewアクションにredirectする
4. routingはresoucesメソッドで作成する、onlyオプションも使用する
5. Viewの作成方法は、フォルダ右クリックからnewファイルするか、Controllerを作成する際にオプションで作成する
6. フォームはform_forメソッドで作成する
7. contactsテーブルのカラムは(nameとemailとcontent)

課題に取り組んでみましょう。ご質問等がありましたら、無料説明会にて承ります。

DIVE INTO CODEの無料説明会を開催中

ハイレベルなプログラミングに入門したい方、フリーランスエンジニアになりたい方、
つくりたいアプリがある方、一歩前へ踏み出すお手伝いいたします。

無料説明会はこちら