1
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?

Ruby on Rails<Step2>

1
Posted at

📅 note公開日:2025-09-14 20:59
🔁 この記事はnoteで公開していた内容をQiitaへ移行・再掲したものです。(必要に応じて加筆修正しています)

Home 画面の記事一覧の下に「Create」ボタンを配置し、ボタンを押すと Create 画面に遷移する

Create 画面で「Publish Article」を押すと、入力した内容がデータベースに保存され、Home 画面のリストに表示される

Home 画面の記事をクリックすると、該当の記事の Article 画面に遷移する

Article 画面で「Edit Article」ボタンを押すと Edit 画面に遷移し、各項目には記事の内容が入力済みで表示される

Edit 画面で内容を変更して「Publish Article」を押すと、データベースが更新され、Home 画面でも更新後の内容が表示される

「Delete Article」ボタンを押すと記事がデータベースから削除され、Home 画面のリストからも削除される


1、Home 画面の記事一覧の下に「Create」ボタンを配置し、ボタンを押すと Create 画面に遷移する

1-1,作業場に移動
1-2,コードを追加すべき場所を特定
1-3,コードを追加

1-1,作業場に移動

Home画面のUIを見せているのは
app>views>articles>index.html.erbにあるので、まずここへ移動

1-2,コードを追加すべき場所を特定

今回のは記事一覧というボタンはなく、ホームページっぽく見せるためにhtmlとcssだけでかかれた画面のため、どのあたりが一番したかな?と探す。以下の写真の様な場所にcreateボタンを作りたい。

image.png

以下、htmlの画面。Albert Paiの記事を表示させているhtmlの行です。
この一塊の直下にボタンを配置すればいいと思います。

<div class="article-preview">
  <div class="article-meta">
    <a href="/profile/albert-pai"><img src="http://i.imgur.com/N4VcUeJ.jpg" /></a>
    <div class="info">
      <a href="/profile/albert-pai" class="author">Albert Pai</a>
      <span class="date">January 20th</span>
    </div>
    <button class="btn btn-outline-primary btn-sm pull-xs-right">
      <i class="ion-heart"></i> 32
    </button>
  </div>
  <a href="/article/the-song-you" class="preview-link">
    <h1>The song you won't ever stop singing. No matter how hard you try.</h1>
    <p>This is the description for the post.</p>
    <span>Read more...</span>
    <ul class="tag-list">
      <li class="tag-default tag-pill tag-outline">realworld</li>
      <li class="tag-default tag-pill tag-outline">implementations</li>
    </ul>
  </a>
</div>

1-3,コードを追加

移動先に似せたいボタンがあるので取ってこれるかやってみます。
Publish Articleボタンと同じ様にしたいので、app>views>articles>new.html.erbに移動しCSSを探します。

image.png

あった!

<%= link_to "Publish Article", "/articles/show", class: "btn btn-lg pull-xs-right btn-primary" %>

copy

これを拝借で中身を書き換えでどうかしら。

<%= link_to "Create", "/articles/new",class: "btn btn-lg pull-xs-right btn-primary" %>

成功です!動作も問題ありませんでした。

image.png


2、Create 画面で「Publish Article」を押すと、入力した内容がデータベースに保存され、Home 画面のリストに表示される

2-0,前知識MVCモデル
2-1,rails generate model で Article モデルを作る
2-2,コントローラに create アクションを追加
2-3,ルーティングに create を追加
2-4,new.html.erb のフォームを form_with に書き換える
(ここまでできれば、「フォーム入力 → Publish Articleクリック → createアクションにPOST → 保存 → Homeへリダイレクト」がつながる。)
2-5,index.html.erb に保存された記事を表示する

2-0,前知識MVCモデル

1、フォームから要求が出される
ユーザーが「Publish Article」を押す
→ HTTPリクエスト(POST /articles)がサーバに送られる

2、コントローラが受け取る
ArticlesController#create が呼ばれる
params にフォームの入力値が入っている

3、モデルへ送信 & DB保存
Article.new(params) でモデルのオブジェクトを作成
.save を呼ぶと ActiveRecord が DB(MySQL/SQLiteなど)にINSERTする

4、DBから呼び出し(読み込み)
保存したデータをもう一度 Article.all などで取り出せる

5、コントローラがviewへ渡す
コントローラで @articles = Article.all を用意
この @articles がビューで使える変数になる

6、ビューで表示
index.html.erb が @articles を使ってリストをレンダリング
ユーザーに「新しい記事が一覧に追加された!」と見える

MVCモデルの画像を一緒に載せるべきなんですが、著作権かかっているものしかなく載せれません。MVCモデルと検索し画像からもまずはデータの流れを確認し理解して取り組んだほうがいいと思います。


2-1,rails generate model で Article モデルを作る

