Edited at

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

More than 3 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