はじめに
とある事情によりruby on railsでアプリ開発することになったのでとりあえずチュートリアルやってみる。
今回やってみるチュートリアルはこちら
https://guides.rubyonrails.org/getting_started.html
ruby on railsの公式ガイド(だと思う)です。
おそらく日本語訳とかそういうのはありふれてると思うので、rubyすら知らない段階から初めてつまづいたところや分かりにくかったところを残しておこうと思います。
チュートリアルを進める
私がチュートリアルを始めたときの環境は以下です。
ここからrailsに必要なものを入れ始めました。
- Mac OS Mojave
- fish 2.7.1
- anyenv + ndenv (普段Node.js触ってるから)
- ruby (v2.3のどれか…忘れました。Mac買った最初から入ってたバージョンのまま一切触ってない。)
3. Creating a New Rails Project
チュートリアルに従うと、まずはrubyのバージョンを確認してrailsをインストールする…のですが。
「anyenv入れてるしrbenvとかあるらしいしrubyのバージョン管理はrbenvでしたほうが良いんじゃね?」
という謎の思いつきによりrbenvを導入。fish環境でanyenvを使うという本筋と違うところで時間食ったけどなんとか成功。
この部分は別途記事書いてもいいかも。
(fish anyenv
とかでググるとよく出てくる「手動でスクリプト書き換える」がやりたくなくて頑張った。)
このあとは手順通りやれば特に難しいところもなし。
…のはずだった。
# 3.1 Installing Rails
$ ruby -v # rubyのバージョン確認
$ sqlite3 --version # sqlite3も必要なのでバージョン確認 (このマシンでは最初から入ってた)
$ gem install rails
$ rails --version # railsがインストールされていることを確認
# 3.2 Creating the Blog Application
$ rails new blog # 新しく "blog"という名前のプロジェクトを作成
$ cd blog
4. Hello, Rails!
4.1 Starting up the Web Server
チュートリアルで毎度おなじみのHello Worldですね。
とりあえずサーバを起動します。
$ bin/rails server
Could not find public_suffix-3.0.3 in any of the sources
Run `bundle install` to install missing gems.
はい、コケました。チュートリアル通りやったやん!
エラーメッセージをよく見ると、bundle install
してねって書いてあるのでやってみます。
$ bundle install # 不足しているgemをインストールしてくれるらしい(?)
$ bin/rails server # 今度は起動した!
bundle install
なんてチュートリアルになかった…なんて思って見直してみると、3.2節の説明にちょこっと書いてました。ショック。
たぶんruby触ってる人に取ってはこれくらいは常識なのでしょう。
あと気になったのは、rails
コマンドをgemでインストールしたはずなのに、bin/rails
からサーバ起動させてるところ。
これはきっとnode.jsで言うところのnpm install --global
で入れたコマンドがプロジェクトごとにバージョン違って困っちゃう問題と同じ意味合いなのだろう。
これと関連して、gem install
でインストールするgemはrubyのバイナリと紐付いているようなので、rbenvでrubyのバージョン変えると「そんなgemはこのバージョンにはねぇ!」って怒られた。
gemをプロジェクトごとに管理することってできないのだろうか。
知ってる人教えてください。
4.2 Say "Hello", Rails
ここまでだとデフォルトのページが表示されただけなので、ちゃんと"Hello, Rails!"って出しましょう。
$ bin/rails generate controller Welcome index
これで新しくControllerというものを作った…らしい。
機能単位で分けたページ群というぐらいのくくりだろうか。
Welcomeコントローラのviewを編集するだけで特に難しいところもなし。
4.3 Setting the Application Home Page
サーバーのルートにアクセスしたときにHello, Railsが表示されるようにしてみましょう、ということらしい。
チュートリアルに従ってconfig/routes.rb
を編集してみる。
Rails.application.routes.draw do
get 'welcome/index'
root 'welcome#index'
end
これで以下の2つのルートが設定された。
-
localhost:3000
にアクセスしたらHello,Railsが表示されるようになった。 -
localhost:3000/welcome/index
にアクセスしてもHello,Railsが表示されるようになった。
ここで2つ疑問。
1つ目は、一番最初に表示されていたページはどこにアクセスしても見られなくなった。
初期プロジェクトのどのファイルが初期ページと紐付いていたのでしょう…?
2つ目は、routes.rb
のget
とroot
でパスの表記が違うこと。
生成されたcontrollers/welcome_controller.rb
にdef index
という記述があるので、どちらもこいつの指定だと思うのだけれど…。
とりあえず疑問を残したまま次へ進む。
5. Getting Up and Running
次はリソース(?)を追加する。
Rails.application.routes.draw do
get 'welcome/index'
resources :articles # ここを追加した
root 'welcome#index'
end
なんとこれだけでlocalhost:3000/articles
周りのREST Interfaceが用意されるらしい。(もちろん中身を実装しないとアクセスしてもエラーだけど)
なんて楽な。
さらに、今どんなルートが設定されているかも見れるらしい。
$ bin/rails routes
普段Node.js+expressでサーバ組んでる私にとっては結構衝撃的である。いつもルートが訳わからなくなるんだよねー。こりゃ便利。
5.1 Laying down the groundwork
articlesの中身を実装していくらしい。
$ bin/rails generate controller Articles
そういえばWelcome controllerを作ったときより引数が一つ少ない。
この場合、viewには何も生成されなくて、controllerの中身も空らしい。なるほど。
チュートリアルに従うと、まずはControllerに実装したいパス(今回は/articles/new)を定義して。
class ArticlesController < ApplicationController
def new
end
end
次に、そのパスにアクセスされたときに表示するviewを作る。
<h1>New Article</h1>
すると、エラーなく表示されるようになる。ふむふむ。
5.2 The first form
railsでフォームを扱うときにはform_with
というヘルパーメソッドが使えるらしい。
チュートリアルのものをそのまま使う。
<h1>New Article</h1>
<%= form_with scope: :article, local: true do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
これでタイトルとテキストを入力するフォームと、submitボタンが配置された。
おもむろに適当なテキストを入力してsubmitすると、No route matches [POST] "/articles/new"
だそうだ。
確かに、ブラウザからアクセスした(GETリクエスト)ときに表示させるページは作成したが、POSTしたときの動きは実装していない。
ただ、RESTの考えから行くと、ここでPOSTしてほしいのは/articles/new
ではなく/articles
のはずだ。
なぜならPOSTして作って欲しいオブジェクトはarticle
であってnew
ではない。
というところの解決策が次に書いてあった。
どうやらurl:
というオプションを使うらしい。
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
このarticles_path
というのがどこから来たのか気にはなるが、きっとconfig/routes.rb
に書いたresources
あたりと紐付いているのだろう。
5.3 Creating articles
次にやるのは/articles
にPOSTしたときの動作を実装すること。
まずはControllerにパスを登録する。
class ArticlesController < ApplicationController
def new
end
def create
end
end
パスを登録する、と言ったが、def create
となっているあたりどうも違うらしい。
ここではあくまでこのControllerが扱う動作を定義しているだけで、ここで定義した動作とサーバのパスをマッピングするのはconfig/routes.rb
なのだろう。
次に、create
で行う動作を記述する。
def create
render plain: params[:article].inspect
end
render
メソッドで行えるのは単純に画面にデータを貼り付けることらしい。なるほど。
5.4 Creating the Article model
ここまで散々article
というものが出てきたが、そういえばそのデータモデルは何も作っていない。
ここでやっと作るらしい。
$ bin/rails generate model Article title:string text:text
ここで、実行すると何やらdb
というディレクトリの中にファイルが生まれたことに気づく。
どうやらrailsではアプリの中にDBまで含んであるようだ。ほほう。
5.5 Running a Migration
5.4が終わった段階で/articles/new
にアクセスすると、何やらMigration Error
というものが出てきた。
データモデルを変更したときは、DBのマイグレーションをしなければならないようだ。
$ bin/rails db:migrate
どうやらこのコマンドを実行することで、アプリに組み込んであるDBのテーブル構造を新しいものにマイグレーションするらしい。
自分でSQL書いてゴニョゴニョする必要がないのは確かに楽だと思う。
チュートリアルにも強調してあるが、上のコマンドでマイグレーションが実行されるのはあくまでdevelopment環境だけだそうだ。
production環境もマイグレーションする場合、RAILS_ENV=production
というオプションを付ける必要があるらしい。
5.6 Saving data in the controller
データモデルを作成したので、/articles/new
で表示するフォームから送信したデータを保存するように修正する。
def create
@article = Article.new(params[:article])
@article.save
redirect_to @article
end
修正して実行したら通る…と思いきや。ForbiddenAttributesError
だそうな。
どうやらrailsが持つstrong_parameters
と呼ばれる機構で保護されているらしい。
これの許可を取るために下のようにも書けるそうな。
@article = Article.new(params.require(:article).permit(:title, :text))
ただ、操作ごとに毎回書くのも汚いし良くない、ということで次のようにprivateにしてやる方が良いらしい。
def create
@article = Article.new(article_params)
@article.save
redirect_to @article
end
private
def article_params
params.require(:article).permit(:title, :text)
end
5.7 Showing Articles
前節でcreate
したときの動作を定義したが、よく見ると"記事を保存したあと、その記事自体にリダイレクトする"という動作になっている。
そのため、今度は/articles/:id
へのGETリクエストを処理する部分を実装しなければならない。
def show
@article = Article.find(params[:id])
end
:id
というのは、bin/rails routes
で確認できるパスのうち、/:id
となっている部分と紐づくらしい。
ここではredirect
やrender
をしていないので、viewを用意してやる必要がある。
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
ここまで来ると、記事登録画面→API経由で記事を登録→登録した記事を表示、までできるようになる。
5.8 Listing all articles
続きは時間のあるときにやります…。
まとめ
ちゃんと覚えればWebサービスをサクッと立ち上げたいときにはすごく楽かもしれない。
外部のサービスと連携したいときは?とか、まだ気になるところはたくさんあるけれども。