<なぜモデルを作る必要があるのか?>-----------------------

  1. モデルがないとどうなる?
    Rails でフォームから記事を送って「Publish Article」を押しても、
    受け取ったデータを保存する 入れ物(テーブル) が存在しない。
    つまり「保存先がない=データは一切残らない」状態。

  2. モデルがあると何ができる?
    モデルの役割
     -DBのテーブルと1対1で対応する
     -Article モデル → articles テーブル
     -カラム(title, description, body)を属性として扱える


ターミナルで以下のコマンドを入力し、
app/models/article.rb
db/migrate/XXXXXXXXXXXX_create_articles.rb
を作成する。

bin/rails   generate   model   Article   title:string   description:string   body:text
└実行バイナリ └ジェネレータ └種類     └モデル名    └属性:型         └属性:型              └属性:型

コードの解説
bin/rails:このアプリのRailsを実行(プロジェクト直下で使うのが安全)。generate(短縮形g):雛形を作るコマンド。
model:作る雛形の種類=モデル。
Article:モデル名(単数・CamelCase)。→ テーブル名は自動で複数形 articles になります。
title:string description:string body:text:作るカラム名と型。コロンで区切る。(string=短文、text=長文。)

まだDBには反映されていないので、この後に

bin/rails db:migrate

これでテーブルが作成され、db/schema.rb が更新されます。

Point
・区切りはすべて半角スペース。
・コロンは半角で name:type の形。
・型を省くと既定で string。
・モデル名は単数、テーブルは複数になる(Railsの規約)。
・途中で迷ったら bin/rails g model --help で使える型やオプションを確認。


2-2,コントローラに create アクションを追加

まずapp/controllers/articles_controller.rbに移動する。

編集前;ここに必要なコードを足していきます。

class ArticlesController < ApplicationController
  def index
  end

  def show
  end

  def new
  end

  def create
  end

  def edit
  end
end

編集後

class ArticlesController < ApplicationController

<!-- ホーム画面表示用 -->
  def index
    @articles = Article.all
  end
<!-- ここまで -->
  def show
  end
<!-- ②記事作成画面表示用 -->
  def new
    @article = Article.new
  end
<!-- ここまで -->

<!-- DB保存用 -->
  def create
    @article = Article.new(article_params)
    if @article.save
      redirect_to articles_path
    else
      render :new
    end
  end
<!-- ここまで -->

  def edit
  end
end

解説


DBに入っているすべての記事を取得 (Article.all)
インスタンス変数 @articles をビュー (index.html.erb) に渡す
ビュー側で <% @articles.each do |article| %> ... <% end %> と書けば一覧表示ができる
「保存した記事を確認できる」ための処理


空の Article オブジェクトを生成
ビュー (new.html.erb) で form_with model: @article を使うと、この空オブジェクトを元にフォームが作られる
フォームから入力して送信すると、次は create アクションが呼ばれる
「記事作成画面を表示する」ための処理


フォームから受け取った値で Article を作成して DBに保存。
成功すれば true を返す。
その場合は redirect_to articles_path が実行されて、Home画面に戻る。
保存できなかった(false が返った)とき。
render :new
→ 「新規作成フォーム(new.html.erb)をもう一度表示しなさい」という命令


2-3,ルーティングに create を追加

ルーティングの目的
今のままだと new.html.erb のフォームが送信されても、
送信先(POST /articles)のルートが存在しません。
つまり create アクション用のルートを追加する必要があります。

ルート追加方法
config/routes.rbへ移動&編集する。

編集前

Rails.application.routes.draw do
  get "articles/index"
  get "articles/show"
  get "articles/new"
  get "articles/edit"
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
  # Can be used by load balancers and uptime monitors to verify that the app is live.
  get "up" => "rails/health#show", as: :rails_health_check

  # Render dynamic PWA files from app/views/pwa/* (remember to link manifest in application.html.erb)
  # get "manifest" => "rails/pwa#manifest", as: :pwa_manifest
  # get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker

  # Defines the root path route ("/")
  # root "posts#index"
end

編集後

Rails.application.routes.draw do
root "articles#index"

  resources :articles, only: [:index, :show, :new, :edit, :create]
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
  # Can be used by load balancers and uptime monitors to verify that the app is live.
  get "up" => "rails/health#show", as: :rails_health_check

  # Render dynamic PWA files from app/views/pwa/* (remember to link manifest in application.html.erb)
  # get "manifest" => "rails/pwa#manifest", as: :pwa_manifest
  # get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker

  # Defines the root path route ("/")
  # root "posts#index"
end

解説
-get "articles/index" などは 不要(resources が全部カバーする)
-resources :articles, only: [...] が create 用の POST /articles を生んでくれる
-root "articles#index" を入れると、http://localhost:3000/ で Home が開ける

⚠️resources:articlesに変更したために、以降、アクセスするリンクが変わります。

正しいURLで確認

Home(index):http://localhost:3000/
Create(new):http://localhost:3000/articles/new
Edit(edit):http://localhost:3000/articles/1/edit(ダミーIDでOK)
Show(show):http://localhost:3000/articles/1

copy


2-4,new.html.erb のフォームを form_with に書き換える

