Populating a table column-wise - ruby-on-rails

I am implementing a HTML table in my Rails application. Currently, I have in my view:
<table>
<thead>
<tr>
<% #electives.each do |elective| %>
<th><%= elective.name %></th>
<% end %>
</tr>
</thead>
<tbody>
</tbody>
</table>
Elective and Course are models in my application. I have created a has_and_belongs_to_many association between them, thereby creating a courses_electives table.
At present, my webpage looks like:
What I want to do next is display all the courses related to each elective under the elective name.
I think I can achieve this using:
<% #electives.each do |elective| %>
<% elective.courses.each do |course| %>
<%= course.name %>
<% end %>
<% end %>
The problem I am facing with this approach is that it doesn't allow me to build my table vertically. I can create new <td> elements inside the above loops, but that will render data horizontally. That is, courses which belong to Software Engineering Elective A will end up being <td> entries in Software Engineering Elective B and so on.
What I want is:
How can I achieve this? Any help is very much appreciated. Thank you.

Sliim's suggestion is good. But what you're battling here is the limitations of html concepts that are over 30 years old. We now have grid and flexbox, which are much better ways to arrange elements on the page than tables. So how would this look in modern html? (well, I'll use haml b/c it's easier to see the structure, and b/c I'm lazy and haml rocks)
#electives
- #electives.each do |elective|
.elective
.name= elective.name
- elective.courses.each do |course|
.course= course.name
This just gives you a bunch of divs, but with a little css magic we can create the arrangement that you want:
#electives {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.elective {
display: flex;
flex-direction: column;
}
The grid-template-columns 'auto-fit' declaration adjusts to however many columns you may have, whilst setting minimum and maximum widths. It's described here.
Of course, the flexbox doesn't care that there are different numbers of courses in each elective.

You can use .transpose to flip the columns and the rows.
<% #electives.map(&:courses).transpose.each do |row| %>
<tr>
<% row.each do |course| %>
<td>
<%= course.name %>
</td>
<% end %>
</tr>
<% end %>
Do be careful with nil-s here, because I assume your electives might not have exactly the same amount of courses.

Related

Find associated records through third table association

I have 3 models I am working with and trying to find the most frequent items between two models that are not related, but have a third table that is.
My 3 models are:
Visits (has_many Diagnoses)
Diagnosis (belongs_to Visit)
Prescriptions (belongs_to Visit)
Given a specific diagnosis, I want to know what drug is most commonly prescribed. Since Diagnosis and Prescriptions don't have a direct relationship I am lost. Below is my current code
This gets my top diagnoses
#top_diag = Diagnosiswork.group("diagnosis").order("count_diagnosis_id desc").limit(10).count("diagnosis_id")
This is in my view
<tbody>
<% #top_diag.each do |diagnosis, count| %>
<% top_visits = Diagnosiswork.where(diagnosis_id: diagnosis.id) %>
<% top_prescription = Prescription.where(visit_id: #top_visits) %>
<tr>
<td><%= count %>: <%= diagnosis.id %></td><td><strong><%= diagnosis.name %></strong></td>
<td>
<% top_prescription.each do |prescription| %>
<%= prescription.medicine.full_name %>
<% end %>
</td>
<td><span class="badge badge-success">Active</span></td>
<td>
</td>
</tr>
<% end %>
</tbody>
This gets me a list of drugs, but it is the same list for every diagnosis. My current thought is to get the Visits where these diagnosis are used the most, and then use a query similar to my top_diag that uses a where clause singling out certain visits.
Thanks so much in advance!

How do I extract relevant attribute values from a Rails habtm collection object in my view

I have 2 models:
1) upload
2) date_range
there is an intermediate join table as these models are associated by a many to many relationship thus, each is habtm to the other.
In my view for uploads(index.html.erb) Im trying to show all the date_ranges for a particular upload as follows:
<tr>
<th>File name</th>
<th>Upload Date, Time, Filename</th>
<th>Type</th>
<th>Dates in Upload</th>
<th>Total Rows</th>
<th>Rows Entered in DB</th>
<th>Percentage Completed</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% #uploads.each do |u| %>
<tr>
<td> <%= u.sourcedata_file_name%></td>
<% path_arr = u.f_path.split("\/")%>
<td><%= path_arr[-3..-1]%></td>
<td> <%= u.sourcedata_content_type%></td>
=>> <td> <%= u.date_ranges.inspect%>
<td> <%= u.total_rows%></td>
<td> <%= u.rows_completed%></td>
like so.
This shows up as follows on the browser:
In my "Dates in Upload" column I want to only show some string with dates like this:
"2013-12-25, 2013-12-26" how do I only get these extracted out of the ActiveRecord::Associations::CollectionProxy object as it shows in the image?
Thanks
Use u.date_ranges.pluck(:date_range) to get just the date ranges.
you can then pretty it up with
u.date_ranges.pluck(:date_range).each {|range| puts range}
if you want them in a column.
I see you want them side by side, so it looks like there will only be two because it's a "range" so:
<%= u.date_ranges.pluck(:date_range).first %>, <%= u.date_ranges.pluck(:date_range).last %>
The simplest thing would probably be to add a to_s method in your DateRange model:
def to_s
date_range.to_s
end
And in your view, something like:
<%= u.date_ranges.map {|dr| dr.to_s }.join(', ') %>
However, that's really a bit too much code to put right in the view. Better would be to move that to a helper, or even use a presenter pattern. The 'draper' gem can make this kind of thing very easy, so you can do the same transformation in multiple places in your app, and keep your view template much cleaner.

