bootstrap-confiirmation doesn't handle method :delete in rails app - ruby-on-rails

I'm trying to use bootstrap-confirmation for an index view with datatables and a column for deleting the row item. I have it working without the confirmation, or with the default confirmation, but not with bootstrap-confirmation, it sends me to the show method, rather than the delete method of the controller. Its like it doesnt see the method: :delete
Here is the way I'm calling it in the index view. The popup confirmation displays, but when I click ok, it sends me to the show page.
<td><%= link_to '<i class="fa fa-trash-o fa-lg"></i>'.html_safe, role_path(id: role.id), method: :delete, :'data-toggle' => 'confirmation', :'data-copy-Attributes' => 'href data-method'%></td>
This following works (without confirmation), so I know my routes, controller action, etc work.
<td><%= link_to '<i class="fa fa-trash-o fa-lg"></i>'.html_safe, role_path(id: role.id), method: :delete, %></td>
Any ideas?
Heres my view:
<h1> Roles</h1>
</br>
<table width="100%" class="table table-striped table-bordered table-hover" id="roles-table">
<thead>
<tr>
<th>Roles</th>
<th>User Count</th>
<th>Delete Role</th>
</tr>
</thead>
<tbody>
<% #roles.each do |role| %>
<tr>
<td><%= role.name %>
<td><%= role.users.count %></td>
<% if (role.users.count == 0) %>
<!--td><%= link_to '<i class="fa fa-trash-o fa-lg"></i>'.html_safe, role_path(id: role.id), method: :delete, :data => {:confirm => 'Are you sure?'}%></td-->
<td><%= link_to '<i class="fa fa-trash-o fa-lg"></i>'.html_safe, role_path(id: role.id), method: :delete, :'data-toggle' => 'confirmation', :'data-copy-Attributes' => 'href data-method'%></td>
<% else %><
<td></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to "Add Role", new_role_path, class: "btn btn-success"%>

I couldn't make the library work because it doesn't provide a way to edit the popup html it generates, so, it also took for me the link to the show method and no way to delete it.
So what I did was to create a route to delete the resource that expects to receive the id from the resource and a value in the params for delete:
get 'role/:id/:delete', to: 'role#show', as: 'show_role'
Then in your controller you can check if you're receving a delete param, in order to separate between show and destroy, if you receive it, then you destroy it and redirects to the roles_url:
def show
#role = Role.find(params[:id])
if params[:delete]
#role.destroy
redirect_to roles_url
end
end
Then in your view you can use a link_to helper, passing the route created previously passing the resource and a value for the delete param, adding the data attributes Bootstrap Confirmation needs to make it work:
<%= link_to 'Destroy', show_role_path(role, delete: true), data: { toggle: 'confirmation', title: 'Delete it?' } %>

Related

How to use same Partial for multiple resources?

