Ruby on Railsでのアプリケーションの開発
こんにちはPoSoと申します。現在地元の受託IT企業でインターンをしています。
プログラミングスクールにてHTML、CSS、JavaScript、フレームワークのNode.js、Vue.jsを学習し、現在フロントエンドのエンジニアとして仕事ができるようRubyとRailsの学習を進めています。今回はその学習で得た知識をアウトプットするべく記事を書いてみることにしました。
MVCアーキテクチャ
Model・View・Controllerのそれぞれの頭文字を取ったもので、処理を3つの役割に分割して実装する手法をいいます。Railsではこれが採用されており、理解が必要です。簡単にそれぞれの役割を説明すると、
Model
・データベースアクセスなどデータ関連処理
View
・画面表示
Controller
・リクエストやレスポンスを制御
・ViewとModelの橋渡し
となります。
役割ごとに分けてコードを書くことで、プログラム全体の見通しが良くなり、メンテナンス性が高まるというメリットがあります。
詳しくは以下参照。
アプリケーション制作の流れ
1.新規Railsプロジェクトの作成
$ mkdri rails_projects
$ cd rails_projects/
$ rails _6.0.2_ new hello
$ cd hello/
作業ディレクトリを作成後、中に入ってrails newコマンドを打ちます。Railsのバージョンを指定したい場合は上のようにアンダースコアで囲って指定します。ディレクトリを移動して以下作業に入ります。
2.ジェネレータ(controller作成)
$ rails generate controller users index
rails generate controller でcontrollerを作成しなさいという指示になります。generateはgと省略可能です。
usersはcontrollerにつける名前です。ここではusersとしていますが任意に変更可能です。controller名はデータベースと直接紐づかない場合を除き、基本的に複数形が一般的です。
indexはアクションと言われ、このusersクラスcontroller内に定義するメソッド名です。アクションについての詳しい解説は以下を参照。
3.サーバー起動
Railsにはwebサーバー機能が備わっており、簡単にwebアプリケーションの動作確認が行えます。以下コマンドを入力します。
$ rails server
serverはsと省略可能です。開発環境によってURLは様々だと思いますが、コンソールに表示されたURLを開きます。
このようなウェルカム画面が表示されます。
4.ルーティング
ルーティングとは何なのか、まずは公式ガイドを見てみます。
Railsのルーターは受け取ったURLを認識し、適切なコントローラ内アクションに割り当てます。ルーターは、ビューでこれらのパスやURLを直接ハードコードすることを避けるためにパスやURLを生成することもできます。
RailsGuides:https://railsguides.jp/routing.html
つまり簡単に言うと、Railsアプリケーションのコントローラへ指示を出すための道筋 です。
ユーザーがwebページへのアクセスを要求するとサーバーへリクエストが送られます。その送られてきたリクエストに対して、ルーティングで適切なコントローラーへ割り当てていく機能ということです。
まずはコンソールでURLとアクションの対応表を表示してみます。
$ rails routes
Prefix はパスを指定する時に使います。
Verb は“動詞”と日本語訳されます。一般的にはHTTPメソッドやHTTPリクエストメソッドと呼ばれます。(GET、POST、DELETEなど)
こちらで詳しくまとめられていました。
URI Pattern はざっくりいうとURLのことです。いわゆるアドレスです。
Controller#Action は記載の通りです。
例えば、users コントローラーのindex アクションを実行するには、/users/index でアクセスすればよいということです。
(.:format) は必須ではないパラメータなのでここでは無視で大丈夫です。.json、.xml といった拡張子が入ることがあります。
そしてこのような設定はhello/config/routes.rb で定義されています。URLと実行するプログラムの関係を記述するファイルです。
hello/config/routes.rb
Rails.application.routes.draw do
get 'users/index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
このコードは users/index のURLでアクセスしたら、users コントローラーのindex アクションを実行しなさいという意味です。この記述は rails generate controller したときに自動で追加されました。このコードは、
Rails.application.routes.draw do
get 'users/index' , to: 'users#index'
end
上記の省略形です。
それでは users にアクセスしたら、users コントローラーの index アクションを呼ぶように書き換えてみます。
Rails.application.routes.draw do
get 'users' , to: 'users#index'
end
rails routes コマンドで確認します。
URI Pattern が /users だったら、users コントローラーの index アクションを呼ぶという記述に書き換わりました。
5.ジェネレータ(Modelの作成)
2のcontrollerの作成でusers controller を作成したので、ユーザーを管理するUserモデルを作成しようと思います。
ユーザーは、名前(name)、年齢(age)というデータを持つとします。
$ rails g model user name:string age:integer
モデル名は単数形にします。テーブルの構造は、カラム名:データ型 のように記述します。主なデータ型には、
・integer‥‥整数
・float‥‥小数
・string‥‥文字列
・text‥‥長い文字列
・boolean‥‥真偽値
などがあります。
app/models/user.rb
db/migrate/[timestamp]_create_users.rb
この2つのファイルが生成されていることを確認します。[timestamp]には作成時の日時が入ります。
$ rails db:migrate
これでマイグレーションが完了しました。マイグレーションとはデータベースのテーブルの構造に変更を加えることです。ざっくりいうと、ジェネレータがコピー、マイグレーションがペーストの役割をしているイメージです。詳しくは以下サイトでまとめられています。
6.Viewの作成
rails g controller を実行した際、View のファイルが作成されています。
app/views/users/index.html.erb
<h1>Users#index</h1>
<p>Find me in app/views/users/index.html.erb</p>
これを編集してwebページの画面を作っていきます。
ERBとは、Enbedded RuBy の略で、HTMLの中にRubyのプログラムを埋め込むことができる技術のことです。ERBに書かれたRubyのコードが書かれたHTMLは、ユーザーに表示される前にRubyやRuby on Railsによって処理され、最終的にはHTMLとしてユーザーには表示されます。
ViewファイルでのRubyコードの書き方は以下サイトにまとまっています。
Gem(ライブラリ)の導入
今回はBootstrapの導入を例にしていきます。ディレクトリ直下のGemfileを開き、わかりやすいように一番下に追記していきます。
Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
...
gem 'bootstrap', '~> 4.1.1'
gem 'jquery-rails', '~> 4.3.1'
Bootstrapではjqueryに依存する部分があるので一緒に導入します。
$ bundle install
Gemのインストールを行います。bundle installはbundleと略せます。
手順は以下でも確認できます。
続いてapplication.cssの拡張子を.scssに変更します。ファイルエクスプローラーからの操作か、以下コマンドを入力します。
$ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
application.scssを開いて追記します。すでに書かれているコードは全て削除してしまって大丈夫です。
app/assets/stylesheets/application.scss
@import "bootstrap";
application.jsを編集します。上で貼ったページリンクからコピペします。
この部分です。
app/assets/javascripts/application.js
...
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery3
//= require popper
//= require bootstrap-sprockets
//= require_tree .
以上で完了となります。
Seedsファイルを使った初期データの投入
ViewにRubyのコードを書いたがデータがないためきちんと表示されているかわからない。そんな時にこの方法を利用します。
db/seeds.rbに記述するだけです。今回僕はモデルを
$ rails g model question name:string title:string content:text
このように作成したので、
db/seeds.rb
Question.create(id: 1, name: 'Test name 1', title: 'Test question 1', content: 'Test content 1')
Question.create(id: 2, name: 'Test name 2', title: 'Test question 2', content: 'Test content 2')
Question.create(id: 3, name: 'Test name 3', title: 'Test question 3', content: 'Test content 3')
作成したカラムの通りにデータを入れます。
最後にコマンドを入力します。
$ rails db:seed
エラーが出なければOKです。
フォームヘルパー
開発者が煩雑になりがちなHTMLを書かなくても、formに関するHTMLを自動で生成してくれるメソッドのことを言います。
現在はRails5.1で導入されたform_withヘルパーが推奨となっており、逆に今まで利用されてきたform_forヘルパーとform_tagヘルパーは非推奨になっています。
実際のコードで見比べてみます。
<%= form_with model: @question, local:true do |f| %>
<div class="form-group">
<lavel>Name</lavel>
<%= f.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<lavel>Title</lavel>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<lavel>Content</lavel>
<%= f.text_area :content, class: "form-control" %>
</div>
<div class="text-center">
<%= f.submit "Save", class: "btn btn-primary" %>
</div>
<% end %>
local:trueについては、form_withで生成されたフォームのデフォルトは非同期通信で処理されるのですが、それを無効とするオプションです。
このコードが実際に出力されると、
<form action="/questions" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="hk3rxZZRvNdHoXmn/seVJcSZyR6C6GISLCmxlKQUxR4nyqIO/la5ggx0WviUzDNKH/a3kbSatuS/KaoijQ2t8w==">
<div class="form-group">
<lavel>Name</lavel>
<input class="form-control" type="text" name="question[name]" id="question_name">
</div>
<div class="form-group">
<lavel>Title</lavel>
<input class="form-control" type="text" name="question[title]" id="question_title">
</div>
<div class="form-group">
<lavel>Content</lavel>
<textarea class="form-control" name="question[content]" id="question_content"></textarea>
</div>
<div class="text-center">
<input type="submit" name="commit" value="Save" class="btn btn-primary" data-disable-with="Save">
</div>
</form>
このように自動的にテキストボックス、テキストエリア、送信ボタンが生成されています。
ストロングパラメーター
Web上から入力されてきた値を制限することで、不正なパラメータを防ぐ仕組みのことを言います。
使用例
def question_params
params.require(:question).permit(:name, :title, :content)
end
requireは「必要とする」, permitは「許可する」という意味の英単語です。
つまりparams[:question][:name]はOKだけどparams[:name]やparams[:question][:points]は受け入れられません。
1.requireというメソッドでPOSTで受け取る値のキー設定
2.permitメソッドで許可して受け取る値を制限
なぜストロングパラメータをしようするのかというと、フォームから送られてくるデータはブラウザの機能によって簡単に書き換え可能だからです。
仮にデータベースのテーブルにポイントを管理するpointというカラムがあったとして、そのポイント数をユーザーが任意に変更できてしまうという致命的な脆弱性を発生させてしまう可能性が高まります。
そのためフォームから送信されたデータparamsは信頼できないデータとして処理を行う必要があるのです。
バリデート
値が正当かどうか確かめる処理を言います。
例えば、フォームの入力欄が空の状態でも空の状態できてしまう状態をバリデートを用いて改善することができます。
app/models/question.rb
class Question < ApplicationRecord
validates :name, presence: true
validates :title, presence: true
validates :content, presence: true
end
これで上記のカラムが入力必須項目となり、空の状態で保存できなくなりました。
リファクタリング
プログラムを外部から見た時の動作を変えずに、ソースコードを整理することです。
完璧を求めすぎると開発が進まなかったり、納期に間に合わなくなってしまうので、まずは動作するプログラムを書くことを優先します。
そして、きりの良いタイミングや時間的余裕がある時にこれを行います。
例としては、
app/views/questions/edit.html.erb
<div>
<div class="col-md-4 offset-md-4">
<h2 class="text-center">Edit question</h2>
<%= form_with model: @question, local:true do |f| %>
<div class="form-group">
<lavel>Name</lavel>
<%= f.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<lavel>Title</lavel>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<lavel>Content</lavel>
<%= f.text_area :content, class: "form-control" %>
</div>
<div class="text-center">
<%= f.submit "Save", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
app/views/questions/new.html.erb
<div>
<div class="col-md-4 offset-md-4">
<h2 class="text-center">New question</h2>
<%= form_with model: @question, local:true do |f| %>
<div class="form-group">
<lavel>Name</lavel>
<%= f.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<lavel>Title</lavel>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<lavel>Content</lavel>
<%= f.text_area :content, class: "form-control" %>
</div>
<div class="text-center">
<%= f.submit "Save", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
このように同じコードが書いてあるファイルが複数あった場合に、共通化部分を保存するファイルを作成し読み込むことで解決できます。
例えば_form.html.erbというファイルを作成し、共通部分を移動します。
この時、共通化して呼び出すファイルの名前はアンダースコアから始めるのがルールです。
app/views/questions/_form.html.erb
<%= form_with model: @question, local:true do |f| %>
<div class="form-group">
<lavel>Name</lavel>
<%= f.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<lavel>Title</lavel>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<lavel>Content</lavel>
<%= f.text_area :content, class: "form-control" %>
</div>
<div class="text-center">
<%= f.submit "Save", class: "btn btn-primary" %>
</div>
<% end %>
edit.html.erbとnew.html.erbに呼び出します。
app/views/questions/edit.html.erb
<div>
<div class="col-md-4 offset-md-4">
<h2 class="text-center">Edit question</h2>
<%= render 'form' %>
</div>
</div>
app/views/questions/new.html.erb
<div>
<div class="col-md-4 offset-md-4">
<h2 class="text-center">New question</h2>
<%= render 'form' %>
</div>
</div>
この時に、'form'とアンダースコアを取って指定する点に注意します。
この記事が気に入ったらサポートをしてみませんか?