How to Use Rails will_paginate gem to Divide a Large Table for Print on a Single Page

I am making some printable tables for a client with a Ruby on Rails 3.1 app and need to repeat table headers on each page. Unfortunately, at the moment, WebKit browsers do not support a CSS-based solution.
To solve this issue, I thought I would use the will_paginate gem.
Controller
def
#books = current_library.books.order('books.title ASC')
end
Current View Code
<% #books.each do |b| %>
<table>
<thead><th><%= b.title %></th></thead>
<tbody>
<% b.chapters.each do |chap| %
<td><%= chap.number %> ... <%= chap.name %></td>
<% end %>
</tbody>
</table>
<% end %>
How do I setup the pages and step through each one? In other words, how do I get all the pages of the pagination on one view page?
Alternatively, is there a better approach I should pursue?
You might be better off using Enumerable#each_slice here. It allows you to split a large enumerable object into a series of smaller slices, and then iterate on those slices. It's quite nice for this sort of thing, doesn't require any extra math in your loops, and doesn't require a gem.
Here's an example for a collection with 10 items on a page:
<% #books.each_slice(10) do |slice| %>
<h1>Header Information</h1>
<h2>Awesome</h2>
<% slice.each do |book| %>
<table>
<thead><tr><th><%= book.title %></th></tr></thead>
<tbody>
<% book.chapters.each do |chap| %
<tr><td><%= chap.number %> ... <%= chap.name %></td></tr>
<% end %>
</tbody>
</table>
<% end %>
<p>Some footer information</p>
<% end %>
This approach will only work if you assume that each book record takes about the same amount of space (so you don't end up with oversized or undersized pages), but that would be a problem with will_paginate as well.

Create a sortable table on the client side using calculated data

I have a table that displays a name, and two values corresponding to each name that I have calculated using a loop and a progress bar for each value.
The code looks something like this,
<table>
<thead>
<th>Name</th>
<th>Value1</th>
<th>Value2</th>
</thead>
<tbody>
<% i=0 %>
<% j=0 %>
<% #department.members.each do |members| %>
<td><td><% members.name %><td>
<% members.evals.each do |evals| %>
<% i+=value1 * something %>
<% j+=value2 * something %>
<% end %>
<tr>
<td>
<div class="progress"><div class="bar" style="width: <%= (i*10).round() %>%;"></div></div>
<%= i %>
</td>
<td>
<div class="progress"><div class="bar" style="width: <%= (j*10).round() %>%;"></div></div>
<%= j %>
</td>
<% end %>
</tbody>
</table>
I wish to allow the user to click the heads and sort this information dynamically without changing the page on the client side, as well as create a drop-down menu above the table that allows the user to do the same. "Sort by value2" and "Sort by value1".
I am using bootstrap, so I don't want to use DataTables. Even their bootstrap theme doesn't look like boostrap. I just want a simple sort while preserving my current styling.
Datatable (http://datatables.net/release-datatables/examples/basic_init/zero_config.html)
You would need to sort the table with JavaScript, take a look at sortable table with jQuery.
You can always edit the CSS file to match your layout or to match with bootstrap's layout.

What is the best way to structure a multi-page form to create and edit models in a database?

I'm fairly new to Rails.
What is the best way to design/structure a multi-page form in Rails? I would like the form to create a new record in the database immediately when the first page of the form is submitted, and for each subsequent page of the form to update that record in the database.
The reason I want the record created immediately after the first page is submitted is so that there can be the notion of an unfinished record that the user comes back to later to finish.
Once created, I would like to allow the user to edit any part of the model by going directly to that section.
I know enough Rails where if you guide me with the best way to structure this conceptually, I should be able to figure out the code myself.
Thank you.
I have a multi-step signup process that works this way. I create the record the first time and then the other steps are edit/updates on that record. I use multiple controllers for this; it is a much cleaner approach than trying to cram all the logic into one controller action (although you could use multiple actions from the same controller and it would work just as well, but don't forget to create routes for your custom actions). This approach makes validation more difficult for the data added in steps after the first, but you can always add your own errors by calling errors.add on your model, essentially rolling your own validations. You can also write logic in your sessions controller to direct the user back to the same step in the multi-step form if they return later and have not completed it.
Ryan Bates explains this in one of his Railscasts => MultiSteps Forms
I've inherited a 'multi-page' form along those lines - but it was built for Rails 2.2 and I'm only just adapting the approach for Rails 3.
Essentially we used a tabbed layout with the entire form in one view - although this approach was heavily weighted towards one controller in Rails 2.2 I think it can be broken down better.
The layout meant that each section of the form could be accessed by the tabs - but each tabbed section also had a link_to action to the next section, at the bottom of that section (section A -> section B, for example) that saved the entire form each time you moved onto a new section - I've heavily edited the view just to give an idea but if it's a new form it will only reveal each section after the submit button for each section has been pressed.
<ul id="tabs">
<li>Section A</li>
<li>Section B</li>
<li>Section C</li>
<li>Section D</li>
<li>Section E</li>
<li>Section F</li>
<li>Section G</li>
<li>Section H</li>
<li>Section I</li>
<li>Section J</li>
</ul>
<%=hidden_field_tag 'active_fabtabulous_tab'%>
<% form_for(#detail) do |f| %>
<%= f.error_messages %>
<div class="panel" id="SectionA">
<b><u>Section A: Questionnaire Details</u></b>
<br></br>
<table>
<tr>
<td><div id="field_name">Questionnaire received on (dd/mm/yyyy):</div></td>
<td><%= date_select("questionnaire", :received_on, :order=>[:day,:month,:year],:use_month_numbers=>true,:start_year=>Date.today.year,:end_year=>2008,:include_blank => true) %></td>
</tr>
<tr>
<td><div id="field_name">Interviewer name:</div></td>
<td><%=text_field("questionnaire",:intervieweename)%></td>
</tr>
</table><!-- end questionnaire div -->
<%= f.submit "SectionB" , :class => "questButton" %>
</div>
<!--- Page 2 --->
<div class="panel" id="SectionB">
<b><u>Section B: Case Classification</u></b>
<br></br>
<% fields_for :patient, #patient do |p| %>
<table>
<tr>
<td class="sectionA_is_this_case"><div id="field_name">Epidemiology definition:</div></td>
<td><%= #patient.epidef %>
</td>
</tr>
</table>
<% end %>
<table>
<tr>
<% fields_for :patient, #patient do |p| %>
<td><div id="field_name">Asymptomatic:</div></td>
<td><% if #patient.asymptomatic %>Yes<% else %>No<% end %></td>
<% end %>
<tr>
<tr>
<td><div id="field_name">Investigation is:</div></td>
<td><%=select("detail", "invstatus", INVESTIGATION_IS)%></td>
</tr>
<tr>
<td><div id="field_name">Outbreak keyword or number:</div></td>
<td><%= f.text_field :outbreakid ,:cols => 40, :rows => 1 %></td>
</tr>
</table>
</div>
<%= f.submit "SectionC" , :class => "questButton" %>
</div>

Resources