How to use same Partial for multiple resources? - ruby-on-rails

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

Related

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

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?' } %>

.html.erb set div doesn't work correctly

I just created a scaffold in rails and list all stories in index page, and _stories.html.erb is partial which was rendered in index.html.erb
I want each story div has a red background for example:
.storyCell{
background-color:red;
height:100px;
}
_stories.html.erb
<tbody>
<% #stories.each do |story| %>
<div class="storyCell">
<tr>
<td><%= story.content %></td>
<td><%= story.finished %></td>
<td><%= link_to 'Show', story %></td>
<td><%= link_to 'Edit', edit_story_path(story) %></td>
<td><%= link_to 'Destroy', story, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
</div>
<% end %>
</tbody>
But the result is the red div all in top of the story model properties. Thank you!
This is invalid html. You can't have a div inside a tbody. Remove your div, and just put the class directly on the table row:
<tr class="storyCell">
What's happening here is that the browser is trying to do the best it can to render the invalid html, and so it pulls the div out (which it nows is not allowed inside the table) and renders it above the table instead.
You can give the class to <tbody> like this:
<tbody class="storyCell">
Here is the w3schools example you can look at: http://www.w3schools.com/tags/tryit.asp?filename=tryhtml_tbody
.You can't insert div in table elements as it will render in correct html output.

I am Getting the error undefined method `empty?' for nil:NilClass

I am working on a super simple newsletter application, and I'm confused about this error. Why is there a nil class? I am only asking it to render, so why cant I put a redirect_to where the render call is?.
<% if admin_signed_in? %>
<p id="notice"><%= notice %></p>
<h1>Subscribedusers</h1>
<table>
<thead>
<tr>
<th>Email</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #subscribedusers.each do |subscribeduser| %>
<tr>
<td><%= subscribeduser.email %></td>
<td><%= link_to 'Show', subscribeduser %></td>
<td><%= link_to 'Edit', edit_subscribeduser_path(subscribeduser) %></td>
<td><%= link_to 'Destroy', subscribeduser, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Subscribeduser', new_subscribeduser_path %>
<% else %>
<%= render '/' %>
<% end %>
Why does this part of the code <%= render '/' %> trigger an undefined method 'empty?' for nil:NilClass error?
Since your desire is to return the user to the home page, instead of
render '/'
you should use
redirect_to root_path
The difference is render prepares the output to be displayed as the result of the current request and redirect_to commands user's browser to make a new request at specified url.
While it can be possible to render the contents of your home page in an arbitrary action, this is rarely desirable. One downside is the page url would not automatically update to your site's root in the browser's address line.
As a side note, render '/' is not a correct syntax. render generally accepts a hash of options and not a string.
Why do you have an <% else %> clause without any conditional loops? And what are you trying to call with <% render '/' %>? Are you trying to call the index page? If so, you can specify by saying <% render "index" %> .
So you don't need if and else block in view side for page redirect to root path.
From your controller's whatever action you need following code.
if admin_signed_in?
redirect_to root_path
end
also remove if and else block from view.

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