編集前;このままではコントローラーに届かないため、form_with形式に書き換えます。

<form>
  <fieldset>
    <fieldset class="form-group">
      <input type="text" class="form-control form-control-lg" placeholder="Article Title" />
    </fieldset>
    <fieldset class="form-group">
      <input type="text" class="form-control" placeholder="What's this article about?" />
    </fieldset>
    <fieldset class="form-group">
      <textarea
        class="form-control"
        rows="8"
        placeholder="Write your article (in markdown)"
      ></textarea>
    </fieldset>
    <fieldset class="form-group">
      <input type="text" class="form-control" placeholder="Enter tags" />
      <div class="tag-list">
        <span class="tag-default tag-pill"> <i class="ion-close-round"></i> tag </span>
      </div>
    </fieldset>
    <%= link_to "Publish Article", "/articles/show", class: "btn btn-lg pull-xs-right btn-primary" %>
  </fieldset>
</form>

編集後

<%= form_with model: @article, local: true do |f| %>
  <fieldset class="form-group">
    <%= f.text_field :title, class: "form-control form-control-lg", placeholder: "Article Title" %>
  </fieldset>

  <fieldset class="form-group">
    <%= f.text_field :description, class: "form-control", placeholder: "What's this article about?" %>
  </fieldset>

  <fieldset class="form-group">
    <%= f.text_area :body, class: "form-control", rows: 8, placeholder: "Write your article (in markdown)" %>
  </fieldset>

  <%= f.submit "Publish Article", class: "btn btn-lg pull-xs-right btn-primary" %>
<% end %>

解説

タグを Rails が自動生成してくれる(action="/articles" method="post" にしてくれる) f.text_field :title → @article.title に紐付く f.text_area :body → @article.body に紐付く f.submit → DB保存のための「Publish Article」ボタン

2-5,index.html.erb に保存された記事を表示する

元々投稿記事っぽく表示する様にhtmlで書かれていた記事欄(article-preview)を削除して、コントローラーから渡されたDB保存済みviewを呼び出してきて表示させる物に書き換えます。

編集前

<div class="article-preview">
  <div class="article-meta">
    <a href="/profile/eric-simons"><img src="http://i.imgur.com/Qr71crq.jpg" /></a>
    <div class="info">
      <a href="/profile/eric-simons" class="author">Eric Simons</a>
      <span class="date">January 20th</span>
    </div>
    <button class="btn btn-outline-primary btn-sm pull-xs-right">
      <i class="ion-heart"></i> 29
    </button>
  </div>
  <a href="/article/how-to-build-webapps-that-scale" class="preview-link">
    <h1>How to build webapps that scale</h1>
    <p>This is the description for the post.</p>
    <span>Read more...</span>
    <ul class="tag-list">
      <li class="tag-default tag-pill tag-outline">realworld</li>
      <li class="tag-default tag-pill tag-outline">implementations</li>
    </ul>
  </a>
</div>

<div class="article-preview">
  <div class="article-meta">
    <a href="/profile/albert-pai"><img src="http://i.imgur.com/N4VcUeJ.jpg" /></a>
    <div class="info">
      <a href="/profile/albert-pai" class="author">Albert Pai</a>
      <span class="date">January 20th</span>
    </div>
    <button class="btn btn-outline-primary btn-sm pull-xs-right">
      <i class="ion-heart"></i> 32
    </button>
  </div>
  <a href="/article/the-song-you" class="preview-link">
    <h1>The song you won't ever stop singing. No matter how hard you try.</h1>
    <p>This is the description for the post.</p>
    <span>Read more...</span>
    <ul class="tag-list">
      <li class="tag-default tag-pill tag-outline">realworld</li>
      <li class="tag-default tag-pill tag-outline">implementations</li>
    </ul>
  </a>
</div>

編集後

<% if @articles.any? %>
<% @articles.each do |article| %>
    <div class="article-preview">
    <a href="<%= article_path(article) %>" class="preview-link">
        <h1><%= article.title %></h1>
        <p><%= article.description %></p>
        <span>Read more...</span>
    </a>
    </div>
<% end %>
<% else %>
<div class="article-preview">
    <p>まだ記事がありません。右下の「Create」から作成してね!</p>
</div>
<% end %>

解説
@articles.any? の意味
-@articles はコントローラで @articles = Article.all として渡された記事の配列(ActiveRecordのコレクション)。
-.any? は 「中に要素が1つでもあるか?」をチェックするメソッド。
もし記事が1件以上あれば → true
記事が0件なら → false


かなり長くなりそうなので、一旦ここで次の章に引き継ぎます💦


Conclusion

今回のStep2では、Createボタンの配置から始めて、Articleモデル作成 → createアクション追加 → ルーティング追加 → form_with化 → indexでDB記事表示 までを一連でつなげました。
「フォーム送信 → DB保存 → Home表示」の流れが通ると、以降のEdit/Deleteも同じ考え方で進められるので、まずはこの導線を作るのが大事だと感じました。

1
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
1
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?