How to display data in two columns in Rails - ruby-on-rails

I'm new to Ruby on Rails. How can I display products in two columns?
When I write the following, the right column will display the same products, but I want to display
some in the left and some in the right columns.
#main_container
.left_col
%div{"data-hook" => "___homepage_featured_products"}
%h3
Featured Activities
- #featured.each do |pr|
- #product = pr
%a.box{:href=>url_for(#product), :title=>"#{#product.name} | #{#product.location}"}
- if #product.images[0]
.img{:style=>"background-image: url('#{#product.images[0].attachment.url(:original)}')"}
.details
%h3
= #product.name.truncate 20
%p.infos
= image_tag #product.activity_type.icon, :class=>"pictogram" rescue ''
%span= #product.activity_type.name.titleize rescue ''
\/
%span.price= number_to_currency #product.price rescue ''
\/
= #product.location
\/
= #product.level
%p
= #product.description.truncate(120) rescue ''
.right_col

You could put each product into its own div, and then use CSS to float them to the left so that a maximum of 2 boxes will appear next to each other horizontally. This will give the effect of a 2 column layout. As an example:
#main_container { width: 900px; }
.featured_product { width: 450px; float: left; }
Add padding etc as needed.
Alternatively you could split the array after you retrieve it from the database and run the code twice, once in the left column and once in the right:
#left, #right = #featured.in_groups_of((#featured.count / 2.0).ceil, false)

Related

PRAWN - Two variables in same column

I wish to have a Prawn PDF which will contain a column containing two variables. Here is my table definition:
def transactions_table
grid([3,0], [14,3]).bounding_box do
data = [%w(Date Description Amount)]
data += #rows.map{|r| [r.value_date, r.description, r.amount, r.credit]}
options = { header: true, width: 520,
column_widths: {0 => 100, 2 => 200},
row_colors: ['EEEEEE', 'FFFFFF']}
table(data, options) do
cells.padding = 5
cells.border_width = 0.5
cells.border_color = BLACK
row(0).font_weight = 'bold'
row(0).border_color = BLACK
column(2).align = :right
end
end
end
As you can see there are four columns value_date, description, amount and credit. I want to have amount and credit in the same column, however, I'm not sure how to do this. Simply removing the comma does not work. Is there a joiner could someone fill me in. Thanks.
You can combine the two values in one string, for example with string interpolation.
data += #rows.map{|r|
[r.value_date, r.description, "#{r.amount} #{r.credit}"]
}
You can join two strings with the + operator. I'm not sure if the values you want to join are strings, but you can make sure they are with the to_s method:
data += #rows.map{|r| [r.value_date, r.description, r.amount.to_s + ' ' + r.credit.to_s]}
The best solution I could come up with is was to remove borders:
column(3).borders = [:top, :right, :bottom]
column(2).borders = [:top, :left, :bottom]

How to iterate through a collection, and place each item in its own Prawn grid square?

I'm using Prawn in a Rails app to produce a PDF of tiled objects - something like a page of mail merged labels.
I've set up a grid in the pdf document, but am having trouble working out how to iterate through this grid with my collection.
My pdf class looks something like this.
class MyPdf < Prawn::Document
def initialize(vessels, view)
super(page_layout: :landscape)
#objects = objects
define_grid columns: 2, rows: 3, gutter: 10
build_page
end
def build_page
#objects.each do |object|
[0,1].each do |col|
[0,1,2].each do |row|
grid(row,col).bounding_box do
text object.name
end
end
end
end
end
end
This code is obviously not working, and not placing each object in a new grid square and creating new pages as required.
How do I iterate through my objects, and place each one in its own grid square?
(NB. I'm aware of the prawn-labels gem, but it has some limitations so not suitable for my needs. )
The problem is you're writing to each grid location for each item.
Try this instead, this should only write once per object, and create a new page + grid when it needs to.
def build_page
define_grid columns: 2, rows: 3, gutter: 10
col = 0
row = 0
#objects.each do |object|
grid(row,col).bounding_box do
text object.name
if row == 2 && col == 1
start_new_page
define_grid columns: 2, rows: 3, gutter: 10
col = 0
row = 0
else
if col == 1
row += 1
col = 0
else
col += 1
end
end
end
end
end

How can I clean up data from a Model, and include HTML as well?

In my Rails app, I've got a model called Video, and each video has a rating:integer. The ratings are from 1 to 5. However, when I display them to the user, I want to make them look nice. So for now, using text, I replace a rating of 3 with ***.., for instance.
In my video.rb I've got:
def graphical_rating
stars = ''
no_stars = ''
rating.times { stars += '*' }
(5 - rating).times { no_stars += '.' }
return stars + no_stars
end
Now, I want to add some HTML to it, so that it outputs <span class="stars">***</span><span class="no-stars">..</span> but it outputs as text rather than HTML.
What's the best way of handling this so that it's still as easy as it was before (I could just use video.graphical_rating) while being able to also include HTML?
This method actually belongs in your VideoHelper file because it only only applies to your views, not the logic of the model.
This should work:
def graphical_rating(rating)
stars = ''
no_stars = ''
rating.times { stars += '*' }
(5 - rating).times { no_stars += '.' }
return raw("<span class='stars'>#{stars}</span><span class='no-stars'>#{no_stars}</span>")
end
Then, in the view you can call it with:
<%= graphical_rating(#video.rating) %>

Generate table of contents like on Wikipedia, without JavaScript

I have a page that is formatted like so:
<h1>Header</h1>
<h2>Subheader</h2>
<h3>Subsubheader</h3>
<h1>Another header</h1>
Is it possible to server-side generate a table of contents / outline at the start of the page, like Wikipedia does in its articles? I use Ruby on Rails.
EDIT: WITHOUT JavaScript!
I created a class for this purpose today. It depends on http://www.nokogiri.org/, but that gem comes with Rails already.
Put this in app/models/toc.rb:
class Toc
attr_accessor :html
TOC_CLASS = "toc".freeze
TOC_ELEMENT = "p".freeze
TOC_ITEMS = "h1 | h2 | h3 | h4 | h5".freeze
UNIQUEABLE_ELEMENTS = "h1 | h2 | h3 | h4 | h5 | p".freeze
def initialize(content)
#html = Nokogiri::HTML.fragment content
end
def generate
clear
set_uniq_ids
toc = create_container
html.xpath(TOC_ITEMS).each { |node| toc << toc_item_tag(node) }
html.prepend_child toc
return html.to_s
end
private
def clear
html.search(".#{TOC_CLASS}").remove
end
def set_uniq_ids
html.xpath(UNIQUEABLE_ELEMENTS).
each { |node| node["id"] = rand_id }
end
def rand_id
(0...8).map { ('a'..'z').to_a[rand(26)] }.join
end
def create_container
toc = Nokogiri::XML::Node.new TOC_ELEMENT, html
toc["class"] = TOC_CLASS
return toc
end
def toc_item_tag(node)
"<a data-turbolinks='false' class=\"toc-link toc-link-#{node.name}\" href=\"##{node["id"]}\">#{node.text}</a>"
end
end
Use it like
toc = Toc.new article.body
body_with_toc = toc.generate
article.update body: body_with_toc
You need to generate data source from your hierarchy to be something like this
#toc = [ ['header', 0], ['subheader', 1], ['subsubheader', 2],
['header2', 0], ['header3', 0], ['subheader2', 1]
]
Than it is easy to render it in template, for example:
<%- #toc.each do |item, distance| %>
<%= (' ' * distance * 5).html_safe %>
<%= item %>
<br/>
<%- end %>
Would give you:
header
subheader
subsubheader
header2
header3
subheader2
Of course you can use 'distance' for determining style size instead of 'depth', but I hope you get the main idea.
yes, it is possible. you don't really need rails for this; you can also use javascript to generate a table of contents.
Here is an exmaple library that you can use.
http://www.kryogenix.org/code/browser/generated-toc/
You could alternatively create your anchor links as you loop through elements in your rails erb/haml views.

Split #blogs into three divs using size of description field as weight

I have a collection of Blog items.
#blogs = Blog.find(:all)
Each blog has a description textfield with some text. What I would like to do is splitting the #blogs objects into 3 divs, but with roughly the same characters in each column.
<div id="left">
#blog1 (653 characters)
</div>
<div id="center">
#blog2 (200 characters)
#blog5 (451 characters)
</div>
<div id="right">
#blog3 (157 characters)
#blog4 (358 characters)
#blog6 (155 characters)
</div>
I can't figure out how to do that without getting really complicated and probably inefficient.
So far I have thought about converting the description field (size) to % of total characters in the #blogs collection, but how do I match/split the elements, so that I get closest to 33% in each column - like a super simple tetris game :)
Any thoughts?
Here's a quick hack that isn't perfect, but might get you pretty close. The algorithm is simple:
Sort items by size.
Partition items into N bins.
Resort each bin by date (or other field, per your desired presentation order)
Here's a quick proof of concept:
#!/usr/bin/env ruby
# mock out some simple Blog class for this example
class Blog
attr_accessor :size, :date
def initialize
#size = rand(700) + 100
#date = Time.now + rand(1000)
end
end
# create some mocked data for this example
#blogs = Array.new(10) { Blog.new }
# sort by size
sorted = #blogs.sort_by { |b| b.size }
# bin into NumBins
NumBins = 3
bins = Array.new(NumBins) { Array.new }
#blogs.each_slice(NumBins) do |b|
b.each_with_index { |x,i| bins[i] << x }
end
# sort each bin by date
bins.each do |bloglist|
bloglist.sort_by! { |b| b.date }
end
# output
bins.each_with_index do |bloglist,column|
puts
puts "Column Number: #{column+1}"
bloglist.each do |b|
puts "Blog: Size = #{b.size}, Date = #{b.date}"
end
total = bloglist.inject(0) { |sum,b| sum + b.size }
puts "TOTAL SIZE: #{total}"
end
For more ideas, look up the multiprocessor scheduling problem.

Resources