Reputation: 47
I have a "user" model. I have a list of users on the user index page with an edit button beside each. I want to click on the edit button for each user which will open a bootstrap modal.
On the bootstrap modal I want to display the user record which I can edit. The edit form will be from a _form.html.erb partial which will be used for the new and edit user controller methods.
When I click the update button, I want the modal form to update the record, close the modal and update the index page with the updated record.
Issues
Every time I click on the edit link the modal opens and displays the _forms partial but it is for a new record, not the record I want to edit. I think this is because rails runs the @user.persisted? helper which responds with false so it uses the "create" method in the user controller instead of the "edit" method.
The bootstrap modal does not close when I save the record.
Can you tell me how to get this to work?
user/_form.html.erb
<%= form_for(@user, remote: true) 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 |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %>
<br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :company %>
<br>
<%= f.text_field :company %>
</div>
<div class="field">
<%= f.label :email %>
<br>
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
users/create.js.erb
$(".usersTable").replaceWith("<%=j render :partial=> 'users/update_user', :locals => {users: @users }%>");
$("input[type=text]").val("");
$('#myModal').modal('hide');
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
users/index.html.erb
<h1>Listing users</h1>
<table class="usersAll">
<thead>
<tr>
<th>Name</th>
<th>Company</th>
<th>Email</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody class="usersTable">
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.company %></td>
<td><%= user.email %></td>
<td><%= link_to 'Show', user %></td>
<td><%= link_to 'Edit', '#', 'data-target' => '#myModal', 'data-toggle' => 'modal' %></td>
<td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<!-- Button trigger modal -->
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Add User
</button>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
<%= render 'users/form' %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
@users = User.all
@user = User.new
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
@user = User.new
end
# GET /users/1/edit
def edit
@user = User.find(params[:id])
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if @user.update(user_params)
format.js {}
else
format.html { render action: 'edit' }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
Upvotes: 3
Views: 8402
Reputation: 613
@aquajach has given you the right code to solve your 1st problem. Notice that your problem arose because you did not send the 'user' parameter to the form partial, and instead used @user
to build the form, which is the variable you initialized in the index action with new
(so it is empty). As @aquajach did to send the right parameter, you need to place the modal code inside the `.each' loop, otherwise there is no way of telling which user's information you want each modal to display.
Also note that the Edit link_to uses "#" as its url. This means it will link to nowhere, and definitely not go back to the controller on the server (neither to edit, nor to create).
As for your second question. Notice that the Close button has data-dismiss="modal"
, but the Save Changes button does not. Append that code, to get it to hide the modal as well.
Upvotes: 0
Reputation: 2578
The current form is not for editing the record, change it to:
users/index.html.erb
<h1>Listing users</h1>
<table class="usersAll">
<thead>
<tr>
<th>Name</th>
<th>Company</th>
<th>Email</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody class="usersTable">
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.company %></td>
<td><%= user.email %></td>
<td><%= link_to 'Show', user %></td>
<td>
<%= link_to 'Edit', '#', 'data-target' => "#myModal_#{user.id}", 'data-toggle' => 'modal' %>
<div class="modal fade" id='<%= "myModal_#{user.id}" %>' tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
<%= render 'users/form', user: user %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</td>
<td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<!-- Button trigger modal -->
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Add User
</button>
user/_form.html.erb
<%= form_for(user, remote: true) 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 |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %>
<br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :company %>
<br>
<%= f.text_field :company %>
</div>
<div class="field">
<%= f.label :email %>
<br>
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
If you want clicking the submit to refresh the entire page, just remove remote: true from the _form.html.erb
Upvotes: 5