Help us understand the problem. What is going on with this article?

Railsで更新も編集も削除も、全部indexページでやりたい

More than 5 years have passed since last update.

RailsでScaffoldで画面を作ると、丁寧に新規・修正毎にViewができあがります。
ですが、できれば同じ1つの画面内で新規も修正もやりたいと思ったこと、ありませんか?

ということでindexページ内で全て新規登録も修正も完結するサンプルを作ってみました。

準備編

まずscaffoldでCRUD画面をちゃっちゃっと作りますね。

$ rails g scaffold User name:string age:decimal note:text

適当にテストデータを入れます。
Hashieとか使っているのは趣味です。

seed.rb
[
    {name: "Spike Spiegel", age: 27, birth: "2044-06-26", note: "SwordFish2"},
    {name: "Jet Black", age: 36, birth: "2035-12-03", note: "Hammerhead"},
    {name: "Faye Valentine", age: 77, note: "1994-08-14", note: "redtail"},
    {name: "Edward Wong Hau Pepelu Tivrusly 4", age: 13, birth: "2058-01-01", note: ""},
    {name: "Ein", age: 2}
].map{|row| Hashie::Mash.new(row) }.each do |data|
    User.create!(
        name: data.name,
        age: data.age,
        birth: data.birth,
        note: data.note
        )
end

indexページをルートに設定しておきます。

config/routes.rb
Rails.application.routes.draw do
  root "users#index"
  resources :users
end

新規登録編

_form.html.erbの中身をまずはガバっと貼り付けます。

users/index.html.erb
# -------------ここから----------------
<h1>Listing users</h1>

<%= form_for(@user) do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @user.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :age %><br>
    <%= f.text_field :age %>
  </div>
  <div class="field">
    <%= f.label :note %><br>
    <%= f.text_area :note %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

# -------------ここまで----------------


<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
      <th>Note</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= user.age %></td>
        <td><%= user.note %></td>
        <td><%= link_to 'Show', user %></td>
        <td><%= link_to 'Edit', edit_user_path(user) %></td>
        <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New User', new_user_path %>

コントローラでform_forヘルパに渡すための@userオブジェクトを作成します。

app/controllers/users_controller.rb
def index
  @users = User.all
  @user = User.new   #追記
end

こんな見た目になります。

FormWithIndex.png

OK。表示はできました。
この状態でも更新できますが、users/:id/showへ遷移してしまうので更新後に元のindexページに戻るようにします。

redirect_to users_path

(今回はrootがusers#indexなので、root_pathでも同じですが。)

app/controllers/users_controller.rb
def create
  @user = User.new(user_params)

  respond_to do |format|
    if @user.save
      format.html { redirect_to  users_path, notice: 'User was successfully created.' }
      format.json { render :show, status: :created, location: @user }
    else
      format.html { render :new }
      format.json { render json: @user.errors, status: :unprocessable_entity }
    end
  end
end

"New User"をクリックしたときの遷移先も直しておきます。

_form.html.erb
<%= link_to 'New User', users_path %>

この状態でformからレコードを登録すると、パッと見はページ遷移ナシでリストにレコードが追加されたように見えます。

更新編

さて、これでindexページにformを追加して新規レコード作成ができるようにしてみましたが、
今度は編集まで行えるようにしてみます。

まずは、「edit」リンクを踏んだ先の遷移先を、/users/:id/editページではなく、同じくindexページのままで、formに編集対象のレコードの値が表示されるようにします。

更新対象のレコードを取得するため、users_pathにレコードのidを渡すようにします。

_form.html.erb
<td><%= link_to 'Edit', edit_user_path(user) %></td>
↓
<td><%= link_to 'Edit', users_path(id: user.id) %></td>

次はコントローラ側です。
paramsにidが含まれている場合は、そのIDから検索したUserオブジェクトを返すようにします。
User.findとやってもいいのですが、既にscaffoldで作成されたset_userメソッドが存在するのでそのまま使っています。

app/controllers/users_controller.rb
def index
  @users = User.all

  if params[:id].present?
    set_user
  else
    @user = User.new
  end
end

更新後には選択していたレコードの内容をそのままformに表示させておきたいので、
update後のリダイレクト先はusers_pathではなく、request.refererとしておきます。

app/controllers/users_controller.rb
def update
  respond_to do |format|
    if @user.update(user_params)
      format.html { redirect_to request.referer, notice: 'User was successfully updated.' }
      format.json { render :show, status: :ok, location: @user }
    else
      format.html { render :edit }
      format.json { render json: @user.errors, status: :unprocessable_entity }
    end
  end
end

削除編

削除は何も変えなくてOKですね。

その他

show/new/editアクションは使わないので、ルーティングから削除してcontrollerからも消しておいたほうが良いですね。

config/routes.rb
resources :users, expect: [:show, :new, :edit]

そんなこんなで完成です。
作ったサンプルは
https://github.com/jacoyutorius/form_with_index にありますので、もし良ければ参考にしてみてください。

FormWithIndex.png

jacoyutorius
Software/Server developer at AIRS. Ruby / AWS / Vue
http://jacoyutorius.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした