Edit in modal with rails and bootstrap - ruby-on-rails

I'm developing a simple todo list. I want to have delete and edit button for each list item. Also I want edit and create opens in modal window. Now thats work for create and I can't figure out how to make it work with edit(now modal window shows but it steel a create window).
Here is my index.html:
<div class="container-fluid">
<div class="row">
<h1 class="text-left">Task List</h1>
<button type="button" class="btn btn-primary pull-right" data-toggle="modal" data-target="#myModal">New task</button>
</div>
<div class="row button-margin ">
<% #tasks.each do |task| %>
<div class="panel <%= task_status(task) %>">
<div class="panel-heading">
<%= task.title %>
<%= link_to task_path(task), class:"btn btn-link pull-right", method: :delete, data: { confirm: 'Are you sure?' } do %>
<span class="glyphicon glyphicon-remove" style="color:gray"></span>
<% end %>
<!-- <button type="submit" class="btn btn-link pull-right"> -->
<%= link_to edit_task_path(task), class:"btn btn-link pull-right", remote:true, "data-toggle" => "modal", "data-dismiss=" => "modal", "data-target" => "#myModal" do %>
<span class="glyphicon glyphicon-pencil" style="color:gray"></span>
<!-- </button> -->
<% end %>
</div>
<div class="panel-body">
<h3><%= task.body %></h3>
</div>
</div>
<% end %>
</div>
<%= render "tasks/form" %>
</div>
This is _form partial with modal
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">New task</h4>
</div>
<div class="modal-body">
<%= form_for #task, :html => {class:"form-horizontal"} do |f|%>
<div class="form-group">
<label for="inputTitle" class="col-sm-2 control-label">Title</label>
<div class="col-sm-10">
<%= f.text_field :title, class:"form-control", id:"inputTitle", placeholder:"Title" %>
</div>
</div>
<div class="form-group">
<label for="inputBody" class="col-sm-2 control-label">Task</label>
<div class="col-sm-10">
<%= f.text_area :body, class:"form-control", id:"inputBody", placeholder:"Task text", rows:"3"%>
</div>
</div>
<div class="form-group">
<label for="dueDate" class="col-sm-2 control-label">Date</label>
<div class="col-sm-10">
<%= f.datetime_local_field :dueDate, class:"form-control", id:"dueDate"%>
</div>
</div>
<div class="modal-footer">
<%= f.submit class:"btn btn-primary"%>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
<% end %>
</div>
</div>
</div>
</div>
And also task controleer:
class TasksController < ApplicationController
def index
#tasks=Task.all
#task = Task.new
end
def new
#task=Task.new
end
def show
#task=Task.find(params[:id])
end
def edit
#task=Task.find(params[:id])
end
def create
#task=Task.new(task_params)
if #task.save
redirect_to tasks_path
else
render 'new'
end
end
def update
#task = Task.find(params[:id])
if #task.update(task_params)
redirect_to tasks_path
else
render 'edit'
end
end
def destroy
#task = Task.find(params[:id])
#task.destroy
redirect_to tasks_path
end
private
def task_params
params.require(:task).permit(:title, :body, :creationDate, :dueDate)
end
end
Can anybody explain what I'm doing wrong? Wy form opens but doesnot fill with selected task?

In edit.html.erb
<%= render "tasks/form" %>
add ajax call for edit page in index.html.erb, fetch edit page and display it in modal.

You are using remote: true in your link_to edit_task_path(task). This way, task will be loaded asynchronously and the page will not be refreshed. Thats why your form doesn't get filled.
Also, using the same link to load the task and open the modal. I think you'll need a better approach.

Related

How can I use ajax to display Bootstrap 4 modal in Rails 6 app?

