これは、最新のRuby on Rails ガイド(v5.1.3) を読んだ際の学習記録です。
#1はこちら Ruby on Rails Guides(v5.1.3) Getting Started with Railsを読む#1 - Do Something
Adding a Second Model
Articleにつづいて、2つめのmodelを追加しよう。
Generating a Model
$ rails generate model Comment commenter:string body:text article:references Running via Spring preloader in process 19903 invoke active_record create db/migrate/20170817114832_create_comments.rb create app/models/comment.rb invoke test_unit create test/models/comment_test.rb create test/fixtures/comments.yml
生成された app/models/comment.rb を見てみよう。
class Comment < ApplicationRecord belongs_to :article end
belongs_to :article という記述がある。これはアクティブレコードの関連付けを表している。db:migrateをコマンドを実行してみよう。
$ rails db:migrate
db/schema.rb を見てみよう。以下のように変更されている。
ActiveRecord::Schema.define(version: 20170817114832) do create_table "articles", force: :cascade do |t| t.string "title" t.text "text" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "comments", force: :cascade do |t| t.string "commenter" t.text "body" t.integer "article_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["article_id"], name: "index_comments_on_article_id" end end
Associating Models
Active Record Associationを使用すると、2つのモデル間の関係を簡単に宣言できる。 コメントや記事の場合は、このように関係を書き出すことができます。
- Each comment belongs to one article.
- One article can have many comments.
app/models/article.rb へも関係を表すための記述を追加する必要がある。以下のようにhas_manyを追加しよう。
class Article < ApplicationRecord has_many :comments validates :title, presence: true, length: { minimum: 5 } end
Adding a Route for Comments
config/routes.rb を開き、以下のように編集する。
resources :articles do resources :comments end
Generating a Controller
$ rails generate create controller Comments create app/controllers/comments_controller.rb invoke erb create app/views/comments invoke test_unit create test/controllers/comments_controller_test.rb invoke helper create app/helpers/comments_helper.rb invoke test_unit invoke assets invoke coffee create app/assets/javascripts/comments.coffee invoke scss create app/assets/stylesheets/comments.scss
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_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %>
create in 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
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_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %>
Refactoring
app/views/articles/show.html.erb をpartialsファイルを作成することで簡潔にする。
Rendering Partial Collections
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_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %>
これでコメント毎にapp / views / comments / _comment.html.erb をレンダーされる。
Rendering a Partial Form
app/views/comments/_form.html.erb を作成する。
<%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.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 %>
Deleting Comments
スパムコメントの削除機能。
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>
app/controllers/comments_controller.rb へ destroyアクションを追加する。
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
Deleting Associated Objects
記事が削除されるとき、関連しているコメントも削除する必要がある。 以下のように dependentオプションを利用する。
app/models/article.rb
class Article < ApplicationRecord has_many :comments, dependent: :destroy validates :title, presence: true, length: { minimum: 5 } end
Security
Basic Authentication
Rails はHTTP認証システム備えている。 Railsのhttp_basic_authenticate_withメソッドを使用する。
app/controllers/articles_controller.rb
http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
これで、index, show 以外のアクションを実行する際に、basic認証が表示されるようになる。 destroyだけに認証をかける場合は以下のようにする。
http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy
Getting Started with Rails は以上。