0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby on Rails の公式チュートリアルやってみた!

Last updated at Posted at 2020-03-08

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 yarnrails 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のデフォルト情報ページが表示されます。

スクリーンショット 2020-03-08 19.30.17.png

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以降までやると、下記のフォームが見れます!今は見れません!)

スクリーンショット 2020-03-10 0.37.50.png

今のところ少し基本的に見えますが、それでも大丈夫です。後でスタイルの改善を検討します。

5.1 下地を整える

まず、アプリケーション内に新しい記事を作成する場所が必要です。最適な場所は/articles/newです。ルートがすでに定義されているので、アプリケーションの/articles/newにリクエストを送信できるようになりました。 http://localhost:3000/articles/newに移動すると、ルーティングエラーが表示されます。

スクリーンショット 2020-03-09 23.41.41.png

このエラーは、リクエストを処理するためにルートにコントローラーを定義する必要があるために発生します。この特定の問題の解決策は簡単です。ArticlesControllerというコントローラーを作成します。これを行うには、次のコマンドを実行します。

$ rails generate controller Articles

新しく生成されたapp/controllers/articles_controller.rbを開くと、かなり空のコントローラーが表示されます。

class ArticlesController < ApplicationController
end

コントローラーは、ApplicationControllerを継承するように定義された単なるクラスです。このコントローラーのアクションとなるメソッドを定義するのは、このクラス内です。これらのアクションは、システム内の記事に対してCRUD操作を実行します。

Rubyにはpublicprivate、およびprotectedされたメソッドがありますが、コントローラーのアクションにできるのはpublicメソッドのみです。詳細については、プログラミングRubyをご覧ください。

http://localhost:3000/articles/newを今すぐ更新すると、新しいエラーが表示されます。

スクリーンショット 2020-03-09 23.55.22.png

このエラーは、生成した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を更新すると、別のエラーが表示されます。

スクリーンショット 2020-03-10 0.06.38.png

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は最初にこのテンプレートを探します。 ArticlesControllerApplicationControllerを継承するため、見つからない場合は、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を更新すると、ページにタイトルがあることがわかります。ルート、コントローラー、アクション、およびビューが調和して機能するようになりました!新しい記事のフォームを作成します。

スクリーンショット 2020-03-10 0.25.39.png

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でフォームを作成するのは本当に簡単です!

スクリーンショット 2020-03-10 0.37.50.png

form_withを呼び出すとき、このフォームの識別スコープを渡します。この場合、それはシンボル:articleです。これは、form_withヘルパーにこのフォームの目的を伝えます。このメソッドのブロック内で、Formで表されるFormBuilderオブジェクトを使用して、記事のタイトルとテキストにそれぞれ対応する2つのラベルと2つのテキストフィールドを作成します。最後に、フォームオブジェクトでsubmit呼び出しにより、フォームの送信ボタンが作成されます。

ただし、このフォームには1つの問題があります。生成されたHTMLを調べて、ページのソースを表示すると、フォームのアクション属性が/articles/newを指していることがわかります。これは問題です。なぜなら、このルートは、あなたが今いるページそのものに行き、そのルートは新しい記事のフォームを表示するためだけに使用されるべきだからです。

スクリーンショット 2020-03-10 0.47.38.png

別の場所に移動するには、フォームで別の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の作成アクションに関連付けられています。

フォームとそれに関連付けられたルートを定義したら、フォームに入力し、[送信]ボタンをクリックして新しい記事の作成プロセスを開始できるので、先に進んでください。フォームを送信すると、見慣れたエラーが表示されるはずです。

スクリーンショット 2020-03-10 1.00.34.png

これを機能させるには、ArticlesController内にcreateアクションを作成する必要があります。

デフォルトでは、form_withはAjaxを使用してフォームを送信するため、ページ全体のリダイレクトはスキップされます。このガイドを読みやすくするために、local:trueを使用して無効にしました。

5.3 articles作成