Currently I have a modal rendering for each piece on the page. It works but I don't want to render a modal for each piece each time the page is loaded.
Here is the code where my modal is rendered now:
site/gallery.html.erb
<% #pieces.each_slice(3) do |pieces| %>
<div class="row">
<% pieces.each do |piece| %>
<div class="col-lg-4">
<%= image_tag (piece.images.joins(:blob).order('active_storage_blobs.filename ASC').first if piece.images.attached?), data: { toggle: "modal", target: "#modal#{piece.id}" }, class:"img-thumbnail mx-auto d-block img-size" %>
<p><%= piece.name %></p>
<p><%= piece.description %></p>
<%= render 'site/modal', piece: piece %>
</div>
<% end %>
</div>
<% end %>
Here is the modal partial:
site/_modal.html.erb
<div class="modal fade" id="modal<%=piece.id%>" tabindex="-1" role="dialog" aria-labelledby="modalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalLabel"><%= piece.name %></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
//code involving video and images for the piece
</div>
<div class="modal-footer">
<% if piece.quantity == 1 %>
<%= button_to 'Purchase', checkout_create_path, method: :post, params: {id: piece.id}, remote: true, class:"btn btn-dark" %>
<% else %>
<p>SOLD</p>
<% end %>
</div>
</div>
</div>
</div>
What I believe I need to do is add remote: true and pass the piece.id through my image_tag link somehow. I think I would need a modal.js.erb with something along these lines in there
$('modal').html('<%= j render "site/modal", piece: #piece %>');
$('#modal<%=piece.id%>').modal('show');
And then render the modal at the top of the gallery.html.erb page. I'm not quite sure how to go about this though
EDIT
I've made some progress with trying to use AJAX to display the modals.
I've moved my modal into the pieces directory and created a javascript file to go with it.
_piece_modal.html.erb
<div class="modal fade" id="piece-modal" tabindex="-1" role="dialog" aria-labelledby="modalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
//modal content here
</div>
</div>
</div>
piece_modal.js.erb
$('body').append('<%= j render "piece_modal", piece: #piece %>');
$('#piece-modal').modal('show');
In my pieces controller
def piece_modal
#piece = Piece.find_by(params[:piece])
end
In my routes
get 'piece_modal' => 'pieces#piece_modal'
And here is the loop I'm using images to link to my modals
<% #pieces.each_slice(3) do |pieces| %>
<div class="row">
<% pieces.each do |piece| %>
<div class="col-lg-4">
<%= link_to piece_modal_path(piece), remote: true do %>
<%= image_tag (piece.images.joins(:blob).order('active_storage_blobs.filename ASC').first if piece.images.attached?), class:"img-thumbnail mx-auto d-block img-size" %>
<% end %>
<p><%= piece.name %></p>
<p><%= piece.description %></p>
</div>
<% end %>
</div>
<% end %>
The modal displays now but it only displays images from the first piece in the loop. How can I get it to display the correct content when I click on different images?
Okay I found a way for the modal to load dynamically with some ajax.
I changed up my link_to like this
<%= link_to piece_modal_path(piece_id: piece.id), remote: true do %>
I made this change in the pieces controller
def piece_modal
#piece = Piece.find(params[:piece_id])
end
And I made this change to my piece_modal.js.erb
$('body').append('<%= j render "piece_modal", piece: #piece %>');
$('#piece-modal').modal('show');
$('#piece-modal').on('hidden.bs.modal', function () {
$(this).remove();
});
So now instead of each piece on the site rendering it's own modal, only one gets rendered when I click on the image of the piece. On hide though I have to remove it from the DOM or else the modal will stay rendered with the properties of the first piece I click on.
You have written your code like:
<%= image_tag (piece.images.joins(:blob).order('active_storage_blobs.filename ASC').first if piece.images.attached?), class:"img-thumbnail mx-auto d-block img-size" %>
But notice that you use .first which will always return the first property.
You could do something like this instead:
<% #pieces.each_slice(3) do |pieces| %>
<div class="row">
<% pieces.each_with_index do |piece, index| %>
<div class="col-lg-4">
<%= link_to piece_modal_path(piece), remote: true do %>
<%= image_tag (piece.images.joins(:blob).order('active_storage_blobs.filename ASC')[index] if piece.images.attached?), class:"img-thumbnail mx-auto d-block img-size" %>
<% end %>
<p><%= piece.name %></p>
<p><%= piece.description %></p>
</div>
<% end %>
</div>
<% end %>
p/s: I'm writing this on the fly and didn't actually test it.

How to a parameter from my URL to Modal and Controller in Rails 4 application

