How to break inside an haml loop? - ruby-on-rails

It could be a stupid question, but that is why I prefer to ask here.
I have this code below in HAML:
- #calendar[:array_number_day].each.with_index do |num_d, index|
%tr
- (0..6).each do |i|
- if (#calendar[:array_name_day][index] == i)
%td
%span #{num_d}
- else
%td
How can I break the each loop in this case ? I tried #{break} and break after %span #{num_d} but without success.
Thank's in advance for the help,

- break should work:
- #calendar[:array_number_day].each.with_index do |num_d, index|
%tr
- (0..6).each do |i|
- if (#calendar[:array_name_day][index] == i)
%td
%span #{num_d}
- break
- else
%td
Make sure you have - and use the proper indentation (it should be one indentation level deeper than the if statement.

Related

Simpler index views

In a Rails index view you iterate the collection and per item in the collection data is presented. In most cases I end up with a complex view, because there is a need to do additional calculations for a specific item in the collection. Here is a typical example:
- if #projects.blank?
= render "shared/placeholder", colspan: "10"
- else
- #hours_total = 0
- #turnover_total = 0
- #projectusers_total = 0
- #projects.each do |project|
- decorate project do |decorates|
- project_calc = ProjectCalculator.new(project)
- hours = project_calc.get_project_data("hours")
- turnover = project_calc.get_project_data("turnover")
- #hours_total += hours
- #turnover_total += turnover
- #projectusers_total += project.projectusers.size
%tr
%td= link_to decorates.data_field(project.name), admin_project_path(project)
%td= decorates.data_field(project.customer.name) unless project.customer.blank?
%td= decorates.data_field(project.company.name_short)
%td= decorates.status
%td= decorates.data_field(project.projectusers.size)
%td= decorates.decimal(hours)
%td= decorates.amount(turnover)
%td= decorates.fixed_price
%td= decorates.show_progress("hours", "compact", hours)
%td= decorates.show_progress("turnover", "compact", turnover)
An improvement I already implemented is to use a decorator for view specific stuff and another one is to use service objects for the actual calculations.
But what bothers me here are all the calculations. What is a solution to make this simpler and ideally not having this in the view?
What about using a Presenter?
This link helped me a lot: http://robertomurray.co.uk/blog/2014/decorators-presenters-delegators-rails/
Here is another Short overview
In your case you could implement it like this
# app/presenter/project_presenter.rb
class ProjectPresenter
attr_accessor :project, :project_calculator
def initialize project
#project = project
#project_calculator = ProjectCalculator.new
end
def hours
project_calculator.get_project_data("hours")
end
def show_progress *args
# calculate progress
end
end
In your controller you can initialize the presenter for every project
#projects = Project.all.collect { |project| ProjectPresenter.new(project) }
So, your view can access the presenter with
- #projects.each do |project|
%tr
%td= project.show_progress('hours')
Hope it will help
ciao boris

Why is ruby's '.each' giving different results to using 'for'?

I am trying to switch a for x in y loop to a each_with_index. First, I am trying to switch from for to each. The code before is
...
- row_bg_color_group = 'row_color_group_1'
- for link in #links
- construct_hyperlink(link.url_address, link.alt_text)
- if link.group.group_name != (current_group ||= '')
- display_group = current_group = link.group.group_name
- row_bg_color_group = rotate_rows_color_group
- else
- display_group = ''
%tr{:class => "#{row_bg_color_group}"}
%td
= link_to display_group, link.group, {"title" => link.group.group_description}
%td
%span#mainLink
= sanitize #address_url
%td= link.version_number
....
and rotate_rows_color_group is a helper in app/helpers. The code is
def rotate_rows_color_group
if session[:group_shading] == 'true' || params[:show]
cycle('row_color_group_1 color_group_1', 'row_color_group_2 color_group_2', 'row_color_group_3 color_group_3')
else
cycle('row_color_group_1', 'row_color_group_2', 'row_color_group_3')
end
end
The initial change I made is just to switch
- for link in #links
to be
- #links.each do |link|
This is changing my view from
to
The group name gets repeated. Is it a scope issue?
Since .each uses a block, any variable declared within it will be re-declared each time it is entered.
To avoid this, simply declare current_group outside the block:
...
- row_bg_color_group = 'row_color_group_1'
- current_group = ''
- #links.each do |link|
- construct_hyperlink(link.url_address, link.alt_text)
- if link.group.group_name != current_group
- display_group = current_group = link.group.group_name
- row_bg_color_group = rotate_rows_color_group
- else
- display_group = ''
%tr{:class => "#{row_bg_color_group}"}
%td
= link_to display_group, link.group, {"title" => link.group.group_description}
%td
%span#mainLink
= sanitize #address_url
%td= link.version_number
....

Order alphabetically and group by first letter

I currently have the following code:
- #alpha = Glossary.find(:all, :order =>"title ASC").group_by{|u| u.title[0]}
- #glossary = Glossary.find(:all, :order =>"title ASC")
- #alpha.each do|a|
%h1= a[0]
- #glossary.each do |g|
%p display stuff
This displays all of the glossary terms under each letter rather than only the ones that begin with the letter.. I've tried a few things but I'm not sure how to select the right thing.
You should be able to do everything with your #alpha instance variable, since you're using group_by:
- #alpha = Glossary.find(:all, :order =>"title ASC").group_by{|u| u.title[0]}
- #alpha.each do |alpha, glossary_array|
%h1= alpha
- glossary_array.each do |item|
%p= item
You're close. I think you just want to do
- #alpha = Glossary.order("title ASC").group_by{|u| u.title[0]}
- #alpha.each do |letter, items|
%h1= letter
- items.each do |item|
%p= item

Rails + Bootstrap 3: Have two columns in a row, but have them collapse one column after another

This is an odd problem I'm having. I have a list of names, split up into two arrays at the middle. So names A-M are in name1 and names N-Z are in name2. Now I'm going through each array and putting them in a row with two columns so the names look like this:
Aaron Neil
Arthur Nick
etc. But when I collapse the page down, it looks like:
Aaron
Neil
Arthur
Nick
and I want it to look like:
Aaron
Arthur
Neil
Nick
Here's the haml:
- a = true
- index = 0
- while(a)
- first = name1[index]
- second = name2[index]
- if first != nil || second != nil
.row
.col-md-6
- if first
= first
.col-md-6
- if second
= second
- index += 1
- else
- a = false
I understand why this is happening, but I'm not exactly sure how else to approach this. Does anyone have any insight?
You are creating a new row and column for each set of names.
instead you should run your loop inside the columns like this:
- name1 = %w[Aaron Arthur]
- name2 = %w[Neil Nick]
.row
.col-md-6
-name1.each do |x|
%p= x
.col-md-6
-name2.each do |x|
%p= x

haml conditional if/else indentation

I have a situation where I want to add a class to a div tag only when the count is greater than 0
Example:
- #color.shades.each_with_index do |shade, index|
- if index == 0
#shades
- else
#shades.horizontalLine.second
%h3 something
%dl
%dt some
%dd some1
In this example I want everything starting from %h3 to come under either #shades or #shades.horizontalLine.second depending on however those if and else statements evaluate.
work around is:
- #color.shades.each_with_index do |shade, index|
- if index == 0
#shades
%h3 something
%dl
%dt some
%dd some1
- else
#shades.horizontalLine.second
%h3 something
%dl
%dt some
%dd some1
but here I have to repeat code
I'm stumped at how to do this in rails without repeating the code starting from %h3 for both the divs.
You can set the class to a variable holding the class names based on the index to DRY it up:
- #color.shades.each_with_index do |shade, index|
- shade_classes = index == 0 ? '' : 'horizontalLine second'
#shades{ :class => shade_classes }
%h3 something
%dl
%dt some
%dd some1

Resources