Ruby Each Loop Variable Substitution - ruby

I'm trying to set all the values to 0 but the 3rd line (send(x)) is giving me problems. Seems right to me, but doesn't work. x is the car and name of the columns in Power. Any tips?
<% #cars.each do |x| %>
<% #power = Power.find_by_user_id(#user) %>
<% #power.send(x) = 0 %>
<% #power.save %>
<% end %>

Assuming #cars contains column names of Power, you need to send the setter method (i.e. with an = at the end). You also need to ensure you're passing a symbol to send.
#cars.each do |x|
#power = Power.find_by_user_id(#user)
#power.send(:"#{x}=", 0)
#power.save
end
There's also not an obvious reason why you need to set or save #power in the loop, so it might be better as:
#power = Power.find_by_user_id(#user)
#cars.each do |x|
#power.send(:"#{x}=", 0)
end
#power.save

Related

Ruby - trying to make hashtags within string into links

I am trying to make the hashtags within a string into links.
e.g. I'd like a string that's currently: "I'm a string which contains a #hashtag" to transform into: "I'm a string which contains #hashtag"
The code that I have at the moment is as follows:
<% #messages.each do |message| %>
<% string = message.content %>
<% hashtaglinks = string.scan(/#(\d*)/).flatten %>
<% hashtaglinks.each do |tag| %>
<li><%= string = string.gsub(/##{tag}\b/, link_to("google", "##{tag}") %><li>
<% end %>
<% end %>
I've been trying (in vain) for several hours to get this to work, reading through many similar stackoverflow threads- but frustration has got the better of me, and as a beginner rubyist, I'd be really appreciate it if someone could please help me out!
The code in my 'server.rb' is as follows:
get '/' do
#messages = Message.all
erb :index
end
post '/messages' do
content = params["content"]
hashtags = params["content"].scan(/#\w+/).flatten.map{|hashtag|
Hashtag.first_or_create(:text => hashtag)}
Message.create(:content => content, :hashtags => hashtags)
redirect to('/')
end
get '/hashtags/:text' do
hashtag = Hashtag.first(:text => params[:text])
#messages = hashtag ? hashtag.messages : []
erb :index
end
helpers do
def link_to(url,text=url,opts={})
attributes = ""
opts.each { |key,value| attributes << key.to_s << "=\"" << value << "\" "}
"<a href=\"#{url}\" #{attributes}>#{text}</a>"
end
end
Here is the code to get you started. This should replace (in-place) the hashtags in the string with the links:
<% string.gsub!(/#\w+/) do |tag| %>
<% link_to("##{tag}", url_you_want_to_replace_hashtag_with) %>
<% end %>
You may need to use html_safe on the string to display it afterwards.
The regex doesn't account for more complex cases, like what do you do in case of ##tag0 or #tag1#tag2. Should tag0 and tag2 be considered hashtags? Also, you may want to change \w to something like [a-zA-Z0-9] if you want to limit the tags to alphanumerics and digits only.

Redmine modification for issue number

I would like to hide the issue number on the issue list.
I use "Redmine 2.3.1" and the file to achieve that is this file: ./app/views/issues/_list.html.erb
It contains this line:
<%= raw query.inline_columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, issue)}</td>"}.join%>
And the array query.inline_columns contains the id for example. I thought modifying this array would help me with my problem, but the changes aren't saved.
This is what I tried:
<%= #query.inline_columns.inspect %>
=> [#<QueryColumn:0x00000003607928 #name=:id ... and so on>]
<% #query.inline_columns.delete_at(0) %>
=>
<%= #query.inline_columns.inspect %>
=> [#<QueryColumn:0x00000003607928 #name=:id ... and so on>]
Why was the delete_at useless? And how would I modify this array or hide the number?
A few things to note:
#query.inline_columns might not an array. It may quack like an Array, but it's not.
#query.inline_columns.delete_at(0) should have returned something. Did it return and you ommited?
And last, but not least, the most probable guess I can make:
#query.inline_columns fetches something, converts it to an array and dups it before returning. The only way you can do something like that would be:
some_columns = #query.inline_columns
some_columns.delete_at(0)
some_columns
This is my solution now:
<% if #project.id == 1 %>
<% #qcols = query.inline_columns.reject{ |col| col.name.to_s == 'id' } %>
<% else %>
<% #qcols = query.inline_columns.each %>
<% end %>
So I took advantage of the reject method. And then I work with the #qcols.
Posted on behalf of OP.

How to apply a mapping to a value in a Puppet/Ruby ERB template?

I'm writing an ERB template (for a Puppet module) that gets passed an Hash like this:
{"stuff" => {"foo"=>"aaa", "bar"=>"ccc"},
"other" => {"foo"=>"bbb", "bar"=>"ddd"}}
and I'm iterating over it in my templates producing rows of text:
<% #my_data.each_pair do |k, v| -%>
<%= k %> <%= v["foo"] %>:<%= v["bar"] %>
<% end -%>
Now I'd like to apply some mapping to the "foo" data with a second hash I'll pass to the template. In pseudocode:
mappings = {"aaa" => "something", "bbb" => "somethingelse"}
<% #my_data.each_pair do |k, v| -%>
<%= k %> <%= TRANSLATE_SOMEHOW(v["foo"], mappings) %>:<%= v["bar"] %>
<% end -%>
...in order to get "something" whenever the value was "aaa", and so on. I expect to get the original value if there is no corresponding key in the "mappings".
Doing that kind of thing in Puppet's language is probably possible (by extending it with some Ruby code) I think it is probably more appropriate in the ERB template, but I don't know how to do that and not knowing Ruby isn't helping me - tried google without much success.
I'm looking for code to achieve that in an ERB function or some pointers to relevant documentation for my RTFM pleasure.
EDIT:
for future readers, here's DigitalRoss' answer translated to my ERB example above:
<% #my_data.each_pair do |k, v| -%>
<%= k %> <%= mappings[v["foo"]] || v["foo"] %>:<%= v["bar"] %>
<% end -%>
With the erb stuff removed for clarity, this is what you want to do. (The p() function just prints its argument. You can try this in irb.)
#my_data.each do |k, v|
f, b = v['foo'], v['bar']
p(mappings[f] || f)
p(mappings[b] || b)
end

Ruby 'First and Rest' Logic

My app is reaching a point where I must begin optimizing for performance. I've posted some code from my view that I feel can be improved.
In the view, I am treating the first item in the index a certain way and the rest of the items another way. Each time a new item is iterated over, it is being checked (Ruby asks itself.. does this item have an index of 0?)
I feel like performance can be improved if I can stop that behavior by treating the first item special with index.first? and treating the other items another way (without even checking whether they have an index of zero) How can this be done?
<% #links.each_with_index do |link, index| %>
<% if link.points == 0 then #points = "?" else #points = link.points %>
<% end %>
<% if index == 0 then %>
<h1> First Item </h1>
<% else %>
<h1> Everything else </h1>
<% end %>
<% end %>
<% end %>
You can do this non-destructively like so:
first, *rest = *my_array
# Do something with 'first'
rest.each{ |item| … }
…where first will be the first element (or nil if my_array was empty) and rest will always be an array (possibly empty).
You can get the same results more easily if it's OK to modify your array:
# remove the first item from the array and return it
first = my_array.shift
# do something with 'first'
my_array.each{ |item| … }
However, this will only clean up your code; it will make no measurable performance difference.

In a Ruby each block, how do I do something to the last record in the array within the block?

Say I have a block like this:
<% #help_sections.each do |section| %>
<li><%= section.name %></li>
<% end %>
But on the last record returned, I want to do something else, e.g. applying a class to the li that's there:
<li class="last"><%= section.name %></li>
How do I do that in the most DRY way?
Thanks.
Edit1:
I imagine I would simply use an if statement and the last ruby method, but not sure how to do that within the block? I know that if I just wanted the last element in that array, I could just do #help_sections.last, but that doesn't make sense within the confines of a Ruby block.
The most DRY way is to use CSS instead. Instead of e.g. this:
li.last { color: red; }
..and then cluttering up your markup with an extra CSS class, just use the :last-child pseudoselector, i.e.:
li:last-child { color: red; }
Then you don't have to change anything in your view. This is supported in all modern browsers including IE9.
Try each_with_index:
<% #help_sections.each do |section, index| %>
<li <%= "class='last'" if index == (#help_sections.length-1) %>><%= section.name %></li>
<% end %>
DRY is a good idea in general, but don't kill yourself to keep from repeating a li.
<% #help_sections[0...-1].each do |section| %>
<li><%= section.name %></li>
<% end %>
<li class="last"><%= #help_sections.last.name %></li>
You could either do something like
<% #help_sections.count.times do |i| %>
<%= #help_sections[i].name %>
<%= do_something if #help_sections.count == i - 1 %>
<% end %>
This old answer might help (Tell the end of a .each loop in ruby). Basically, you can use:
<% #help_sections.each_with_index do |section, index| %>
<% if index == #help_sections.size - 1 %>
<li class="last">
<% else %>
<li>
<% end %>
<%= section.name %></li>
<% end %>
If you use each_with_index instead of plain each, the block will also be passed the index of the current element within the collection. You can then compare that to #help_sections.length.
E.g.
<% #help_sections.each_with_index do |section, i| %>
<li<% concat " class='last'" if i == #help_sections.length - 1 %>><%= section.name %></li>
<% end %>
In general cases not covered by smart CSS selectors, you can define a convenient helper method, which would provide each iterated element with its context within the collection. Like this one:
def each_with_context enum
length = enum.count
enum.each_with_index do |elem, i|
context = {
:first => i == 0,
:last => i == length - 1,
:even => i.even?,
:odd => i.odd?,
:middle => i == length / 2
}
yield elem, context
end
end
And then use it within HAML view like this:
-each_with_context(#help_sections) do |section, context|
%li{:class => context[:last] ? 'last' : nil}
=section.name

Resources