How can I refactor this code for Ruby? - ruby

I created the following helper method and it is working fine but I want to improve the way it is being called.
def display_if_present(attribute, i18key, hours=nil)
unless attribute.blank?
content_tag :li do
if hours.present?
concat content_tag :h2, get_translation_by_model_attr('achievment', i18key) + ' ('+t(:hours)+'): '
else
concat content_tag :h2, get_translation_by_model_attr('achievment', i18key)+': '
end
if i18key.include? 'date'
concat content_tag :p, attribute.strftime('%m/%Y')
elsif hours.present?
concat content_tag :p, h(attribute) + "(" + t(:hours) + ")"
else
concat content_tag :p, h(attribute)
end
end
end
end
And on the view side I have the following:
<%= display_if_present(academic_achievment.institution,'institution') %>
<%= display_if_present(academic_achievment.ativs_description,'ativs_description') %>
<%= display_if_present(academic_achievment.date_start,'date_start') %>
<%= display_if_present(academic_achievment.date_finished,'date_finished') %>
<%= display_if_present(academic_achievment.load, 'load', :hours) %>
<%= display_if_present(academic_achievment.tags, 'tags') %>
which I want to do some refactor. So I tried:
<% elements = %w(institution ativs_description date_start date_finished load tags) %>
<% elements.collect! do |item| %>
<% params = (item == "load") ? "item, :hours" : "item" %>
<%= display_if_present("academic_achievment.#{item}".constantize, params.constantize) %>
<% end %>
the above block of code returned the error:
wrong constant name academic_achievment.institution
Extracted source (around line #15):
12:
13: <% elements.collect! do |item| %>
14: <% params = (item == "load") ? "item, :hours" : "item" %>
15: <%= display_if_present("academic_achievment.#{item}".constantize, params.constantize) %>
16: <% end %>
17:
18: </ul>
I appreciate some help for a better piece of code.

I recommend using the send method like this:
<% %w(institution ativs_description date_start date_finished load tags).each do |item| %>
<%= display_if_present(academic_achievment.send(item), item, item == 'load' ? :hours : nil) %>
<% end %>

Related

How to list(<li>) data from a column in a table having newlines(\r +) inside ruby tag?

My code is
#tariff.each do |tar|
<li><%= tar.lt_ninety%></li>
<%end%>
This lt_ninety has a value (hey hello) contain new line(\r +) in between each word in table.
I have found one method in Stack Overflow, but couldn't help me to solve.
<li><%= h(tar.lt_ninety).gsub(/\r/, '<br/>').html_safe%></li>
and output was like
<li> hey</li>
hello
I cannot wrap hello in <li>
Split up tar.lt_ninety and loop it
<% #tariff.each do |tar| %>
<% tar.lt_ninety.split(/\r/) do |ln|%>
<li><%= h ln %></li>
<% end %>
<%end%>
Just split tar.lt_ninety into separate lines before generating a <li> for each line:
<% #tariff.each do |tar| %>
<% tar.lt_ninety.lines.each do |line| %>
<li><%= line %></li>
<% end %>
<%end%>
Hurray!! my colleague gave me a cool solution
<ul><% (tar.lt_ninety).split(/\r\n/).each do |val| %>
<li><%= val %></li>
<% end%></ul>

erb sudoers iterate over hash of arrays

I try to generate sudoers file dynamically via puppet. Here i have hieradata like this:
---
sudoparameters:
cmnd_aliases:
CMND_ALIAS_A:
- /path/to/command_a *
- /path/to/command_b *
CMND_ALIAS_B:
- /path/to/command_c
- /path/to/command_d *
runas_aliases:
RUNAS_ALIAS_A:
- runas_user_a, runas_user_b
RUNAS_ALIAS_B:
- runas_user_a, runas_user_c
defaults:
- user!authenticate
- user!systlog
commands:
- user ALL=(root) NOPASSWD:/usr/sbin/puppetd --test agent --server=*
- user ALL=(root) NOPASSWD:/usr/bin/lsof -a *
- user ALL=(RUNAS_ALIAS_A) NOPASSWD: CMND_ALIAS_A
And an erb template like this:
<% #sudoparameters['cmnd_aliases'].each do |cmnd_alias| -%>
Cmnd_Alias <%= cmnd_alias %> <%= cmnd_alias.map { |path| path.join(', ') } %>
<% end -%>
<% #sudoparameters['runas_aliases'].each do |runas_alias| -%>
Runas_Aliases <%= runas_alias %> <%= runas_alias.map { |path| path.join(', ') } %>
<% end -%>
<% #sudoparameters['defaults'].each do |default| -%>
Defaults:<%= default %>
<% end -%>
<% #sudoparameters['commands'].each do |command| -%>
<%= command %>
<% end -%>
My approach to iterate over the cmnd_aliases and runas_aliases doesn't work. How can i accomplish it to generate a comma seperatet list für Cmnd_Aliases and Runas_Aliases if these arrays exists in sudoparameter hash?
Cheers
Christian
To solve the issue i wrapped the each blocks into:
<% if (#sudoparameters['cmnd_aliases'] != nil) then -%>
<% #sudoparameters['cmnd_aliases'].each do |cmnd_alias| -%>
Cmnd_Alias <%= cmnd_alias %> <%= cmnd_alias.map { |path| path.join(', ') } %>
<% end -%>
<% end -%>
But for now the cmnd_alias.mapdoesn't work as expected. i get the following error.
Detail: undefined method `join' for "CMND_ALIAS_A":String
To solve that i save key and value to different vars and apply the join directly to the values.
<% if (#sudoparameters['cmnd_aliases'] != nil) then -%>
<% #sudoparameters['cmnd_aliases'].each do |cmnd_alias_key, cmnd_alias_value| -%>
Cmnd_Alias <%= cmnd_alias_key %> <%= cmnd_alias_value.join(', ') %>
<% end -%>
<% end -%>
<% if (#sudoparameters['runas_aliases'] != nil) then -%>
<% #sudoparameters['runas_aliases'].each do |runas_alias_key, runas_alias_value| -%>
Runas_Aliases <%= runas_alias_key %> <%= runas_alias_value.join(', ') %>
<% end -%>
<% end -%>
<% if (#sudoparameters['defaults'] != nil) then -%>
<% #sudoparameters['defaults'].each do |default| -%>
Defaults:<%= default %>
<% end -%>
<% end -%>
<% #sudoparameters['commands'].each do |command| -%>
<%= command %>
<% end -%>
If some values in your Hash are nil, you can use this syntax :
<% (#sudoparameters['cmnd_aliases'] || {}).each do |cmnd_alias_key, cmnd_alias_values| -%>
Cmnd_Alias <%= cmnd_alias_key %> <%= cmnd_alias_values.join(', ') %>
<% end -%>
a || b syntax is helpful to avoid undefined method errors :
{:a => :b} || {}
#=> {:a => :b}
nil || {}
#=> {}
Finally, if cmnd_alias_value is an Array, it should be written as a plural : cmnd_alias_values. It's not a must, but it might make your code a bit easier to understand.

Make counter variable in each method increase itself

How to make a variable within .each method increasable, so the output would be 1, 2, 3...Instead of this:
<% #all_posts.each do |p, a = 0| %>
<% a += 1 %>
<%= a %>
<% end %>
Output: 1, 1, 1...
Just use each_with_index instead of each
Only caveat: the index starts with 0.
<% #all_posts.each_with_index do |p, a| %>
<%= a %>
<%= p.name %>
<% end %>
See http://ruby-doc.org/core-2.3.0/Enumerable.html#method-i-each_with_index
To make it accessible, initialize it outside of the loop.
<% a = 0 %>
<% #all_posts.each do |p| %>
<% a += 1 %>
<%= a %>
<% end %>
But a better way is:
<% #all_posts.each.with_index(1) do |p, a| %>
<%= a %>
<% end %>

erb idiom to handle undefined variable

I'm trying to write some puppet .erb, I'd like to handle this "environment" variable if it's:
undefined
a string with newlines
an array.
I've got as far as this:
<% Array(environment).join("\n").split(%r{\n}).each do |f| %>
one line: <%= f %>
<% end %>
But haven't gotten around the undefined case yet. I've tried this
<% if (defined?(environment)).nil? %?
<% Array(environment).join("\n").split(%r{\n}).each do |f| %>
one line: <%= f %>
<% end %>
<% end %>
but am still getting "(erb):11: undefined local variable or method `environment' for main:Object (NameError)" when trying to test it like this:
ruby -rerb -e "environmentUNDEFINEME= [ 'cronvar=cronval', 'var2=val2' ];
puts ERB.new(File.read('templates/job.erb')).result"
Sorry this is so basic, but somebody's got to ask the easy questions. Any help?
I would do this:
<% if defined?(environment) %>
<% Array(environment).each do |f| %>
one line: <%= f %>
<% end %>
<% end %>
I didn't understand why you joining on new lines and then splitting on them again, so I removed it from the example.

Ruby each, different action depending on index, with a pattern?

Ok so my title may be confusing. What I want to do is to loop through a collection of models, and for the first two, render a template, for the next four render a different template and next two render the same template as for the first ones, and so on.
Like this:
<% ads.each do |ad| %>
<% # if it's 1-2, 7-8, 13-14 and so on render as big' %>
<%= render 'front/home/big_ad', ad: ad %>
<% # if it's 3-6, 9-12, 15-18 and so on render as small' %>
<%= render 'front/home/small_ad', ad: ad %>
<% end %>
<% end %>
What would be the cleanest way to accomplish this?
If your groups would be even long, then you could use in_groups_of command, and alternate between them, but with these specifications, the easiest way is this:
<% ads.each_with_index do |ad, index| %>
<% if (index % 6 < 2) %>
<%= render 'front/home/big_ad', ad: ad %>
<% else %>
<%= render 'front/home/small_ad', ad: ad %>
<% end %>
<% end %>

Resources