I'm using tables to list recorded from database in index templates, And as usual the last three table cells are used for the links of Show, Edit and Destroy the Object.
../users/index.html.erb
<table>
...
<% #users.each do |user| %>
<tr>
...
<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>
Anyway, I was trying to replace those links text to some Bootstrap's glyph icons, And I succeeded but It got messy so I thought it better to put it in a partial with a variable to be shared with all index templates that use the same table layout.
../shared/_editLinks.html.erb
<td>
<%= link_to dist do %>
<span class="glyphicon glyphicon-eye-open"></span>
<% end %>
</td>
<td>
<%= link_to send("edit_#{dist}_path(#{dist})") do %>
<span class="glyphicon glyphicon-edit"></span>
<% end %>
</td>
<td>
<%= link_to dist, method: :delete, data: { confirm: 'Are you sure?' } do %>
<span class="glyphicon glyphicon-remove"></span>
<% end %>
</td>
Then To use the following code line to render the partial in the index table. Passing the resource name as variable.
<%= render 'editLinks', dist: user %>
Then the first and the last links seems to work fine but I got this error around the middle -Edit- link.
undefined method `edit_user_path(#<User:0x007f611ab015a8>)' for #<#<Class:0x007f611a7064d0>:0x007f611ab143b0>
Can you tell me what causes this error and how to get it work?
The lines causing errors are because you're trying to treat an object like a string.
Because the _path helpers are typically snake_case, you can use the underscore method on the object's class name like so:
<%= link_to send("edit_#{dist.class.name.underscore}_path", dist) do %>
As pointed out by Deepak, you also can be providing the dist object as the second argument to send. Otherwise, you'll end up with a similar error because you'd again be treating the object as a value that can be coerced into a string.
Pass param to route/method separated by comma
<%= link_to send("edit_#{dist.class.name.underscore}_path", dist) do %>
send method syntax

My nested relationship is switching the ids of the models

I'm trying to delete an attachment from my rails project. I have the attachment nested under test_suite. When I hit the attachment delete button, the generated url switch the ids of attachment and test_suite. ex. the url should be localhost:3000/test_suites/3/attachments/11 but I'm getting localhost:3000/test_suites/11/attachmnts/3 and I get the error that attachment id=3 doesn't exist which is right because it should be attachment id = 11
Here is how I set it up.
routes.rb:
resources :test_suites do
resources :attachmnts, :only => [:create, :new, :destroy]
end
model/test_suite.rb:
class TestSuite < ApplicationRecord
has_many :attachemnts
end
model/attachment.rb:
class Attachment < ApplicationRecord
belongs_to :test_suite
has_attached_file :attach
validates_attachment_content_type :attach, :content_type => ["text/xml", "text/plain","text/html"]
end
I'm creating new attachment in test_suite show.The attachment will have a test_suite_id attribute.
test_suites_controller.rb:
def show
# create a variable pammed to test_suite with id passed from previous page
#test_suite = TestSuite.find(params[:id])
#attachment = Attachment.new
#attachment.test_suite_id = #test_suite.id
end
test_suite/show.html.erb:
<table class="table table-hover table-responsive">
<thead>
<tr>
<th>File Name</th>
<th>File Type</th>
<th>File Size</th>
<th>Created At</th>
<th></th>
</tr>
</thead>
<tbody>
<%= render partial: 'attachment', locals: {test_suite: #test_suite} %>
</tbody>
</table>
attachments/_attachment.html.erb:
<% test_suite.attachemnts.each do |attachment| %>
<tr>
<td> <%=attachment.attach_file_name %> </td>
<% if attachment.attach_content_type == 'text/plain'%>
<td>txt</td>
<% else %>
<td><%= attchement.attach_content_type.split('/').last %></td>
<% end %>
<td><%= attachement.attach_file_size %></td>
<td><%= attachement.created_at %></td>
<td><%= link_to '<span class="glyphicon glyphicon-remove-sign"></span>'.html_safe, test_suite_attachment_path(attachment),class:"btn btn-lg", method: :delete, data: {confirm: "Are you sure you want to delete the file?"} %>
</td>
</tr>
<% end %>
My rails routes outputs:
Prefix Verb URI Pattern Controller#Action
root GET / test_suites#index
test_suite_attachements POST /test_suites/:test_suite_id/attachements(.:format) attachements#create
new_test_suite_attachement GET /test_suites/:test_suite_id/attachements/new(.:format) attachements#new
test_suite_attachement DELETE /test_suites/:test_suite_id/attachements/:id(.:format) attachements#destroy
test_suites GET /test_suites(.:format) test_suites#index
POST /test_suites(.:format) test_suites#create
new_test_suite GET /test_suites/new(.:format) test_suites#new
edit_test_suite GET /test_suites/:id/edit(.:format) test_suites#edit
test_suite GET /test_suites/:id(.:format) test_suites#show
PATCH /test_suites/:id(.:format) test_suites#update
PUT /test_suites/:id(.:format) test_suites#update
DELETE /test_suites/:id(.:format) test_suites#destroy
When you're dealing with a nested object, you need the ids of both the parent and child object to perform show/edit/update/destroy operations. The issue is because you're not passing the test_suite object to test_suite_attachment_path helper. Modify your link to
<%= link_to '<span class="glyphicon glyphicon-remove-sign"></span>'.html_safe, test_suite_attachement_path(test_suite, attachment),class:"btn btn-lg", method: :delete, data: {confirm: "Are you sure you want to delete the file?"} %>
You can also pass an array of the parent and child objects instead of using the path helper.
#[test_suite, attachment]
<%= link_to '<span class="glyphicon glyphicon-remove-sign"></span>'.html_safe, [test_suite, attachment], class:"btn btn-lg", method: :delete, data: {confirm: "Are you sure you want to delete the file?"} %>
Please use a consistent spelling of 'attachments'. You're using a different version in every place.

Can't use method and confirm attributes on custom helper to create link with icon

I've created the following custom helpers to add links with icons:
module ApplicationHelper
def link_with_icon_to(label, icon, url, data = {}, method = nil)
render "shared/link_with_icon", label: label, icon: icon, url: url, data: data, method: method
end
def edit_link(url)
link_with_icon_to 'Editar', 'fa fa-pencil', url
end
def remove_link(url)
link_with_icon_to 'Excluir', 'fa fa-trash', url, method: :delete, data: { confirm: 'Are you sure?' }
end
end
_link_with_icon.html.erb
<%= link_to url, method: method, data: data do %>
<i class="<%= icon %>" /><span><%= label.html_safe %></span>
<% end %>
And I'm using them this way:
<% #insurance_companies.each do |insurance_company| %>
<tr>
<td><%= insurance_company.name %></td>
<td><%= insurance_company.cnpj %></td>
<td><%= edit_link edit_insurance_company_path(insurance_company) %></td>
</td>
<td><%= remove_link insurance_company %></td>
</tr>
<% end %>
However the remove_link helper is not working. The confirmation is not displayed and the data is not deleted.
What is wrong with my helper?
This is possible because you're not passing down the additional options(data and method) to the link_to.
Can't immediately confirm/verify this, but I think a way you can work around this is:
def link_with_icon_to(label, icon, url, opts = {})
render "shared/link_with_icon", label: label, icon: icon, url: url, opts: opts
# there definitely better ways of handling this, but can't think of another right now
end
# _link_with_icon.html.erb
# spread the opts hash here. the opts hash could be {data: {element: 'whatever'}, method: :delete} etc.
<%= link_to url, **opts do %>
<i class="<%= icon %>" /><span><%= label.html_safe %></span>
<% end %>

Input a check_box_tag value into a Rails model from outside the main form_for

I'm developing a marketplace app. Sellers list products to sell. I want to create a featured listings widget. So I created an admin page where I can see all listed items. Then added a check box for "featured" on the admin page so I can select which items I want to be featured.
Then I did a migration to add 'featured' as a boolean field in my listing model.
How do I insert a form_for in my admin page html below so the check box value is input as 1(or true) into the listing model?
Once I get the check box value to the model, I can add the method to my controller to filter for featured listings.
<div class="center">
<h2>Admin area: All Listings</h2>
</div>
<table class="table table-striped table-bordered">
<tr>
<th>Image</th>
<th>Seller</th>
<th>Name</th>
<th>Price</th>
<th>Featured</th>
<th>Action</th>
</tr>
<% #listings.each do |listing| %>
<tr>
<td><%= image_tag listing.image.url(:thumb) %></td>
<td><%= listing.userid %></td>
<td><%= listing.name %></td>
<td><%= number_to_currency(listing.price) %></td>
<td><%= check_box_tag(:featured) %></td>
<td>
<div class="btn-group">
<button type="button" class="btn btn-primary btn-xs dropdown-toggle" data-toggle="dropdown">
Action <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><%= link_to "View", listing, class: "btn btn-link" %></li>
<li><%= link_to "Edit", edit_listing_path(listing), class: "btn btn-link" %></li>
<li><%= link_to 'Delete', listing, method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-link" %></li>
</ul>
</div>
</td>
</tr>
<% end %>
</table>
Typically I would implement this via JS/jQuery and a nice post/get request back to server, it feels like this would be a better UX approach. However, I've also added a rough idea for the form approach too.
JS Approach
$(document).ready(function(){
$("input[type=checkbox]").click(function(){
$.get('/listings/admin/feature_listing/'+$(this).val(), function(data){
alert("Listing has been toggled!");
});
});
});
Don't forget to update your routes file for this.
Form Approach
You'd basically have to break out a new form and seperate the :featured attribute out.
<%= form_tag listing_featured_path, method: :get do %>
<td><%= check_box_tag "listing_featured", "Featured", :value=>listing.featured %></td>
<td><%= submit_tag "Submit" %></td>
<% end %>
You will then need to create a new seperate action in your controller to pick up that custom param and also update routes.
You can do it through javascript, there are many methods but a simple solution would be in your form:
<%= f.hidden_field :featured, class: 'hidden' %>
In your checkbox:
<%= check_box_tag(:featured_checkbox), data: {id: listing.id} %> #or whatever
and append those values this way (jquery):
$(function(){
$("input[type=checkbox]").click(function(){
$('.hidden').value($(this).data('id'))
});
});
Disclaimer: not tested but it should work.
EDIT:
Make sure that the jquery snippet is executed on document ready. See above edited.
If you need to parse the value of the checkbox, the data should be saved even if it's not, you could do it through cookies. If the record is saved:
<%= check_box_tag(:featured_checkbox), value: listing.featured, data: {id: listing.id} %>
Anyway, it's more important to understand the procedure than make this code work (as is).

Link_to another view ruby on rails

I am trying to use the link_to feature to link one view to another.
The view i am calling link_to is app/views/instructors/show.html.erb and that snippet of code looks like this (namely, the second to last line of it)
<% provide(:title, #instructor.login) %>
<% courses = Course.where(:instructor_ID => #instructor.id) %>
<div class="span2">
<h1 align=center ><%= #instructor.login %></h1>
<%= link_to "Add course", new_course_path(:instructor_ID\
=> #instructor.id), :class => "btn" %>
<br>
<br>
<%= link_to "Remove course", delete_course_path(courses), :class => "btn"%>
</div>
The view I am trying to link to is is app/views/courses/show_all.html.erb and looks like this:
<% #courses.each do |course| %>
<tr>
<td><%= course.course_name %></td>
<td><%= course.instructor_ID %></td>
<td><%= link_to 'Show', course %></td>
<td><%= link_to 'Edit', edit_course_path(course) %></td>
<td><%= link_to 'Destroy', course, :method => :delete, :data => { :confirm => 'Are you sure?' } %></td>
</tr>
delete_course_path routes to app/views/courses/show_all.html.erb shown above. When I try the code above, I get the following error:
undefined method `each' for nil:NilClass
At this line:
<% #courses.each do |course| %>
Any ideas what i'm missing in my link_to?
In your show_all action, you should define a #courses instance variables. This is
<% courses = Course.where(:instructor_ID => #instructor.id) %>
not passed to show_all.html.erb.
An instance variables is a variable passed from action of controller to the view corresponding.
I suppose when you show page of instructor, your route will like this: /instructors/:id, so maybe in your show_all action of instructor controller, you need something like:
def show_all
#courses = Course.where(instructor_ID: params[:id])
render 'courses/show_all'
end
This means that #courses is nil. Did you set it in your show_all action of your controller? E.g.
def show_all
#courses = Course.all
end
Also, in your show view, you set courses to a collection of Course objects, but your "Remove course" link looks like you only want to delete one course. Why do you use the delete_course route to link to your show_all view?

Resources