All, i am facing an issue with passing a parameter into my Modal to sent the value of a field. I am able to pass and lookup the value via params if i go to new page where i can find the value from the URL params. But i am trying to use the same logic but in a modal and i can't seem to get it to work.
_my comments partial has the following
<% Reply.all.each do |reply|%>
<% if reply.parent_id == comment.id%>
<p class="feed-s-connection-update-item__headline Sans-1px-black-55%">
<%= image_tag(User.find(reply.user_id).avatar,:size => "20x20",class: "image-responsive") %>
<%=reply.body %>
</p>
<%end%>
<%end%>
<% from_reply_form ||= nil %>
<% unless from_reply_form %>
<p>
<%= link_to 'reply', new_reply_path( :id => comment.id) %>
</p>
<%= link_to 'Add release', new_reply_path(#reply,:id => comment.id), {:remote => true, ':id' => 'comment.id','data-toggle' => "modal", 'data-target' => '#replyModal'} %>
<% end %>
<div id="modal-window" class="modal hide fade" role="dialog" aria- labelledby="myModalLabel" aria-hidden="true"></div>
</div>
</li>
</ul>
<%end%>
I am trying this out using this link:
<%= link_to 'Add release', new_reply_path(#reply,:id => comment.id), {:remote => true, ':id' => 'comment.id','data-toggle' => "modal", 'data-target' => '#replyModal'} %>
If i use i am taking to the new page and will have the params in the url which works fine
url: https://hidemyurldevel/replies/new?id=72
<%= link_to 'reply', new_reply_path( :id => comment.id) %></p>
I am able to see the same URL when i try the other URL where remote is true, but i am not able to see the PARENT_ID populated.
Replies_controller - know this part i need to remove the respond but i have it break here so i can see whats returning
def create
#reply = Reply.new(reply_params)
if #reply.save
flash[:notice] = "thanks for reply"
respond_to do |format|
format.js
redirect_to :back
end
end
end
def new
#reply = Reply.new
#comment = Comment.find(params[:id])
#userid = current_user.id
end
Here is the Modal i call
for some reason the value is not populated into the Modal
<%= form_for(#reply) do |f| %>
<div id="replyModal" class="modal fade" tabindex="-1" role="dialog" 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>
Post A Reply
</div>
<div class="modal-body">
<form class="form center-block">
<div class="form-group">
Post <%= f.text_area :body, class:"form-control input-lg" %>
<%= f.hidden_field :user_id, :value =>#userid %>
<%= f.hidden_field :parent_id, :value =>#comment.id %>
</div>
<div class="field">
</div>
</form>
</div>
<div class="modal-footer">
<div>
<button class="btn btn-primary btn-sm" data-dismiss="modal" aria-hidden="true">reply</button>
<ul class="pull-left list-inline"><li><i class="glyphicon glyphicon-upload"></i></li><li><i class="glyphicon glyphicon-camera"></i></li><li><i class="glyphicon glyphicon-map-marker"></i></li></ul>
</div>
<div class="actions">
<%= f.submit class: "btn btn-primary btn-sm"%>
</div>
</div>
</div>
</div>
<%end%>
I can't seem to be able to use the parent_id from the URL and pass it into the
This works fine if you go to the new page but not when i try passing it into the URL to the controller. Please help!
So guys i solve my problem... I am not sure if this is the right way to go, but i wasn't setting the comment parameters and it was Nill to begin with.... i just initialize the comment and set it to the instance of the comments and that works..
Excerpt
i am iterating the comment
then in my reply section where i add a comment field next to each comment i am able to pass the value in the URL
<%#comment = comment%>
<%= link_to 'Add release', new_reply_path(:#comment => comment), {:remote => true, :id => comment.id,'data-toggle' => "modal", 'data-target' => '#replyModal'} %>

carrierwave AJAX upload with remotipart

In my rails4 I would like to submit a form via AJAX that has a file uploaded via carrierwave. As far as I know it can be done via remotipart, but can't figure it out how I can do that. (Remotipart installed properly since it's working with refile gem that I also use in the app.)
With the current code below the form gets submitted according to the logs and it says the create.js.erb is rendered, but the code in the create.js.erb file never runs.
Rendered posts/create.js.erb (387.0ms)
What should I do?
form
<%= form_for #post, remote: true, method: :post, :html => { :multipart => true, class: "post-create-form" } do |f| %>
<img id="img_prev" style="margin-bottom:10px;" width=300 height=200 src="#" class="img-thumbnail hidden"/>
<%= f.text_area :body, placeholder: "Share something useful..", class: "form-control post-create-body" %>
<%= f.button "SHARE", class: "btn btn-primary btn-sm btn-create-post", data: {disable_with: "<i class='fa fa-spinner fa-spin'></i> Saving..."} %>
<span class="btn btn-success btn-sm btn-message-file">Upload Image
<%= f.file_field :post_image, class: "choose-message-file", id: "avatar-upload" %>
</span>
<%= f.hidden_field :post_image_cache %>
<% end %>
create.js.erb
$('ul.errors').hide();
$('.alert-danger').hide();
$('.post-index').prepend('<%= j render #post %>');
$('.post-create-body').val('');
$('.btn-create-post').prop('disabled',true);
_post.html.erb
<div class="col-md-2">
<%= link_to user_path(post.user) do %>
<%= image_tag post.user.avatar.url(:base_thumb), class: 'post-avatar' %>
<% end %>
</div>
<div class="col-md-8">
<div class="post-info">
<%= link_to user_path(post.user) do %>
<span class="post-user-name"><%= post.user.full_name %></span>
<% end %>
<span class="post-updated"><%= local_time_ago(post.updated_at) %></span>
</div>
<div class="post-body">
<%= simple_format(find_links(h post.body)) %>
</div>
<div class="post-image" data-postlink="<%= post_path(post) %>">
<% if post.post_image? %>
<button data-toggle="modal" data-target="#post-image-modal">
<%= image_tag post.post_image.url(:base_thumb) %>
</button>
<% end %>
</div>
</div>
UPDATE:
The problem is connected to updating the post object. The update form code can be found in the _post.html.erb, so that's why <%= j render #post %> didn't work. Still don't know what the problem is.
So what works:
1. creating post that has no image
2. updating post that has no image
3. updating post that has image BUT image is not edited
Not working:
1. creating post that has image
2. updating post that has image which is edited
<%= form_for post, method: :patch, remote: true, :html => { :multipart => true } do |f| %>
<div class="modal fade updatepost" id="updatepost_<%= post.id %>" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content" style="text-align:left">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="edittaskmodalohhhhh">Edit Task</h4>
</div>
<div class="modal-body">
<div class="alert alert-danger" style="display:none">
<ul class="errors" style="display:none">
<%= render 'layouts/error_messages', object: f.object %>
</ul>
</div>
<div class="field form-group">
<%= f.file_field :post_image, id: "avatar-upload-update" %>
<%= f.hidden_field :post_image_cache %>
</div>
<div class="field form-group">
<%= f.text_area :body, class: "form-control edit-post-body" %>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" id="updatepostclose">Close</button>
<%= f.button "Update post", class: 'btn btn-primary edit-post-submit', data: {disable_with: "<i class='fa fa-spinner fa-spin'></i> Saving..."} %>
</div>
</div>
</div>
</div>
<% end %>
update.js.erb
$("ul.errors").html("");
<% if #post.errors.any? %>
$('.alert-danger').show();
$('ul.errors').show();
<% #post.errors.full_messages.each do |message| %>
$("ul.errors").append($("<li />").html("<%= message.html_safe %>"));
<% end %>
<% else %>
$('ul.errors').hide();
$('.alert-danger').hide();
$('#updatepost_<%= #post.id %>').modal('hide');
$post = $('<%= j render #post %>');
editPostHideDanger($post);
$('#post_<%= #post.id %>').remove();
$(".new-post-insert").prepend($post);
$("html, body").animate({ scrollTop: 0 }, "slow");
<% end %>
There was some issue (still don't know what) with the bootstrap modals. I changed the structure of the modals and now it's working fine.

Form attribute is not nil but getting First form attribute can't be nil error

I'm getting an error on my edit user modal that says that the first argument can't be nil; however, the form works and pulls the information as expected. The setup is like this:
1) I have a table that summarizes employees
2) each employee has a modify action
3) the modify action opens up a modal with the edit form
The form works and users are able to edit employees. However, every time it's open I get an internal error notification saying that the first argument can't be nil or empty. just to be sure, I'm displaying the employee name in the edit modal to confirm it's not nil (and it's not). The problem is, I'm getting notifications for internal server errors caused by this issue although somehow the form is working.
Any thoughts on what could be causing this and how to fix it?
Employee table code:
<tr>
<td> <%= employee.name %> </td>
<td> <%= employee.status ? t(:active) : t(:inactive) %> </td>
<td> <%= mmm_dd_yy_date(employee.created_at) %> </td>
<td> <%= mmm_dd_yy_date(employee.updated_at) %> </td>
<td> <%= link_to t(:edit), '#', "data-toggle" => "modal", "data-target" => "#EditModal_#{employee.id}", "data-remote" => edit_employee_path(employee) + "#modal-edit-form" %> |
<%= link_to t(:remove), employee, method: :delete, data: { confirm: t(:confirm_remove_employee, name: employee.name)} %>
<!-- Modal -->
<div id='<%= "EditModal_#{employee.id}" %>' class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title"><%= t(:edit_employee) %></h4>
</div>
<div class="modal-body">
<%=render partial: 'edit_form', locals: {employee: employee} %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><%= t(:close) %></button>
</div>
</div>
</div>
</div>
</td>
</tr>
Form modal code:
<div id= "modal-edit-form">
<%= employee.name %>
<%=form_for(employee) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class = "row" >
<div class = "col-xs-6">
<%= f.label :name%>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :status %>
<%= f.collection_select :status, {true: t(:yes), false: t(:no)}, :first, :last, selected: employee.status %>
<%= f.submit t(:update), class: "btn btn-primary"%>
</div>
</div>
<% end %>
</div>
The code looks good to me.
--
The one thing I would say is that including form_for multiple times on the same page is a big no-no - a bunch of conflicts will occur (id etc).
I would personally move the functionality to your employees#edit action as ajax:
#app/controllers/employees_controller.rb
class EmployeesController < ApplicationController
respond_to :js, :html, :json, only: :edit
def edit
#employee = Employee.find params[:id]
respond_with #employee
end
end
#app/views/employees/edit.js.erb
$("<%=j render 'edit' %>").appendTo("body");
// fire modal
#app/views/employees/edit.html.erb
<div id='<%= "EditModal_#{employee.id}" %>' class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title"><%= t(:edit_employee) %></h4>
</div>
<div class="modal-body">
<%=render partial: 'edit_form', locals: {employee: #employee} %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><%= t(:close) %></button>
</div>
</div>
</div>
</div>
#app/views/employees/index.html.erb
<%= link_to t(:edit), '#', data: { toggle: "modal", target: "#EditModal_#{employee.id}", remote: edit_employee_path(employee) + "#modal-edit-form" }, remote: true %>
This way, you'll only be appending the edit forms when you render them.

How can I get the modal to display in the following situation?

Firstly, this does not display any errors when I click the link. Can anyone suggest why the modal is not being displayed on the button click?
I do get the contents of the .js.erb file converted to html printed in the Network/Preview section of my dev tools:
$("#contactForm").html("<div class=\"modal fade\" id=\"contactForm\">\n <div class=\"modal-dialog\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n ...
I've got the link_to call:
<%= link_to 'Contact', contact_form_path, {:remote => true, 'data_toggle' => "modal", 'data-target' => '#contactForm'} %>
ContactsController method:
def contact_form
#contact = Contact.new
respond_to do |format|
format.js
end
end
routes.rb
get "contacts/contact_form" => 'contacts#contact_form', :as => :contact_form
contact_form.js.erb:
$("#contactForm").html("<%= escape_javascript(render(:partial => 'contacts/contact_form') )%>");
contacts/contact_forml.html.erb
<div class="modal fade" id="contactForm">
<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">send me a message</h4>
</div>
<div class="modal-body">
<% if flash[:notice] %>
<p class='notice'><%=h flash[:notice] %></p>
<% end %>
<%= form_for(#contact) do |f| %>
<%= f.text_field :name, :placeholder => "first name" %>
<%= f.text_field :email, :placeholder => "email" %>
<%= f.text_area :message, :placeholder => "your message..."%>
<div class="actions">
<%= f.submit :value => "Send Feedback", :class => "btn" %>
</div>
<% end %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Thanks.
You just forgot to call the modal to show the modal. And modal partial should be rendered into wrapper div, so contact_form.js.erb should look like this:
$("#modal-div").html("<%= escape_javascript(render(:partial => 'contacts/contact_form') )%>");
$("#contactForm").modal();
And the view where you are adding modal should have empty div element
<div id="modal-div"></div>

Resources