Ruby on Rails の公式チュートリアルやってみた!
公式サイト「rubyonrails.org」 のチュートリアルを見ながら、作成しました。(全部英文なので、和訳したやつ共有しておきますwありがとう、google!!)
Railsを始めよう
このガイドでは、Ruby on Railsを使用して実行する方法について説明します。
このガイドを読むと、次のことがわかります。
- Railsをインストールし、新しいRailsアプリケーションを作成し、アプリケーションをデータベースに接続することができる。
- Railsアプリケーションの一般的なレイアウトを理解できる。
- MVC(モデル、ビュー、コントローラー)およびRESTful設計の基本原則を触れることができる。
- Railsアプリケーションの開始部分をすばやく生成する方法を理解できる
1. ガイドの前提
このガイドは、Railsアプリケーションをゼロから使い始めたい初心者を対象としています。 Railsの使用経験があるとは限りません。
Railsは、Rubyプログラミング言語で実行されるWebアプリケーションフレームワークです。 Rubyの以前の経験がない場合は、Railsに直接飛び込む非常に急な学習曲線を見つけるでしょう。 Rubyを学習するためのオンラインリソースの厳選されたリストがいくつかあります。
一部のリソースは優れたものですが、Rubyのバージョンは1.6(通常は1.8)であり、Railsでの日々の開発で見られる構文は含まれていません。
2. Railsって何?
Railsは、Rubyプログラミング言語で書かれたWebアプリケーション開発フレームワークです。すべての開発者が何を始める必要があるかを想定することにより、Webアプリケーションのプログラミングを容易にするように設計されています。他の多くの言語やフレームワークよりも多くのことを達成しながら、より少ないコードを書くことができます。 Railsの経験豊富な開発者も、Webアプリケーションの開発がより楽しくなると報告しています。
Railsは独断的なソフトウェアです。それは、物事を行うための「最良の」方法があると仮定し、その方法を奨励するように設計されています-場合によっては代替案を思いとどまらせるように設計されています。 「The Rails Way」を学べば、おそらく生産性が大幅に向上することがわかります。他の言語の古い習慣をRails開発に持ち込み、他の場所で学んだパターンを使用しようとする場合、満足感が少なくなります。
Railsの哲学には、2つの主要な指針が含まれています。
- 自分自身繰り返さない:DRYはソフトウェア開発の原則であり、「すべての知識は、システム内で単一の明確な権威ある表現を持たなければならない」と述べています。同じ情報を何度も書き込まないことで、コードの保守性、拡張性、バグの軽減が向上します。
- 設定より規約:Railsは、Webアプリケーションで多くのことを行う最良の方法について意見を持ち、無限の構成ファイルで詳細を指定することを要求するのではなく、この一連の規則をデフォルトにしています
※にゃるほど・・こんな哲学あったんだっていう感じで見ればいいです^^;
3.新しいRailsプロジェクトの作成
このガイドを読む最良の方法は、手順を追って説明することです。このサンプルアプリケーションを実行するには、すべての手順が不可欠であり、追加のコードや手順は必要ありません。
このガイドに従って、ブログと呼ばれる(非常に)シンプルなウェブログであるRailsプロジェクトを作成します。アプリケーションの構築を開始する前に、Rails自体がインストールされていることを確認する必要があります。
3.1 Railsのインストール
Railsをインストールする前に、システムに適切な前提条件がインストールされていることを確認する必要があります。これらには、RubyおよびSQLite3が含まれます。
コマンドラインプロンプトを開きます。 macOSではTerminal.appを開き、Windowsでは[スタート]メニューから[実行]を選択し、「cmd.exe」と入力します。ドル記号$で始まるコマンドはすべて、コマンドラインで実行する必要があります。 Rubyの現在のバージョンがインストールされていることを確認します。
$ ruby -v
ruby 2.3.7p456
RailsにはRubyバージョン2.5.0以降が必要です。返されるバージョン番号がその番号よりも小さい場合は、Rubyの新しいコピーをインストールする必要があります。
WindowsのシステムにRubyおよびRuby on Railsをすばやくインストールするには、Railsインストーラーを使用できます。ほとんどのオペレーティングシステムのインストール方法については、ruby-lang.orgをご覧ください。
Windowsで作業している場合は、Ruby Installer Development Kitもインストールする必要があります。
SQLite3データベースのインストールも必要になります。多くの一般的なUNIXライクなOSには、SQLite3の許容可能なバージョンが付属しています。 Windowsでは、Railsインストーラーを使用してRailsをインストールした場合、SQLiteが既にインストールされています。他の人は、SQLite3 Webサイトでインストール手順を見つけることができます。正しくインストールされ、PATHにあることを確認します。
$ sqlite3 --version
プログラムはバージョンを報告する必要があります。
Railsをインストールするには、RubyGemsが提供するgem install
コマンドを使用します。
$ gem install rails
すべてが正しくインストールされていることを確認するには、次を実行できる必要があります。
$ rails --version
「Rails 6.0.0」のようなメッセージが表示されたら、続行する準備ができています。
3.2 ブログアプリケーションの作成
Railsにはジェネレーターと呼ばれる多数のスクリプトが付属しています。これらのスクリプトは、特定のタスクで作業を開始するために必要なものをすべて作成することにより、開発作業を容易にします。これらの1つは、新しいアプリケーションジェネレーターです。これは、新しいRailsアプリケーションの基盤を提供するため、自分で作成する必要はありません。
このジェネレーターを使用するには、ターミナルを開き、ファイルを作成する権限があるディレクトリに移動して、次のように入力します。
$ rails new blog
これにより、ブログディレクトリにBlogというRailsアプリケーションが作成され、バンドルインストールを使用してGemfileで既に言及されているgem依存関係がインストールされます。
Linux用のWindowsサブシステムを使用している場合、現在、ファイルシステム通知にはいくつかの制限があります。これは、
Spring
を無効にして、railsの新しいブログ--skip-spring --skip-listen
を実行することで行うことができるgemをリッスンする必要があることを意味します。
rails new -hを実行すると、Railsアプリケーションビルダーが受け入れるコマンドラインオプションをすべて表示できます。
ブログアプリケーションを作成したら、そのフォルダーに切り替えます。
$ cd blog
blogディレクトリ
には、Railsアプリケーションの構造を構成する自動生成されたファイルとフォルダーが多数あります。このチュートリアルのほとんどの作業はapp
フォルダーで行われますが、Railsがデフォルトで作成した各ファイルとフォルダーの機能の基本的な概要は次のとおりです。
File/Folder | 目的 |
---|---|
app/ | アプリケーションのコントローラー、モデル、ビュー、ヘルパー、メーラー、チャネル、ジョブ、およびアセットが含まれています。このガイドの残りの部分では、このフォルダーに焦点を当てます。 |
bin/ | アプリを起動するrailsスクリプトが含まれています。また、アプリケーションのセットアップ、更新、デプロイ、実行に使用する他のスクリプトを含めることができます。 |
config/ | アプリケーションのルート、データベースなどを構成します。これについては、Railsアプリケーションの構成で詳しく説明しています。 |
config.ru | アプリケーションの起動に使用されるラックベースのサーバーのラック構成。ラックの詳細については、ラックのWebサイトを参照してください。 |
db/ | 現在のデータベーススキーマとデータベースの移行が含まれています。 |
Gemfile Gemfile.lock |
これらのファイルにより、Railsアプリケーションに必要なgem依存関係を指定できます。これらのファイルは、Bundler gemによって使用されます。 Bundlerの詳細については、Bundler Webサイトを参照してください。 |
lib/ | アプリケーションの拡張モジュール。 |
log/ | アプリケーションログファイル。 |
package.json | このファイルにより、Railsアプリケーションに必要なnpm依存関係を指定できます。このファイルはYarnによって使用されます。Yarnの詳細については、YarnのWebサイトを参照してください。 |
public/ | 公開フォルダ。静的ファイルとコンパイル済みアセットが含まれます。 |
Rakefile | このファイルは、コマンドラインから実行できるタスクを見つけてロードします。タスク定義は、Railsのコンポーネント全体で定義されます。 Rakefileを変更するのではなく、アプリケーションのlib / tasksディレクトリにファイルを追加して、独自のタスクを追加する必要があります。 |
README.md | アプリケーションの簡単な取扱説明書です。このファイルを編集して、アプリケーションの動作、設定方法などを他の人に伝えます。 |
storage/ | ディスクサービスのアクティブストレージファイル。これについては、アクティブストレージの概要で説明しています。 |
test/ | 単体テスト、フィクスチャ、およびその他のテスト装置。これらはRailsアプリケーションのテストで説明されています。 |
tmp/ | 一時ファイル(キャッシュファイルやpidファイルなど)。 |
vendor/ | すべてのサードパーティコードの場所。典型的なRailsアプリケーションでは、これにはベンダーが提供するgemが含まれます。 |
.gitignore | このファイルは、gitに無視するファイル(またはパターン)を指示します。ファイルの無視の詳細については、GitHub-ignoreを参照してください。 |
.ruby-version | このファイルには、デフォルトのRubyバージョンが含まれています。 |
4. Hello, Rails!
まず、画面にテキストをすばやく表示してみましょう。これを行うには、Railsアプリケーションサーバーを実行する必要があります。
4.1 Webサーバーの起動
Railsアプリケーションが既にあると思います(例:blogっていうプロジェクトを作ってるはず!)。表示するには、開発マシンでWebサーバーを起動する必要があります。これを行うには、ブログディレクトリで次のコマンドを実行します。
$ rails server
補足: 実行する前にbrew install yarn
とrails webpacker:install
を行ってから、rails server
をやるとうまく行きます! (Mac環境確認済み!)
Windowsを使用している場合は、binフォルダーの下のスクリプトをRubyインタープリターに直接渡す必要があります。 ruby bin \ railsサーバー。
JavaScriptアセットの圧縮では、システムでJavaScriptランタイムを使用できる必要があります。ランタイムがない場合、アセットのコンパイル中にexecjsエラーが表示されます。通常、macOSおよびWindowsにはJavaScriptランタイムがインストールされています。 therubyrhinoはJRubyユーザーに推奨されるランタイムであり、デフォルトでJRubyで生成されたアプリのGemfileに追加されます。 ExecJSでサポートされているすべてのランタイムを調査できます。
これにより、デフォルトでRailsとともに配布されるWebサーバーであるPumaが起動します。アプリケーションの動作を確認するには、ブラウザーウィンドウを開いてhttp://localhost:3000に移動します。 Railsのデフォルト情報ページが表示されます。
Webサーバーを停止するには、実行中のターミナルウィンドウでCtrl + Cを押します。サーバーが停止したことを確認するには、コマンドプロンプトカーソルが再び表示されるはずです。 macOSを含むほとんどのUNIXライクシステムでは、これはドル記号$になります。開発モードでは、通常、Railsはサーバーの再起動を要求しません。ファイルに加えた変更は、サーバーによって自動的に取得されます。
「Yay! You're on Rails!」ページは、新しいRailsアプリケーションの煙テストです。ページを提供するのに十分なソフトウェアが正しく構成されていることを確認します。」 pageは、新しいRailsアプリケーションのスモークテストです。ページを提供するのに十分なソフトウェアが正しく構成されていることを確認します。
4.2 Railsで「Hello」と言う
Railsに「Hello」と言わせるには、少なくともコントローラーとビューを作成する必要があります。
コントローラーの目的は、アプリケーションに対する特定の要求を受信することです。ルーティングは、どのコントローラーがどの要求を受信するかを決定します。多くの場合、各コントローラーへのルートは複数あり、異なるアクションによって異なるルートに対応できます。各アクションの目的は、情報を収集してビューに提供することです。
ビューの目的は、この情報を人間が読める形式で表示することです。重要な違いは、情報が収集されるのはビューではなくコントローラーであることです。ビューはその情報を表示するだけです。デフォルトでは、ビューテンプレートはeRuby(Embedded Ruby)と呼ばれる言語で記述され、ユーザーに送信される前にRailsのリクエストサイクルによって処理されます。
新しいコントローラーを作成するには、「コントローラー」ジェネレーターを実行し、「welcome」というコントローラーに「index」というアクションが必要であることを伝える必要があります。
$ rails generate controller Welcome index
Railsはいくつかのファイルとルートを作成します。
create app/controllers/welcome_controller.rb
route get 'welcome/index'
invoke erb
create app/views/welcome
create app/views/welcome/index.html.erb
invoke test_unit
create test/controllers/welcome_controller_test.rb
invoke helper
create app/helpers/welcome_helper.rb
invoke test_unit
invoke assets
invoke scss
create app/assets/stylesheets/welcome.scss
これらの中で最も重要なのは、もちろんapp/controllers/welcome_controller.rb
にあるコントローラーとapp/views/welcome/index.html.erb
にあるビューです。
テキストエディターでapp/views/welcome/index.html.erb
ファイルを開きます。ファイル内の既存のコードをすべて削除し、次の1行のコードに置き換えます。
<h1>Hello, Rails!</h1>
4.3 アプリケーションのホームページの設定
コントローラーとビューを作成したので、「Hello、Rails!」が欲しいときにRailsに伝える必要があります。表示されます。この例では、サイトのルートURL http://localhost:3000に移動したときに表示されるようにします。現時点では、「Yay! You're on Rails!」その場所を占有しています。
実際のホームページの場所をRailsに伝える必要があります。
エディターでconfig/routes.rb
ファイルを開きます。
Rails.application.routes.draw do
get 'welcome/index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
これはアプリケーションのルーティングファイルであり、特殊なDSL(ドメイン固有の言語)のエントリを保持します。このファイルは、受信リクエストをコントローラーおよびアクションに接続する方法をRailsに指示します。コードroot 'welcome#index'
の行を追加して、このファイルを編集します。次のようになります。
Rails.application.routes.draw do
get 'welcome/index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
root 'welcome#index'
end
root 'welcome#index'
は、アプリケーションのルートへのリクエストをウェルカムコントローラーのインデックスアクションにマッピングするようにRailsに指示し、get 'welcome/index'
は、リクエストをhttp:// localhost:3000/welcome/indexにウェルカムにマッピングするように指示しますコントローラーのインデックスアクション。これは、以前にコントローラージェネレーターを実行したときに作成されました(railsはコントローラーのWelcomeインデックスを生成します
)。
コントローラー(レールを生成するために停止した場合は、Webサーバーを再度起動します
サーバー)、ブラウザでhttp://localhost:3000に移動します。 「Hello、Rails!」と表示されます。 app/views/welcome/index.html.erb
に入れたメッセージは、この新しいルートが実際にWelcomeControllerのインデックスアクションに進み、ビューを正しくレンダリングしていることを示しています。
ルーティングの詳細については、外部からのRailsルーティングを参照してください。
5. 起動と実行
コントローラー、アクション、ビューを作成する方法を見てきたので、もう少し実体のあるものを作成しましょう。
ブログアプリケーションで、新しいリソースを作成します。リソースとは、記事、人、動物などの類似オブジェクトのコレクションに使用される用語です。リソースのアイテムを作成、読み取り、更新、および破棄できます。これらの操作はCRUD操作と呼ばれます。
Railsは、標準のRESTリソースを宣言するために使用できるリソース
メソッドを提供します。ファイルが次のようになるように、記事リソースをconfig/routes.rb
に追加する必要があります。
Rails.application.routes.draw do
get 'welcome/index'
resources :articles
root 'welcome#index'
end
Railsルートを実行すると、すべての標準RESTfulアクションのルートが定義されていることがわかります。プレフィックス列(および他の列)の意味は後で説明しますが、Railsが単数形の記事を推測し、その区別を有意義に使用していることに注意してください。
$ rails routes
Prefix Verb URI Pattern Controller#Action
welcome_index GET /welcome/index(.:format) welcome#index
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format) articles#edit
article GET /articles/:id(.:format) articles#show
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
root GET / welcome#index
次のセクションでは、アプリケーションに新しい記事を作成し、それらを表示できる機能を追加します。これは、CRUDの「C」と「R」です。作成して読み取ります。これを行うためのフォームは次のようになります。(手順5.1以降までやると、下記のフォームが見れます!今は見れません!)
今のところ少し基本的に見えますが、それでも大丈夫です。後でスタイルの改善を検討します。
5.1 下地を整える
まず、アプリケーション内に新しい記事を作成する場所が必要です。最適な場所は/articles/new
です。ルートがすでに定義されているので、アプリケーションの/articles/new
にリクエストを送信できるようになりました。 http://localhost:3000/articles/newに移動すると、ルーティングエラーが表示されます。
このエラーは、リクエストを処理するためにルートにコントローラーを定義する必要があるために発生します。この特定の問題の解決策は簡単です。ArticlesController
というコントローラーを作成します。これを行うには、次のコマンドを実行します。
$ rails generate controller Articles
新しく生成されたapp/controllers/articles_controller.rb
を開くと、かなり空のコントローラーが表示されます。
class ArticlesController < ApplicationController
end
コントローラーは、ApplicationController
を継承するように定義された単なるクラスです。このコントローラーのアクションとなるメソッドを定義するのは、このクラス内です。これらのアクションは、システム内の記事に対してCRUD操作を実行します。
Rubyには
public
、private
、およびprotected
されたメソッドがありますが、コントローラーのアクションにできるのはpublic
メソッドのみです。詳細については、プログラミングRubyをご覧ください。
http://localhost:3000/articles/newを今すぐ更新すると、新しいエラーが表示されます。
このエラーは、生成したArticlesController
内でRailsがnew
actionを見つけられないことを示しています。これは、コントローラーがRailsで生成されると、生成プロセス中に目的のアクションを指定しない限り、デフォルトで空になるためです。
コントローラー内でアクションを手動で定義するには、コントローラー内で新しいメソッドを定義するだけです。 app/controllers/articles_controller.rb
を開き、ArticlesController
クラス内で、コントローラーが次のようになるようにメソッドnew
を定義します。
class ArticlesController < ApplicationController
def new
end
end
ArticlesController
で定義された新しいメソッドで、http://localhost:3000/articles/newを更新すると、別のエラーが表示されます。
Railsでは、このような単純なアクションが情報を表示するためにビューに関連付けられていると想定しているため、このエラーが発生しています。使用可能なビューがない場合、Railsは例外を発生させます。
エラーメッセージ全部をもう一度見てみましょう。
ArticlesController#new is missing a template for request formats: text/html
NOTE!
Unless told otherwise, Rails expects an action to render a template with the same name,
contained in a folder named after its controller. If this controller is an API responding with 204 (No Content),
which does not require a template, then this error will occur when trying to access it via browser,
since we expect an HTML template to be rendered for such requests. If that's the case, carry on.
このメッセージは、欠落しているテンプレートを識別します。この場合、それはarticles/new
テンプレートです。 Railsは最初にこのテンプレートを探します。 ArticlesController
はApplicationController
を継承するため、見つからない場合は、application/new
というテンプレートをロードしようとします。
次に、メッセージにはrequest.formats
が含まれ、応答で提供されるテンプレートの形式を指定します。ブラウザ経由でこのページをリクエストしたときにtext/html
に設定されているため、RailsはHTMLテンプレートを探します。
この場合に機能する最も単純なテンプレートは、app/views/articles/new.html.erb
にあるテンプレートです。このファイル名の拡張子は重要です。最初の拡張子はテンプレートの形式であり、2番目の拡張子はテンプレートのレンダリングに使用されるハンドラーです。 Railsは、アプリケーションのapp/views
内でarticles/new
というテンプレートを見つけようとしています。このテンプレートの形式はhtml
のみで、HTML
のデフォルトハンドラーはerb
です。 Railsは、他の形式に対して他のハンドラを使用します。ビルダーハンドラーはXMLテンプレートを構築するために使用され、コーヒー
ハンドラーはCoffeeScriptを使用してJavaScriptテンプレートを構築します。新しいHTMLフォームを作成するため、RubyをHTMLに埋め込むように設計されたERB言語を使用します。
したがって、このファイルはarticles/new.html.erb
と呼ばれ、アプリケーションのapp/views
ディレクトリ内に配置する必要があります。
さあ、app/views/articles/new.html.erb
で新しいファイルを作成し、このコンテンツを書き込みます。
<h1>New Article</h1>
http://localhost:3000/articles/newを更新すると、ページにタイトルがあることがわかります。ルート、コントローラー、アクション、およびビューが調和して機能するようになりました!新しい記事のフォームを作成します。
5.2 最初のフォーム
このテンプレート内にフォームを作成するには、フォームビルダーを使用します。 Railsの主要なフォームビルダーは、form_with
というヘルパーメソッドによって提供されます。このメソッドを使用するには、このコードをapp/views/articles/new.html.erb
に追加します
<%= 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 %>
ここでページを更新すると、上記の例とまったく同じフォームが表示されます。 Railsでフォームを作成するのは本当に簡単です!
form_with
を呼び出すとき、このフォームの識別スコープを渡します。この場合、それはシンボル:article
です。これは、form_with
ヘルパーにこのフォームの目的を伝えます。このメソッドのブロック内で、Form
で表されるFormBuilder
オブジェクトを使用して、記事のタイトルとテキストにそれぞれ対応する2つのラベルと2つのテキストフィールドを作成します。最後に、フォームオブジェクトでsubmit
呼び出しにより、フォームの送信ボタンが作成されます。
ただし、このフォームには1つの問題があります。生成されたHTMLを調べて、ページのソースを表示すると、フォームのアクション
属性が/articles/new
を指していることがわかります。これは問題です。なぜなら、このルートは、あなたが今いるページそのものに行き、そのルートは新しい記事のフォームを表示するためだけに使用されるべきだからです。
別の場所に移動するには、フォームで別のURLを使用する必要があります。これは、form_with
の:url
オプションで非常に簡単に実行できます。通常、Railsでは、このような新しいフォームの送信に使用されるアクションは「作成」と呼ばれるため、フォームはそのアクションを指す必要があります。
app/views/articles/new.html.erb
内のform_with
行を次のように編集します。
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
この例では、articles_path
ヘルパーが:url
オプションに渡されます。 Railsがこれで何をするかを見るために、railsルート
の出力を振り返ります。
$ rails routes
Prefix Verb URI Pattern Controller#Action
welcome_index GET /welcome/index(.:format) welcome#index
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format) articles#edit
article GET /articles/:id(.:format) articles#show
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
root GET / welcome#index
articles_path
ヘルパーは、記事がプレフィックスに関連付けられたURIパターンを指すようにRailsに指示します。フォームは(デフォルトで)POST
リクエストをそのルートに送信します。これは、現在のコントローラーであるArticlesController
の作成アクションに関連付けられています。
フォームとそれに関連付けられたルートを定義したら、フォームに入力し、[送信]ボタンをクリックして新しい記事の作成プロセスを開始できるので、先に進んでください。フォームを送信すると、見慣れたエラーが表示されるはずです。
これを機能させるには、ArticlesController
内にcreate
アクションを作成する必要があります。
デフォルトでは、
form_with
はAjaxを使用してフォームを送信するため、ページ全体のリダイレクトはスキップされます。このガイドを読みやすくするために、local:true
を使用して無効にしました。
5.3 articles作成
「Unknown action」をなくすには、次に示すように、app/controllers/ articles_controller.rb
のArticlesController
クラス内で、新しいアクションの下にcreate
アクションを定義できます。
class ArticlesController < ApplicationController
def new
end
def create
end
end
今すぐフォームを再送信すると、ページに変更が表示されない場合があります。心配しないでください!これは、応答がどうあるべきかを指定しない場合、デフォルトでRailsはアクションに対して204 No Content
応答を返すためです。 create
アクションを追加しただけですが、応答の方法については何も指定しませんでした。この場合、create
アクションは新しい記事をデータベースに保存する必要があります。
フォームが送信されると、フォームのフィールドがパラメーターとしてRailsに送信されます。これらのパラメーターは、通常、特定のタスクを実行するために、コントローラーアクション内で参照できます。これらのパラメーターの外観を確認するには、create
アクションを次のように変更します。
class ArticlesController < ApplicationController
def new
end
def create
render plain: params[:article].inspect
end
end
ここでのrender
メソッドは、:plain
のキーとparams[:article].inspect
の値を持つ非常に単純なハッシュを取得しています。 params
メソッドは、フォームから受信するパラメーター(またはフィールド)を表すオブジェクトです。 paramsメソッドはActionController::Parameters
オブジェクトを返します。これにより、文字列またはシンボルを使用してハッシュのキーにアクセスできます。この状況では、重要なパラメーターはフォームのパラメーターのみです。
params
メソッドをかなり定期的に使用するため、しっかりと把握してください。 URLの例を考えてみましょう:http://www.example.com/?username=dhh&email=dhh@email.com。このURLでは、params [:username]
は「dhh」に等しく、params [:email]
は「dhh@email.com」に等しくなります。
このアクションは、フォームから入ってくるarticleのパラメーターを表示しています。ただし、これは実際にはそれほど役に立ちません。はい、パラメータを見ることができますが、特に何も行われていません。
5.4 Article model作成
Railsのモデルは単数形の名前を使用し、対応するデータベーステーブルは複数形の名前を使用します。 Railsは、モデルを作成するためのジェネレーターを提供します。これは、ほとんどのRails開発者が新しいモデルを作成するときに使用する傾向があります。新しいモデルを作成するには、ターミナルで次のコマンドを実行します。
$ rails generate model Article title:string text:text
このコマンドを使用して、文字列タイプのタイトル属性とテキストタイプのテキスト属性とともに、Article
モデルが必要であることをRailsに伝えました。これらの属性は、データベース内のarticle
テーブルに自動的に追加され、article
モデルにマップされます。
Railsは、多数のファイルを作成して応答しました。今のところ、app/models/article.rb
とdb/migrate/20140120191729_create_articles.rb
にのみ興味があります(名前は少し異なる場合があります)。後者はデータベース構造の作成を担当します。これについては次に説明します。
5.5 Migration実行
これまで見てきたように、rails generate model
はdb/migrate
ディレクトリ内にデータベース移行ファイルを作成しました。移行は、データベーステーブルの作成と変更を簡単にするために設計されたRubyクラスです。 Railsはrakeコマンドを使用して移行を実行します。データベースに適用した後、移行を取り消すことができます。移行ファイル名には、作成された順序で処理されるようにタイムスタンプが含まれています。
db/migrate/YYYYMMDDHHMMSS_create_articles.rb
ファイルを見ると(名前が少し異なることを思い出してください)、ここにあります:
class CreateArticles < ActiveRecord::Migration[6.0]
def change
create_table :articles do |t|
t.string :title
t.text :text
t.timestamps
end
end
end
上記の移行では、この移行の実行時に呼び出されるchange
という名前のメソッドが作成されます。このメソッドで定義されたアクションも可逆的です。つまり、後で移行したい場合に備えて、Railsはこの移行によって行われた変更を元に戻す方法を知っています。この移行を実行すると、1つの文字列列と1つのテキスト列を持つ記事テーブルが作成されます。また、2つのタイムスタンプフィールドを作成して、Railsがarticle
の作成時間と更新時間を追跡できるようにします。
移行の詳細については、Active Record Migrationsを参照してください。
この時点で、railsコマンドを使用して移行を実行できます。
$ rails db:migrate
※Ruby 2.7.0 とRails 6.0.2.1 でマイグレーションするとたくさん警告が出てしまう。。解決方法は、「~/.bash_profile」に「export RUBYOPT='-W:no-deprecated -W:no-experimental'」を追記。その後「source ~/.bash_profile」を実行して、上記のコマンドを叩くとうまく行くと思います!
$ rails db:migrate
== 20200309232712 CreateArticles: migrating ===================================
-- create_table(:articles)
-> 0.0030s
== 20200309232712 CreateArticles: migrated (0.0033s) ==========================
デフォルトでは開発環境で作業しているため、このコマンドは
config/database.yml
ファイルのdevelopment
セクションで定義されたデータベースに適用されます。本番環境など、別の環境で移行を実行する場合は、コマンドrails db:migrate RAILS_ENV= production
を呼び出すときに、移行を明示的に渡す必要があります。
5.6 コントローラーにデータを保存する
ArticlesController
に戻り、create
アクションを変更して、新しいArticleモデルを使用してデータベースにデータを保存する必要があります。 app/controllers/articles_controller.rb
を開き、作成アクションを次のように変更します。
def create
@article = Article.new(params[:article])
@article.save
redirect_to @article
end
進行状況は次のとおりです。すべてのRailsモデルは、それぞれのデータベース列に自動的にマップされるそれぞれの属性で初期化できます。最初の行では、まさにそれを行います(params [:article]
には関心のある属性が含まれていることに注意してください)。次に、@article.save
がモデルをデータベースに保存します。最後に、ユーザーをshowアクションにリダイレクトします。これは後で定義します。
なぜ
Article.new
のA
が大文字であるのか疑問に思うかもしれませんが、このガイドの他のほとんどの記事では小文字を使用しています。このコンテキストでは、app/models/article.rb
で定義されているArticleという名前のクラスを参照しています。 Rubyのクラス名は大文字で始める必要があります。
後で見るように、
@article.save
は記事が保存されたかどうかを示すブール値を返します。
ここでhttp://localhost:3000/articles/newにアクセスすると、記事をほぼ作成できます。それを試してみてください!次のようなエラーが表示されます。
Railsには、安全なアプリケーションを作成するのに役立ついくつかのセキュリティ機能があり、現在それらの1つにアクセスしています。これは強力なパラメーターと呼ばれ、コントローラーアクションに許可されるパラメーターをRailsに正確に伝える必要があります。
なぜあなたは気にする必要がありますか?一度にすべてのコントローラーパラメーターを取得してモデルに自動的に割り当てることができるため、プログラマーの仕事は簡単になりますが、この便利さにより悪意のある使用も可能になります。サーバーへのリクエストが新しい記事フォーム送信のように作成されているが、アプリケーションの整合性に違反する値を持つ追加フィールドも含まれている場合はどうなりますか?それらはモデルに「大量に割り当て」られ、次に良いものと一緒にデータベースに入れられます-アプリケーションを破壊するか、さらに悪いことになります。
許可されたコントローラーパラメーターを定義して、不正な大量割り当てを防止する必要があります。この場合、createを有効に使用するには、title
パラメーターとtext
パラメーターの両方を許可および要求します。この構文は、require
およびpermit
を導入します。変更には、作成アクションの1行が含まれます。
@article = Article.new(params.require(:article).permit(:title, :text))
これは多くの場合、独自のメソッドに組み込まれるため、同じコントローラー内の複数のアクション(作成や更新など)で再利用できます。一括割り当ての問題を超えて、メソッドは、意図されたコンテキストの外で呼び出されないようにするためにプライベートにされることがよくあります。結果は次のとおりです。
def create
@article = Article.new(article_params)
@article.save
redirect_to @article
end
private
def article_params
params.require(:article).permit(:title, :text)
end
詳細については、上記のリファレンスと、Strong Parametersに関するこのブログ記事を参照してください。
5.7 Articles参照
ここでフォームを再度送信すると、Railsはshowアクションが見つからないことについて文句を言います。それはあまり有用ではありませんので、先に進む前にshowアクションを追加しましょう。
railsルートの出力で見たように、show actionのルートは次のとおりです。
article GET /articles/:id(.:format) articles#show
特別な構文:id
は、このルートが:id
パラメーターを期待していることをレールに伝えます。このパラメーターは、この場合、articleのidになります。
前にやったように、app/controllers/articles_controller.rb
とそのそれぞれのビューにshow
アクションを追加する必要があります。
頻繁に実行されるのは、
index
,show
,new
,edit
,create
,update
、destroy
の順序で各コントローラーに標準のCRUDアクションを配置することです。任意の順序を使用できますが、これらはパブリックメソッドであることに注意してください。このガイドで前述したように、コントローラーでprivate
可視性を宣言する前に配置する必要があります。
次のように、show
アクションを追加しましょう。
class ArticlesController < ApplicationController
def show
@article = Article.find(params[:id])
end
def new
end
注意すべき点がいくつかあります。 Article.find
を使用して関心のあるarticleを見つけ、params [:id]
を渡してリクエストから:id
パラメーターを取得します。また、インスタンス変数(接頭辞@
)を使用して、記事オブジェクトへの参照を保持します。これは、Railsがすべてのインスタンス変数をビューに渡すためです。
次に、次のコンテンツを含む新しいファイルapp/views/articles/show.html.erb
を作成します。
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
この変更により、最終的に新しい記事を作成できるようになります。 http://localhost:3000/articles/newにアクセスして、試してみてください!
5.8 Articleリスト表示
まだすべてのArticleをリストする方法が必要なので、それをやってみましょう。 rails routes
の出力によるこのためのルートは次のとおりです。
articles GET /articles(.:format) articles#index
app/controllers/articles_controller.rb
ファイルのArticlesController内に、そのルートに対応するイindex
アクションを追加します。index
アクションを作成する場合、通常は、それをコントローラーの最初のメソッドとして配置します。やってみましょう:
class ArticlesController < ApplicationController
def index
@articles = Article.all
end
def show
@article = Article.find(params[:id])
end
def new
end
そして最後に、app/views/articles/index.html.erb
にあるこのアクションのビューを追加します。
<h1>Listing Articles</h1>
<table>
<tr>
<th>Title</th>
<th>Text</th>
<th></th>
</tr>
<% @articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td><%= link_to 'Show', article_path(article) %></td>
</tr>
<% end %>
</table>
これで、http://localhost:3000/articlesにアクセスすると、作成したすべての記事のリストが表示されます。
5.9 リンクを追加する
Articleの作成、表示、および一覧表示できるようになりました。次に、ページ間を移動するためのリンクを追加しましょう。
app/views/welcome/index.html.erb
を開き、次のように変更します。
<h1>Hello, Rails!</h1>
<%= link_to 'My Blog', controller: 'articles' %>
link_to
メソッドは、Railsの組み込みビューヘルパーの1つです。表示するテキストに基づいてハイパーリンクを作成します。この場合、記事のパスに移動します。
他のビューへのリンクも追加しましょう。まず、この「New Article」リンクをapp/views/articles/index.html.erb
に追加し、<table>
タグの上に配置します。
<%= link_to 'New article', new_article_path %>
このリンクを使用すると、新しい記事を作成できるフォームを表示できます。
次に、フォームの下にあるapp/views/articles/new.html.erb
に別のリンクを追加して、インデックスアクションに戻ります。
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
・・・
<% end %>
<%= link_to 'Back', articles_path %>
最後に、app/views/articles/show.html.erb
テンプレートへのリンクを追加して、同様にindex
アクションに戻ります。これにより、1つの記事を表示している人が戻ってリスト全体を表示できるようになります。
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
<%= link_to 'Back', articles_path %>
同じコントローラ内のアクションにリンクする場合、Railsはデフォルトで現在のコントローラを使用するため、
:controller
オプションを指定する必要はありません。
開発モード(デフォルトで作業しているモード)では、Railsはブラウザーの要求ごとにアプリケーションをリロードするため、変更が行われたときにWebサーバーを停止して再起動する必要はありません。
5.10 バリデーション追加
モデルファイルapp/models/article.rb
は、取得できるほど簡単です。
class Article < ApplicationRecord
end
このファイルにはそれほど多くはありませんが、ArticleクラスはApplicationRecordを継承することに注意してください。 ApplicationRecordはActiveRecord :: Baseを継承し、基本的なデータベースCRUD(作成、読み取り、更新、破棄)操作、データ検証、洗練された検索サポート、関連する機能など、Railsモデルに多くの機能を無料で提供します。
Railsには、モデルに送信するデータの検証に役立つメソッドが含まれています。 app/models/article.rb
ファイルを開いて編集します。
class Article < ApplicationRecord
validates :title, presence: true,
length: { minimum: 5 }
end
これらの変更により、すべてのAriticleのタイトルが少なくとも5文字以上になることが保証されます。 Railsは、列の有無や一意性、形式、関連オブジェクトの存在など、モデル内のさまざまな条件を検証できます。検証については、アクティブレコード検証で詳しく説明しています。
検証が行われたので、無効な記事で@article.save
を呼び出すと、falseが返されます。 app/controllers/articles_controller.rb
を再度開くと、create
アクション内で@article.save
を呼び出した結果を確認しないことに気付くでしょう。この状況で@article.save
が失敗した場合、フォームをユーザーに表示する必要があります。これを行うには、新規を変更し、app/controllers/articles_controller.rb
内で次のアクションを作成します。
def new
@article = Article.new
end
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
new
アクションにより、@article
という新しいインスタンス変数が作成されるようになりました。その理由はすぐにわかります。
create
アクション内で、saveがfalse
を返す場合、redirect_to
ではなくrender
を使用することに注意してください。 render
メソッドは、@article
オブジェクトがレンダリングされるときに新しいテンプレートに渡されるように使用されます。このレンダリングはフォーム送信と同じリクエスト内で行われますが、redirect_to
はブラウザに別のリクエストを発行するように指示します。
http://localhost:3000/articles/newをリロードし、タイトルなしで記事を保存しようとすると、Railsはフォームに戻りますが、それはあまり役に立ちません。ユーザーに何か問題があったことを伝える必要があります。そのためには、app/views/articles/new.html.erb
を変更してエラーメッセージを確認します。
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
<% if @article.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(@article.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% @article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<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 %>
<%= link_to 'Back', articles_path %>
いくつかのことが進行中です。 @article.errors.any?
でエラーがあるかどうかを確認し、その場合は@article.errors.full_messages
ですべてのエラーのリストを表示します。
pluralize
は引数として数値と文字列を受け取るrailsヘルパーです。数が1より大きい場合、文字列は自動的に複数形になります。
ArticlesController
に@article = Article.new
を追加した理由は、そうしないと@article
がビューでnil
になり、@article.errors.any
が呼び出されるためです。エラーがスローされます。
Railsは、クラス
field_with_errors
のdivでエラーを含むフィールドを自動的にラップします。 CSSルールを定義して、それらを目立たせることができます。
これで、新しい記事フォームhttp://localhost:3000/articles/newでタイトルを付けずに記事を保存しようとすると、素敵なエラーメッセージが表示されます。
5.11 Article編集
CRUDの「CR」部分について説明しました。では、記事を更新する「U」の部分に注目しましょう。
最初に行うステップは、次に示すように、通常はnew
アクションとcreate
アクションの間に、ArticlesController
にedit
アクションを追加することです。
def new
@article = Article.new
end
def edit
@article = Article.find(params[:id])
end
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
ビューには、新しい記事を作成するときに使用したものと同様のフォームが含まれます。 app/views/articles/edit.html.erb
というファイルを作成し、次のようにします。
<h1>Edit Article</h1>
<%= form_with(model: @article, local: true) do |form| %>
<% if @article.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(@article.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% @article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<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 %>
<%= link_to 'Back', articles_path %>
今回は、フォームにupdate
アクションを指定します。このアクションはまだ定義されていませんが、すぐに定義されます。
記事オブジェクトをform_with
メソッドに渡すと、編集された記事フォームを送信するためのURLが自動的に設定されます。このオプションは、RESTプロトコルに従ってリソースを更新するために使用することが予想されるHTTPメソッドであるPATCH
HTTPメソッドを介してこのフォームを送信することをRailsに伝えます。
また、上記の編集ビューのmodel:@article
のように、モデルオブジェクトをform_with
に渡すと、フォームヘルパーはオブジェクトの対応する値をフォームフィールドに入力します。新しいビューで行われたように、scope::article
などのシンボルスコープを渡すと、空のフォームフィールドのみが作成されます。詳細については、form_withのドキュメントをご覧ください。
次に、app/controllers/articles_controller.rb
にupdate
アクションを作成する必要があります。 create
アクションとprivate
メソッドの間に追加します。
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
新しいメソッドupdate
は、既に存在するレコードを更新するときに使用され、更新する属性を含むハッシュを受け入れます。前と同様に、記事の更新中にエラーが発生した場合は、ユーザーにフォームを表示します。
create
アクションに対して以前に定義したarticle_params
メソッドを再利用します。
更新する
ためにすべての属性を渡す必要はありません。たとえば、@article.update(title: 'A new title')
が呼び出された場合、Railsはtitle
属性のみを更新し、他のすべての属性は変更されません。
最後に、すべての記事のリストにedit
アクションへのリンクを表示したいので、それをapp/views/articles/index.html.erb
に追加して、「Show」リンクの横に表示させます。
<table>
<tr>
<th>Title</th>
<th>Text</th>
<th colspan="2"></th>
</tr>
<% @articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td><%= link_to 'Show', article_path(article) %></td>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
</tr>
<% end %>
</table>
また、app/views/articles/show.html.erb
テンプレートにも1つ追加するので、記事のページに「Edit」リンクもあります。これをテンプレートの下部に追加します。
...
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
これまでのアプリの外観は次のとおりです。
5.12 ビューの重複をクリーンアップするためにパーシャルを使用する
編集ページ
は新しいページ
と非常によく似ています。実際、両者はフォームを表示するために同じコードを共有しています。ビューのパーシャルを使用して、この重複を削除しましょう。慣例により、部分ファイルにはアンダースコアが前に付けられます。
Railsガイドのレイアウトとレンダリングでパーシャルの詳細を確認できます。
次のコンテンツを含む新しいファイルapp/views/articles/_form.html.erb
を作成します。
<%= form_with model: @article, local: true do |form| %>
<% if @article.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(@article.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% @article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<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 %>
form_with
宣言以外はすべて同じままでした。この短くてシンプルなform_with
宣言を使用して他のフォームのいずれかに代わることができる理由は、@article
がRESTfulルートの完全なセットに対応するリソースであり、RailsがどのURIとメソッドを使用するかを推測できるためです。 form_withのこの使用の詳細については、リソース指向スタイルを参照してください。
ここで、この新しいパーシャルを使用するようにapp/views/articles/new.html.erb
ビューを更新し、完全に書き換えましょう。
<h1>New Article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
次に、app/views/articles/edit.html.erb
ビューに対して同じことを行います。
<h1>Edit Article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
5.13 Article削除
これで、CRUDの「D」部分をカバーし、データベースから記事を削除する準備が整いました。 REST規則に従って、rails routes
の出力ごとに記事を削除するルートは次のとおりです。
DELETE /articles/:id(.:format) articles#destroy
リソースを削除するルートには、ルーティングの削除方法を使用する必要があります。これが典型的な取得ルートとして残されている場合、次のような悪意のあるURLを作成できる可能性があります。
<a href='http://example.com/articles/1/destroy'>look at this cat!</a>
リソースを破棄するためにdelete
メソッドを使用します。このルートはapp/controllers/articles_controller.rb
内のdestroy
アクションにマップされますが、このアクションはまだ存在しません。 destroy
メソッドは通常、コントローラー内の最後のCRUDアクションであり、他のパブリックCRUDアクションと同様に、プライベートメソッドまたは保護メソッドの前に配置する必要があります。追加しましょう:
def destroy
@article = Article.find(params[:id])
@article.destroy
redirect_to articles_path
end
app/controllers/articles_controller.rb
ファイル内のArticlesController
全体は、次のようになります。
class ArticlesController < ApplicationController
def index
@articles = Article.all
end
def show
@article = Article.find(params[:id])
end
def new
@article = Article.new
end
def edit
@article = Article.find(params[:id])
end
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
def destroy
@article = Article.find(params[:id])
@article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
データベースから削除する場合、Active Record
オブジェクトでdestroy
を呼び出すことができます。インデックスアクションにリダイレクトするため、このアクションのビューを追加する必要がないことに注意してください。
最後に、index
アクションテンプレート(app/views/articles/index.html.erb
)に「Destroy」リンクを追加して、すべてをまとめます。
<h1>Listing Articles</h1>
<%= link_to 'New article', new_article_path %>
<table>
<tr>
<th>Title</th>
<th>Text</th>
<th colspan="3"></th>
</tr>
<% @articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.text %></td>
<td><%= link_to 'Show', article_path(article) %></td>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<td><%= link_to 'Destroy', article_path(article),
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
ここでは、別の方法でlink_to
を使用しています。名前付きルートを2番目の引数として渡し、次にオプションを別の引数として渡します。method::delete
およびdata:{confirm:'Are you sure?' }
オプションはHTML5属性として使用されるため、リンクをクリックすると、Railsは最初にユーザーに確認ダイアログを表示し、次にメソッドdeleteでリンクを送信します。これは、アプリケーションを生成したときにアプリケーションのレイアウト(app/views/layouts/application.html.erb
)に自動的に含まれるJavaScriptファイルrails-ujs
を介して行われます。このファイルがないと、確認ダイアログボックスは表示されません。
RailsでのJavaScriptの操作に関する控えめなJavaScriptについての詳細を入手してください。
おめでとうございます。これで、記事を作成、表示、一覧表示、更新、および破棄できます。
一般的に、Railsはルートを手動で宣言する代わりにリソースオブジェクトを使用することを推奨します。ルーティングの詳細については、外部からのRailsルーティングを参照してください。
6. 2つ目のモデル追加
2つ目のモデルをアプリケーションに追加します。 2つ目のモデルは記事に関するコメントを処理するモデルです。
6.1 Model生成
Article
モデルを作成するときに以前に使用したものと同じジェネレーターが表示されます。今回は、記事への参照を保持するComment
モデルを作成します。ターミナルで次のコマンドを実行します。
$ rails generate model Comment commenter:string body:text article:references
このコマンドは4つのファイルを生成します:
File | 目的 |
---|---|
db/migrate/20200314162156_create_comments.rb | データベースにコメントテーブルを作成するための移行(名前には別のタイムスタンプが含まれます) |
app/models/comment.rb | Commentモデル |
test/models/comment_test.rb | コメントモデルのテストハーネス |
test/fixtures/comments.yml | テストで使用するためのサンプルコメント |
まず、app/models/comment.rb
を見てください。
class Comment < ApplicationRecord
belongs_to :article
end
これは、前に見たArticle
モデルに非常に似ています。違いは、belongs_to:article
という行で、Active Recordの関連付けを設定します。このガイドの次のセクションで関連付けについて少し学習します。
bashコマンドで使用される(:references
)キーワードは、モデルの特別なデータ型です。提供されたモデル名に整数値を保持できる_id
を追加したデータベーステーブルに新しい列を作成します。理解を深めるために、移行の実行後にdb/schema.rb
ファイルを分析します。
Railsはモデルに加えて、対応するデータベーステーブルを作成するための移行も行っています。
class CreateComments < ActiveRecord::Migration[6.0]
def change
create_table :comments do |t|
t.string :commenter
t.text :body
t.references :article, null: false, foreign_key: true
t.timestamps
end
end
end
t.references
行は、article_id
という整数列、そのインデックス、およびarticles
テーブルのid
列を指す外部キー制約を作成します。先に進み、移行を実行します。
$ rails db:migrate
Railsは、現在のデータベースに対してまだ実行されていない移行のみを実行できるほどスマートなので、この場合は次のように表示されます。
== 20200314162156 CreateComments: migrating ===================================
-- create_table(:comments)
-> 0.0054s
== 20200314162156 CreateComments: migrated (0.0056s) ==========================
6.2 モデルの関連付け
アクティブレコードの関連付けにより、2つのモデル間の関係を簡単に宣言できます。コメントや記事の場合、次のように関係を書き出すことができます。
- 各コメントは1つの記事に属します。
- 1つの記事に多くのコメントを含めることができます。
実際、これはRailsがこの関連付けを宣言するために使用する構文に非常に近いものです。Comment
モデル(app/models/comment.rb)内に、各コメントが記事に属するようにするコード行が既にあります。
app/models/article.rb
を編集して、関連付けの反対側を追加する必要があります。
class Article < ApplicationRecord
has_many :comments
validates :title, presence: true,
length: { minimum: 5 }
end
これらの2つの宣言により、かなりの自動動作が可能になります。たとえば、記事を含むインスタンス変数@article
がある場合、@article.comments
を使用して、その記事に属するすべてのコメントを配列として取得できます。
アクティブレコードの関連付けの詳細については、アクティブレコードの関連付けガイドを参照してください。
6.3 Comments用のルートを追加する
welcome
コントローラーと同様に、コメントを表示するためにナビゲートする場所をRailsが認識できるように、ルートを追加する必要があります。 config/routes.rb
ファイルを再度開き、次のように編集します。
resources :articles do
resources :comments
end
これにより、articles
内にネストされたリソースとしてcomments
が作成されます。これは、記事とコメントの間に存在する階層関係をキャプチャする別の部分です。
ルーティングの詳細については、Railsルーティングガイドを参照してください。
6.4 コントローラーの生成
モデルを手に入れると、一致するコントローラーの作成に注意を向けることができます。繰り返しますが、前に使用したものと同じジェネレーターを使用します。
$ rails generate controller Comments
これにより、4つのファイルと1つの空のディレクトリが作成されます。
File/Directory | 目的 |
---|---|
app/controllers/comments_controller.rb | Commentsコントローラー |
app/views/comments/ | コントローラーのビューはここに保存されます |
test/controllers/comments_controller_test.rb | コントローラーのテスト |
app/helpers/comments_helper.rb | ビューヘルパーファイル |
app/assets/stylesheets/comments.scss | コントローラーのカスケードスタイルシート |
他のブログと同様に、読者は記事を読んだ後に直接コメントを作成し、コメントを追加すると、記事の表示ページに戻ってコメントが表示されるようになります。このため、CommentsController
はコメントが到着したときにコメントを作成し、スパムコメントを削除する方法を提供します。
そのため、まず、記事の表示テンプレート(app/views/articles/show.html.erb
)を接続して、新しいコメントを作成します。
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
<h2>Add a comment:</h2>
<%= form_with(model: [ @article, @article.comments.build ], local: true) do |form| %>
<p>
<%= form.label :commenter %><br>
<%= form.text_field :commenter %>
</p>
<p>
<%= form.label :body %><br>
<%= form.text_area :body %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
これにより、CommentsController
のcreate
アクションを呼び出して新しいコメントを作成するフォームが記事表示ページに追加されます。ここでのform_with
呼び出しは、/articles/1/comments
などのネストされたルートを構築する配列を使用します。
app/controllers/comments_controller.rb
で作成を結びましょう:
class CommentsController < ApplicationController
def create
@article = Article.find(params[:article_id])
@comment = @article.comments.create(comment_params)
redirect_to article_path(@article)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
end
ここでは、記事のコントローラーで行ったよりも少し複雑になります。これは、設定したネストの副作用です。コメントの各リクエストは、コメントが添付されている記事を追跡する必要があるため、問題の記事を取得するには、Article
モデルのfind
メソッドを最初に呼び出します。
さらに、コードは、関連付けに使用できるいくつかのメソッドを利用します。 @article.comments
のcreate
メソッドを使用して、コメントを作成して保存します。これにより、特定の記事に属するようにコメントが自動的にリンクされます。
新しいコメントを作成したら、article_path(@article)
ヘルパーを使用して元の記事にユーザーを送り返します。既に見たように、これはArticlesController
のshow
アクションを呼び出し、show.html.erb
テンプレートをレンダリングします。これはコメントを表示したい場所ですので、app/views/articles/show.html.erb
にコメントを追加しましょう。
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
<h2>Comments</h2>
<% @article.comments.each do |comment| %>
<p>
<strong>Commenter:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
<% end %>
<h2>Add a comment:</h2>
<%= form_with(model: [ @article, @article.comments.build ], local: true) do |form| %>
<p>
<%= form.label :commenter %><br>
<%= form.text_field :commenter %>
</p>
<p>
<%= form.label :body %><br>
<%= form.text_area :body %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
ブログに記事やコメントを追加して、適切な場所に表示できるようになりました。
7. リファクタリング
記事とコメントが機能するようになったので、app/views/articles/show.html.erb
テンプレートを見てください。長くて厄介です。パーシャルを使用してクリーンアップできます。
7.1 部分コレクションのレンダリング
最初に、記事のすべてのコメントを表示するためにコメントを部分的に作成します。ファイルapp/views/comments/_comment.html.erb
を作成し、次のファイルをそこに入れます。
<p>
<strong>Commenter:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
その後、app/views/articles/show.html.erb
を次のように変更できます。
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
<h2>Comments</h2>
<%= render @article.comments %>
<h2>Add a comment:</h2>
<%= form_with(model: [ @article, @article.comments.build ], local: true) do |form| %>
<p>
<%= form.label :commenter %><br>
<%= form.text_field :commenter %>
</p>
<p>
<%= form.label :body %><br>
<%= form.text_area :body %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
これにより、@article.comments
コレクションにあるコメントごとにapp/views/comments/_comment.html.erb
にパーシャルが1回レンダリングされます。 render
メソッドは@article.comments
コレクションを反復処理するので、各コメントをパーシャルと同じ名前のローカル変数(この場合はcomment
)に割り当てます。これは、パーシャルで表示できます。
7.2 部分フォームのレンダリング
また、新しいコメントセクションを独自のパーシャルに移動します。繰り返しますが、次を含むファイルapp/views/comments/_form.html.erb
を作成します。
<%= form_with(model: [ @article, @article.comments.build ], local: true) do |form| %>
<p>
<%= form.label :commenter %><br>
<%= form.text_field :commenter %>
</p>
<p>
<%= form.label :body %><br>
<%= form.text_area :body %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
次に、app/views/articles/show.html.erb
を次のようにします。
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
<h2>Comments</h2>
<%= render @article.comments %>
<h2>Add a comment:</h2>
<%= render 'comments/form' %>
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
2番目のレンダリングは、レンダリングする部分テンプレート、comments/form
を定義するだけです。 Railsは、その文字列のスラッシュを見つけて、app/views/comments
ディレクトリにある_form.html.erb
ファイルをレンダリングしたいことを認識するのに十分賢いです。
@article
オブジェクトは、インスタンス変数として定義したため、ビューにレンダリングされたすべてのパーシャルで使用できます。
8. コメントを削除する
ブログのもう1つの重要な機能は、スパムコメントを削除できることです。これを行うには、ビューに何らかのリンクを実装し、CommentsController
にdestroy
アクションを実装する必要があります。
まず、app/views/comments/_comment.html.erb
に削除リンクを追加しましょう。
<p>
<strong>Commenter:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
<p>
<%= link_to 'Destroy Comment', [comment.article, comment],
method: :delete,
data: { confirm: 'Are you sure?' } %>
</p>
この新しい「Destroy Comment」リンクをクリックすると、DELETE
が起動します
/articles/:article_id/comments/:id
をCommentsController
に追加し、これを使用して削除するコメントを見つけることができるので、コントローラーにdestroy
アクションを追加しましょう(app/controllers/comments_controller.rb
):
class CommentsController < ApplicationController
def create
@article = Article.find(params[:article_id])
@comment = @article.comments.create(comment_params)
redirect_to article_path(@article)
end
def destroy
@article = Article.find(params[:article_id])
@comment = @article.comments.find(params[:id])
@comment.destroy
redirect_to article_path(@article)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
end
destroy
アクションは、私たちが見ている記事を見つけ、@article.comments
コレクション内でコメントを見つけ、データベースからコメントを削除して、記事のshow
アクションに送り返します。
8.1 関連オブジェクトの削除
記事を削除する場合、関連するコメントも削除する必要があります。削除しないと、データベース内のスペースを占有するだけです。 Railsでは、関連付けのdepend
オプションを使用してこれを実現できます。次のように、記事モデルapp/models/article.rb
を変更します。
class Article < ApplicationRecord
has_many :comments, dependent: :destroy
validates :title, presence: true,
length: { minimum: 5 }
end
9. セキュリティ
9.1 Basic認証
ブログをオンラインで公開すると、誰でも記事を追加、編集、削除したり、コメントを削除したりできます。
Railsは、この状況でうまく機能する非常にシンプルなHTTP認証システムを提供します。
ArticlesController
では、個人が認証されていない場合、さまざまなアクションへのアクセスをブロックする方法が必要です。ここでは、Railsのhttp_basic_authenticate_with
メソッドを使用できます。これにより、要求されたアクションが許可されている場合、そのアクションへのアクセスが許可されます。
認証システムを使用するには、app/controllers/articles_controller.rb
のArticlesController
の上部で指定します。この場合、index
およびshow
を除くすべてのアクションでユーザーを認証する必要があるため、次のように記述します。
class ArticlesController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
def index
@articles = Article.all
end
# snippet for brevity
また、認証されたユーザーだけがコメントを削除できるようにするため、CommentsController
(app/controllers/comments_controller.rb
)に次のように記述します。
class CommentsController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy
def create
@article = Article.find(params[:article_id])
# ...
end
# snippet for brevity
これで、新しい記事を作成しようとすると、Basic認証が表示されます。
Railsアプリケーションでは、他の認証方法を使用できます。 Rails用の2つの一般的な認証アドオンは、Devise railsエンジンとAuthlogic gem、およびその他の多くのアドオンです。
9.2 その他のセキュリティに関する考慮事項
特にWebアプリケーションにおけるセキュリティは、幅広く詳細な領域です。 Railsアプリケーションのセキュリティについては、Ruby on Railsセキュリティガイドで詳しく説明しています。
10. 次は何?
最初のRailsアプリケーションを見たので、気軽に更新して自分で試してみてください。
覚えておいて、あなたは助けなしですべてをする必要はありません。 Railsのセットアップと実行に支援が必要な場合は、次のサポートリソースを参照してください。
・Ruby on Railsガイド
・Ruby on Railsメーリングリスト
・irc.freenode.netの#rubyonrailsチャンネル※日本では確認取れない?
11. 構成の落とし穴
Railsを使用する最も簡単な方法は、すべての外部データをUTF-8として保存することです。そうしないと、RubyライブラリとRailsは多くの場合ネイティブデータをUTF-8に変換できますが、これは常に確実に機能するとは限らないため、すべての外部データをUTF-8にすることをお勧めします。
この領域で間違いを犯した場合、最も一般的な症状は、ブラウザに表示される疑問符の内側に黒い菱形です。別の一般的な症状は、「ü」の代わりに「ü」などの文字が表示されることです。 Railsは、これらの問題の一般的な原因を軽減するために、自動的に検出および修正できる多くの内部手順を実行します。ただし、UTF-8として保存されていない外部データがある場合、Railsが自動的に検出して修正できないこの種の問題が発生することがあります。
UTF-8ではない2つの非常に一般的なデータソース:
- テキストエディター:ほとんどのテキストエディター(TextMateなど)、デフォルトではファイルをUTF-8として保存します。テキストエディターがそうでない場合、テンプレートに入力した特殊文字(éなど)がブラウザー内に疑問符の付いたひし形として表示される可能性があります。これは、国際化翻訳ファイルにも適用されます。まだUTF-8にデフォルト設定されていないほとんどのエディター(Dreamweaverの一部のバージョンなど)は、デフォルトをUTF-8に変更する方法を提供します。そうする。
- ご使用のデータベース:Railsは、デフォルトでデータベースのデータを境界でUTF-8に変換します。ただし、データベースが内部でUTF-8を使用していない場合、ユーザーが入力したすべての文字を保存できない場合があります。たとえば、データベースがLatin-1を内部で使用しており、ユーザーがロシア語、ヘブライ語、または日本語の文字を入力した場合、データベースに入るとデータは永久に失われます。可能であれば、データベースの内部ストレージとしてUTF-8を使用してください。