「Unknown action」をなくすには、次に示すように、app/controllers/ articles_controller.rbArticlesControllerクラス内で、新しいアクションの下に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のパラメーターを表示しています。ただし、これは実際にはそれほど役に立ちません。はい、パラメータを見ることができますが、特に何も行われていません。

スクリーンショット 2020-03-10 8.22.31.png

5.4 Article model作成

Railsのモデルは単数形の名前を使用し、対応するデータベーステーブルは複数形の名前を使用します。 Railsは、モデルを作成するためのジェネレーターを提供します。これは、ほとんどのRails開発者が新しいモデルを作成するときに使用する傾向があります。新しいモデルを作成するには、ターミナルで次のコマンドを実行します。

$ rails generate model Article title:string text:text

このコマンドを使用して、文字列タイプのタイトル属性とテキストタイプのテキスト属性とともに、Articleモデルが必要であることをRailsに伝えました。これらの属性は、データベース内のarticleテーブルに自動的に追加され、articleモデルにマップされます。

Railsは、多数のファイルを作成して応答しました。今のところ、app/models/article.rbdb/migrate/20140120191729_create_articles.rbにのみ興味があります(名前は少し異なる場合があります)。後者はデータベース構造の作成を担当します。これについては次に説明します。

5.5 Migration実行

これまで見てきたように、rails generate modeldb/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.newAが大文字であるのか疑問に思うかもしれませんが、このガイドの他のほとんどの記事では小文字を使用しています。このコンテキストでは、app/models/article.rbで定義されているArticleという名前のクラスを参照しています。 Rubyのクラス名は大文字で始める必要があります。

後で見るように、@article.saveは記事が保存されたかどうかを示すブール値を返します。

ここでhttp://localhost:3000/articles/newにアクセスすると、記事をほぼ作成できます。それを試してみてください!次のようなエラーが表示されます。

スクリーンショット 2020-03-11 8.22.12.png

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, updatedestroyの順序で各コントローラーに標準の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にアクセスして、試してみてください!

スクリーンショット 2020-03-12 9.18.26.png

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にアクセスすると、作成したすべての記事のリストが表示されます。

スクリーンショット 2020-03-14 19.35.19.png

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でタイトルを付けずに記事を保存しようとすると、素敵なエラーメッセージが表示されます。

スクリーンショット 2020-03-14 20.59.00.png

5.11 Article編集

CRUDの「CR」部分について説明しました。では、記事を更新する「U」の部分に注目しましょう。

最初に行うステップは、次に示すように、通常はnewアクションとcreateアクションの間に、ArticlesControllereditアクションを追加することです。

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.rbupdateアクションを作成する必要があります。 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 %>

これまでのアプリの外観は次のとおりです。

スクリーンショット 2020-03-14 23.09.52.png

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を介して行われます。このファイルがないと、確認ダイアログボックスは表示されません。

スクリーンショット 2020-03-15 0.03.52.png

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 %>

これにより、CommentsControllercreateアクションを呼び出して新しいコメントを作成するフォームが記事表示ページに追加されます。ここでの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.commentscreateメソッドを使用して、コメントを作成して保存します。これにより、特定の記事に属するようにコメントが自動的にリンクされます。

新しいコメントを作成したら、article_path(@article)ヘルパーを使用して元の記事にユーザーを送り返します。既に見たように、これはArticlesControllershowアクションを呼び出し、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 %>

ブログに記事やコメントを追加して、適切な場所に表示できるようになりました。

スクリーンショット 2020-03-15 15.24.19.png

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つの重要な機能は、スパムコメントを削除できることです。これを行うには、ビューに何らかのリンクを実装し、CommentsControllerdestroyアクションを実装する必要があります。

まず、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/:idCommentsControllerに追加し、これを使用して削除するコメントを見つけることができるので、コントローラーに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.rbArticlesControllerの上部で指定します。この場合、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

また、認証されたユーザーだけがコメントを削除できるようにするため、CommentsControllerapp/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認証が表示されます。

スクリーンショット 2020-03-16 0.55.09.png

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を使用してください。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?