Sortable table columns based on hash & key array - ruby-on-rails

I would like to create sortable columns for my table which tabulates data based on hashes. By following http://railscasts.com/episodes/228-sortable-table-columns?view=asciicast. From what I understand, order method would only work sorting out a Model. What's the best way of sorting out columns for such tables. I have 29 similar tables as mentioned. My codes are as below :-
admins_controller.rb
class AdminsController < ApplicationController
array =[]
User.each do |user|
company_name = Company.find(user.company_id).name
array.push(company_name)
end
company = array.inject(Hash.new(0)) { |h, e| h[e] += 1 ; h }
end
Results of the above the above query would look like this :-
array = [["3M", 4], ["A.P. Møller-Mærsk Group", 10], ["ABB", 14], ["Abbott Laboratories", 12]]
On views :-
admins.html.erb
<table class="table">
<tr>
<th><%= link_to "Company", remote: true, :sort => "hash" %></th>
<th><%= link_to "Value", remote: true, :sort => "key" %></th>
<th><%= link_to "Percentage", remote: true, :sort => "Percentage" %></th>
</tr>
<% if #mentors.try(:any?) %>
<% #mentors.each do |key, value| %>
<tr>
<td><%= key %></td>
<td><%= value %> </td>
<td><%= ((value.to_f/#total_co.to_f).to_f * 100 ).round(2)%> </td>
</tr>
<% end %>
<% else %>
<td> nil </td>
<td> nil </td>
<td> nil </td>
<% end %>
</table>

You could go for a JavaScript / jQuery solution like http://tablesorter.com/docs/
This would allow for sorting in frontend and you would not need to adjust the backend.
If you want to have a backend solution, you could go for sorting by column index. A simple solution would be something like this:
Controller:
class AdminsController < ApplicationController
def index
array =[]
User.each do |user|
company_name = Company.find(user.company_id).name
array.push(company_name)
end
company = array.inject(Hash.new(0)) { |h, e| h[e] += 1 ; h }
sort_column = params.fetch(:sort, 0).to_i
company.sort! { |a, b| a[sort_column] <=> b[sort_column] }
end
end
View:
<table class="table">
<tr>
<th><%= link_to "Company", remote: true, :sort => 0 %></th>
<th><%= link_to "Value", remote: true, :sort => 1 %></th>
<th><%= link_to "Percentage", remote: true, :sort => 1 %></th>
</tr>
<% if #mentors.try(:any?) %>
<% #mentors.each do |key, value| %>
<tr>
<td><%= key %></td>
<td><%= value %> </td>
<td><%= ((value.to_f/#total_co.to_f).to_f * 100 ).round(2)%> </td>
</tr>
<% end %>
<% else %>
<td> nil </td>
<td> nil </td>
<td> nil </td>
<% end %>
</table>
For reverting sort order, you would need to also pass a direction state and probably reverse order.

Related

Rails: Having trouble adding sorting to a column on a view page

I'm trying to add sorting to these columns using an existing application helper. I'd like to add the ability to add sorting to the "status" and "name" columns, but I cannot get it to function. The links appear but the sorting doesn't happen. I've been toying with this for days and now I'm hoping someone can help me get on track.
The application helper:
def sortable(column, title = nil)
title ||= column.titleize
css_class = column == sort_column ? "current #{sort_direction}" : nil
direction = column == sort_column && sort_direction == "asc" ? "desc" : "asc"
link_to title, request.parameters.merge({ sort: column, direction: direction, page: nil }), { class: css_class }
end
def sort_params(column, direction)
allowed = %i[
search tag_id tag_name
utf8
filter_tag_id
direction sort commit
]
params.permit(allowed).merge(sort: column, direction: direction)
end
end
(The rendered link is Status)
Show:
<table class="table1">
<thead class="thead1">
<tr class="tr1">
<th class="th1">Number</th>
<th class="th1"><%= sortable "name", "Name" %></th>
<th class="th1"><%= sortable "status", "Status" %></th>
<th class="th1">Time</th>
</tr>
</thead>
<tbody class="tbody1">
<% #uniq_contacts.include?(nil) ? #uniq_contacts : #uniq_contacts.uniq! %>
<% #uniq_contacts.each do |contact|%>
<tr class="tr1">
<td class="td1">
<% if contact.blank? %>
<p class="font-italic mb-0">Deleted</p>
<% else %>
<%= Contact.to_us contact.number%>
<% end %>
</td>
<td class="td1">
<% if contact.blank? %>
<p class="font-italic mb-0">Deleted</p>
<% else %>
<%= contact.first_name %>
<%= contact.last_name %>
<% end %>
</td>
<td class="td1" id="contact-id-<%= contact&.id %>">
<%= #broadcast.messages.find_by(contact: contact)&.status %>
</td>
<td class="td1">
<% if #broadcast.updated_at > Time.now - 1.year %>
<%= #broadcast.updated_at.strftime('%b %e %l:%M %P') %>
<% else %>
<%= #broadcast.updated_at.strftime('%b %e, %Y %l:% %P') %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
Controller method:
def sort_column
#broadcast.messages.column_names.include?(params[:sort]) ? params[:sort] : "status"
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
end
schema:
Check your sort_column method:
#broadcast.messages.column_names
Does it include name? If not, there's your problem.

Kaminari - can't get dynamically selected per page limit

Here is my code.
Controller:
def bisac_main_counts
q = "
MATCH (b:Bisac) WHERE (b.bisac_code =~ '.*000000')
WITH b, size((b)<-[:INCLUDED_IN]-()) as wokas_count
RETURN b.bisac_code as bisac_code, b.bisac_value as bisac_value, wokas_count
ORDER BY b.bisac_code
;"
#result = Neo4j::Session.current.query(q).to_a
if params[:limit]
#result = Kaminari.paginate_array(#result).page(params[:page]).per(params[:limit])
else
#result = Kaminari.paginate_array(#result).page(params[:page])
end
end
View:
<%= render 'home/main_links' %>
<%= paginate #result %>
<%= render 'bisac_counts' %>
<%= form_tag bisac_main_counts_path, method: :get do %>
<%= select_tag :limit, options_for_select([5, 10, 15, 20, 25], selected: params[:limit] || 25) %>
<% end %>
Partial:
<table>
<thead>
<tr>
<th>Bisac Code</th>
<th>Bisac Value</th>
<th>Wokas Count</th>
</tr>
</thead>
<tbody>
<% #result.each do |record| %>
<tr>
<td><%= record.bisac_code %></td>
<td><%= record.bisac_value%></td>
<td><%= record.wokas_count %></td>
</tr>
<% end %>
</tbody>
</table>
Apparently params[:limit] is not set in the view. It is always null. Changing pages is working.
What I am doing wrong here?
What was missing was a form for changing the limit and a way to trigger it.
Here are the changes (in the view only):
<%= render 'home/main_links' %>
<%= paginate #result %>
<%= render 'bisac_counts' %>
<%= form_tag bisac_main_counts_path, method: :get, id: 'limit_form' do %>
<%= select_tag :limit, options_for_select([5, 10, 15, 20, 25], selected: params[:limit] || 10) %>
<% end %>
<script type="text/javascript" >
$(function(){
$('#limit').change(
function() {
$('#limit_form').submit();
});
});
</script>

Can not access collection object's value in erb file - has_many relationship - ruby on rails

In my application, there are two classes , which have 'has_many' relationship.
And from that design, I can fetch object from my controller(*_controler.rb) and can pass successfully to my view (*.html.erb)
But on view part(*.html.erb) i can not access object's collection class...
I got following exception:
ActionView::TemplateError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.inject) on line #31 of app/views/student/_populate.html.erb:
Model Classes:
class Student < ActiveRecord::Base
has_many :Subject, :class_name=>"Subject"
attr_accessible :first_name, :middle_name, :last_name,
self.table_name="students"
set_primary_key :id
blahblah
end
class Subject < ActiveRecord::Base
belongs_to :Student, :foreign_key=>'student_id'
attr_accessible :student_id, :name
self.table_name="subjects"
blahblah
end
Controller:
class StudentController < ApplicationController
require "student.rb"
def populate
#pos=0
filter_query = ''
if !params[:firstName].blank?
filter_query +=" first_name='" + params[:firstName].to_s + "' and"
end
if filter_query !=''
filter_query= filter_query[0..filter_query.length-4]
#stuData= Student.find(:all, :conditions=>filter_query)
end
end
View:
populate.html.erb
<div class="header">
<div class="heading" style="float:left;width:900px;">
<% form_tag(:controller=>"student", :action=>"populate") do %>
<table>
<tr>
<td width="10"> <label> First Name:</label> </td>
<td width="40"> <%= text_field_tag('firstName') %> </td>
</tr>
</table>
<input name="submitFormName" class="form_submit" type="submit" value="Search" />
<% end %>
<div height="10"> </div>
</div>
</div>
<div class="students" style="float:left;width:1330px;">
<% if !#stuData.blank? %>
size = <%= #stuData.size %>
<% if !#stuData.nil? %>
<%= render :partial=>'populate' , :locals=>{:stuData => #stuData} %>
<% end %>
<% else %>
<div>Not found...</div>
<% end %>
</div>
_populate.html.erb
<div style="overflow-y:auto;overflow-x:scroll;">
<table >
<thead>
<th>Id</th>
<th>First Name</th>
<th>Middle Name </th>
<th>Last Name</th>
<th>Subject Name</th>
</thead>
<% stuData.each do |item| %>
<tr>
<td id="studentId"> <%= item.id %> </td>
<td id="firstNameId"> <%= item.promotion_code %> </td>
<td id="middleNameId"> </td>
<td id="lastNameId"> </td>
<td id="cityId">
<% #var1 = item.Subject %>
<% if #var1.nil? %>
<% #var1.each do |pc| %>
<%= pc.name %>
<% end %>
<% end %>
</td>
</tr>
<% end %>
</table>
</div>
I have crossed check on console:
#student = Student.find(144)
=> #<Student id: 4, first_name: "ABC", middle_name: "DEF", last_name: "GHI">
>>
?> #isNullCheck = #student.Subject.nil?
=> false
>>
?> #subList = #student.Subject
=> [#<Subject id: 5, student_id: 4, name: "Maths">, #<Subject id: 6, student_id: 4, name: "English"> ]
>>
?> #StuSub1 = #student.Subject[0]
=> #<Subject id: 5, student_id: 4, name: "Maths">
>>
?> #StuSub2 = #student.Subject[1]
=> #<Subject id: 6, student_id: 4, name: "English">
==
?> #StuSub3 = #student.Subject[2]
=> nil
>>
>> #StuSubValue1 = #student.Subject[0].value
=> Maths
>>
>> #StuSubValue2 = #student.Subject[0].value
=> English
>>
Problem:
When i will search any student details from the page(populate.html.erb), my controller will fetch the data and passed the object (#stuData) to the template(_populate.html.erb).
Template(_populate.html.erb) can print student's data.
But can not print student's subject's name. (As student has many subjects)
I have googled many things....
i think there is nothing wrong in model's design and controller part....
but i think problem might be with
page rendering or
local parameters passing to template or
collection parameter passing to template...
but i am not sure....
can any one help me in this???
Thanks in advance,
Your relationships are set up incorrectly. Variable names cannot begin with a capital letter. This article may help.
Set them up without using capitals and use plurals instead - like so:
has_many :subjects and belongs_to :student
and make sure you propagate changes through your views

Pagination not working correctly in rails

I am trying to use will_paginate for a list of items I want to display.
There is a form with drop down selections to fetch objects by status.
This is my controller
def list
#person = Person.find_by_id(session[:person_id])
params[:status] = params[:redirect_status] if params.has_key?('redirect_status')
#statuses = Peptide.statuses
#status = 'Not Ordered'
#status = params[:status] if params[:status] != nil || params[:status] == ''
#peptides = Peptide.find(:all, :conditions => ['status = ?', #status]).paginate(:per_page => 30, :page => params[:page])
if Peptide.count.zero?
flash[:notice] = "There are not any peptides entered"
redirect_to :action => 'new'
end#if zero
end
This is in the view
<form action="/peptide/create_spreadsheet_of_not_ordered" enctype="multipart/form-data" method="post">
<table class="sortable" cellpading="5" cellspacing="2" width="100">
<tr class= "header-line">
<th>SS</th>
<th>Status</th>
<th>Peptide</th>
<th>Gene</th>
<th>Submitter</th>
<th>Created</th>
<th>Updated</th>
<th>Sequence</th>
<th>Modification</th>
<th>Vendor</th>
</tr>
<% for #peptide in #peptides.reverse %>
<tr valign = "top" class= "<%= cycle('color_one', 'color_two') %>">
<!--an error here during development likely indicates that the people table has not be repopulated or
that no submitter primer is present for a primer-->
<td sorttable_customkey = 0 > <%=check_box_tag "box[]", #peptide.id %>
<td><%= #peptide.status%></td>
<td class><%= link_to #peptide.name, :action => :report, :id => #peptide.id %></td>
<td><%= gene_links(#peptide.genes) rescue 'Error'%></td>
<td><%= #peptide.submitter.name rescue "" %></td>
<td <%= sorttable_customkey_from_date(#peptide.created_at)%> >
<%= #peptide.created_at.strftime("%b %d %Y") rescue "Unknown"%>
</td>
<td <%= sorttable_customkey_from_date(#peptide.updated_at)%> >
<%= #peptide.updated_at.strftime("%b %d %Y") rescue "Unknown"%>
</td>
<td><%= #peptide.sequence%></td>
<td><%= #peptide.modifications%></td>
<td><%= #peptide.vendor%></td>
<%= buttons() %>
</tr>
<%end%>
<%= will_paginate #peptides %>
</table>
<br>
<%= submit_tag "Create Spreadsheet"%>
The default list is grouped by status ordered.
however when I select any other status and submit the form the pagination links take me back to the default status.
Please help me resolve this issue.
Thanks
Without seeing the view, it sounds like you need to add the current params as an argument to the links for the other statuses...
Update
Try adding the params to your status link:
<%= link_to #peptide.name, peptide_path(#peptide, params), :action => :report, :id => #peptide.id %>
The documentation is here.

Setting a params hash to a variable within the controller (rails)

I'm very new to rails and have this fairly basic question:
I have a form that takes in an array:
<td><%= fields_for "days" do |form| %>
M: <%= form.check_box "", {}, 'M', '' %>
T: <%= form.check_box "", {}, 'T', '' %>
W: <%= form.check_box "", {}, 'W', '' %>
Th: <%= form.check_box "", {}, 'Th', '' %>
F: <%= form.check_box "", {}, 'F', '' %>
<% end %>
This should be accessible through params[:days]. How can I assign params[:days] to a variable within the controller? #days is not correct here, right? (There's no Days object, so there's no instance of that object). What should go in the [correct_variable] slot below?
[correct_variable] = params[:days]
Thanks!
In response to comments:
I tried using #days, but for some reason it wouldn't get called where I'd like it to. In particular, I'd like to pass it to my Search model:
class Search < ActiveRecord::Base
attr_accessible :name, :day, :units, :instructor
def courses
#courses ||= find_courses
end
private
def find_courses
Course.find(:all, :conditions => conditions)
end
def day_conditions
["courses.day LIKE ?", "%"+ #days.join("%")+"%"]
end
I first instantiate #days in my courses controller (which is connected, through the index method, to a partial that uses an instance of the Search object.
More code:
From courses/index.html.erb:
<% if #search.save %>
<div id = "results_scroll">
<%= render :partial => 'searches/search_results' %>
</div>
<% else %>
From search_results partial:
<% "Search" %>
<table>
<tr>
<th align="left" width="25%"><%= 'Name' %></th>
<th align="left" width="10%"><%= 'Number' %></th>
<th align="left" width="20%"><%= 'Instructor' %></th>
<th align="left" width="10%"><%= 'Room' %></th>
<th align="left" width="5%"><%= 'Day' %></th>
<th align="left" width="5%"><%= 'Units' %></th>
<th align="left" width="15%"><%= 'Time' %></th>
<th align="left" width="10%"><%= 'Limitations' %></th>
</tr>
<%= render :partial => #search_show.courses %>
</table>
From the courses controller (this has the #search_show variable).
def index
#courses = Course.order(sort_column + " " + sort_direction)
#search = Search.new
#search_show = Search.last
#title = "List"
#days = params[:days]
Finally, the _course.html.erb partial:
<tr>
<td><%= course.name %></td>
<td><%= course.number %></td>
<td><%= course.instructor %></td>
<td><%= course.room %></td>
<td><%= course.day %></td>
<td><%= course.units %></td>
<td><%= course.time %></td>
<td><%= course.limitations %></td>
<td><%= link_to 'Show', course %></td>
</tr>
This is not really an answer, but there is some problems with how you are trying to access your #days variable you set in the controller.
# your controller
...
def index
...
#days = params[:days]
# your model
...
private
def day_conditions
["courses.day LIKE ?", "%"+ #days.join("%")+"%"]
end
The #days, in your model, you are calling is not going to access the #days in your controller. Each #days belongs to their respective instances.
You should find a method of sending the #days from your controller into your models, instead of using global variables.
Solved the problem by using a $days global variable instead of #days.

Resources