Ruby on Rails Loops - ruby-on-rails

I want to create the following loop in rails:
If value<=5
display image1.gif value.times && display image2.gif (5-value).times
I was trying to add this to my View, but is there a way I can convert it into a method? How would I put the image tags if I where to make it a helper method?
Thanks in advance for any help.

def show_starts(value)
if value <= 5
image_tag("image1.gif")*value + image_tag("image2.gif")*(5-value)
end
end

This should work if I'm understanding what you're looking for.
Put this in a helper file:
def image_helper(value, image1, image2)
html = ''
if value <= 5
value.times { html += image_tag(image) }
(5 - value).times { html += image_tag(image2) }
end
html.html_safe
end
Then call it from your view like like:
image_helper(value, 'image1.gif', 'image2.gif')

(For star rating system)
Got it working like this:
def display_stars content_tag :span, :class => 'stars' do
current_admin_rating.times do
concat(image_tag("image1.gif";, :size => "30x30", :class => "gold"))
end
(5-current_admin_rating).times do
concat(image_tag("image2.gif";, :size => "30x30", :class => "gold"))
end
nil
end

Related

Ruby on Rails helper prints out odd stuff

I want to create a helper which iterates thru the list of user's communities and creates as many thumbnails as the number of comunities available. So I created these 2 helper methods
def print_admined_group_thumbs
#user_groups_hash[:admined_groups].each {
|group_hash|
name = group_hash[:name]
group_id = group_hash[:group_id]
photo = group_hash[:photo]
members_count = group_hash[:members_count].to_i
concat(get_group_thumbnail_html(group_id, name, members_count, photo))
}
end
# creates a small preview for the selected comunity group
def get_group_thumbnail_html(group_id, name, members_count, photo)
content_tag(:div, :class => "col-md-55") do
concat(content_tag( :div, :class => 'thumbnail') do
concat(content_tag(:div, :class => 'image view view-first') do
concat(image_tag(photo, :class => "group_thumb_image"))
concat(content_tag(:div, :class => "mask") do
concat(content_tag :p, "Your text")
concat(content_tag(:div, :class => "tools tools-bottom") do
end)
end)
concat(content_tag(:div, :class => "caption") do
concat(content_tag(:p, name))
end)
end)
end)
end
end #end get_group_thumbnail_html
So I simply add this call to my view
<%= print_admined_group_thumbs %>
It all works almost correctly and creates all thumbnails just like I want, except for one thing. It also prints out the entire contents of "group_hash" variable right after the thumbnails. Maybe I'm just too exhausted today, but I can't seem to figure out why? I'd be greateful if somebody helped me solve this problem and explain what am I doing wrong with it?
#some_hash.each {} automatically returns the hash after it completes. So your function print_admined_group_thumbs() adds your thumbnails to the template and returns the hash.
The problem is here:
<%= print_admined_group_thumbs %>
That = means "take whatever value is returned and add it to the template. So you're accidentally adding the hash to the template after printing the thumbnails to the template. You can easily fix it by removing the =:
<% print_admined_group_thumbs %>
This tells rails to run the function without adding its return value to the template.

Rails re-factor: How can I refactor this to work?

These two lists are only slightly different as I need to treat the first 3 items a little differently than the rest. The only reason this isn't working now is because the variable with the regex is called twice. Any idea how to get the first 3 items (as shown in the first %li) separated from the rest without having to repeat everything like this?
%ul.list_container
- #links.sort_by { |link| link.votes.where(:up => true).count - link.votes.where(:up => false).count }.reverse.first(3).each do |link|
%li
.various_containers
%p
= link_to link.title, "http://youtube.com/embed/#{link.url.to_s.match(/\/\/youtu.be\/(\S+)$/)[1]}/?rel=0", :class => "youtube title_link"
= link.url_html
- #links.sort_by { |link| link.votes.where(:up => true).count - link.votes.where(:up => false).count }.reverse.drop(3).each do |link|
%li{:style => 'margin-bottom: 50px;'}
.various_containers
%p
= link_to link.title,"http://youtube.com/embed/#{link.url.to_s.match(/\/\/youtu.be\/(\S+)$/)[1]}/?rel=0", :class => "youtube title_link"
A few things. You have a lot of code, including ActiveRecord lookups, in the view where it does not belong. By the time it gets to the view, #links should already be transmogrified into whatever simple collection you want to iterate over.
So the view should look like this:
-#prepared_links.each do |link, url_html|
%p
=link_to link.title, link.embedded_url, :class => "youtube title_link"
=url_html
This means you need a few additional methods: embedded_url can go in your Link model and can essentially just be that "http://youtube.com/embed/.../?rel=0" string you have in link_to now.
As for displaying url_html for the first three, try something like this in your controller:
def my_method
#prepared_links = Link.sorted_by_vote_count # you'll have to add this method as well
url_htmls = #prepared_links[0..2].map(&:url_html)
#prepared_links = #prepared_links.zip(url_htmls)
end
This will give you an array of prepared links as paired values, in which the first three will be [some_link, url_html], and everything after the first three will be [some_link, nil], meaning nothing will be displayed for url_html unless it's actually there.
You can use the each_with_index method and customize each loop depending of the index value.
%ul.list_container
- #links.sort_by { |link| link.votes.where(:up => true).count - link.votes.where(:up => false).count }.reverse.each_with_index do |link, index|
%li{ :style => "#{index < 3 ? 'margin-bottom: 50px;' : ''}" }
.various_containers
%p= link_to link.title, "http://youtube.com/embed/#{link.url.to_s.match(/\/\/youtu.be\/(\S+)$/)[1]}/?rel=0", :class => "youtube title_link"
- if index < 3
= link.url_html

How to use an if statement in HAML to control a tag class string?

I have a condition where if action_name contains "index" then the second class should return "index" only, otherwise, set it to action_name.
I was trying something along these lines:
- if action_name =~ /.*index.*/
%body{ :class => "#{controller_name} index" }
- else
%body{ :class => "#{controller_name} #{action_name}" }
Unfortunately I have the remainder of my body in the layout that follows these and it is only displayed for the else clause.
I figure there is a more readable one liner that I could use here as well that would perform an if within the line vs the more verbose multiline if statement, but I could use some help here in terms of gettin this to work as expected in HAML.
Well, here's a one liner:
%body{ :class => "#{controller_name} #{(action_name =~ /.*index.*/) ? 'index' : action_name}" }
Not that readable though!
I'd put a method in a helper. I like to keep logic out of my views.
application_helper.rb
def get_class(name)
"#{controller_name} #{(name =~ /.*index.*/) ? 'index' : name}"
end
view
%body{ :class => get_class action_name }
%body{:class => "#{controller_name} #{(action_name =~ /[index]/) ? 'index' : action_name}" }

Optional parameters for Rails Image Helper

In my current Rails (Rails 2.3.5, Ruby 1.8.7) app, if I would like to be able to define a helper like:
def product_image_tag(product, size=nil)
html = ''
pi = product.product_images.first.filename
pi = "products/#{pi}"
pa = product.product_images.first.alt_text
if pi.nil? || pi.empty?
html = image_tag("http://placehold.it/200x200", :size => "200x200")
else
html = image_tag(pi, size)
end
html
end
...and then call it from a view with either:
<%= product_image_tag(p) %>
...or:
<%= product_image_tag(p, :size => 20x20) %>
In other words, I'd like to be able to have this helper method take an optional size parameter. What would be the best way to go about this?
You're on the right track. I would do this:
def product_image_tag(product, options = {})
options[:size] ||= "200x200"
if img = product.product_images.first
image_tag("products/#{img.filename}", :alt => img.alt_text, :size => options[:size])
else
image_tag("http://placehold.it/#{options[:size]}", :size => options[:size])
end
end
Explanations:
Setting the final parameter to an empty hash is a common Ruby idiom, since you can call a method like product_image_tag(product, :a => '1', :b => '2', :c => '3', ...) without explicitly making the remaining arguments a hash with {}.
options[:size] ||= "200x200" sets the :size parameter to 200x200 if one wasn't passed to the method.
if img = product.product_images.first - Ruby lets you do assignment inside a condition, which is awesome. In this case, if product.product_images.first returns nil (no image), you fall back to your placehold.it link, otherwise display the first image.

How do I add 'required' to form label if specific option is set?

Using Rails, I would like to add: <span class='req'>•</span> within my <label> tags in my views, if I set an option on the label form helper; i.e.
<%= f.label :address_1, "Address 2:", :req => true -%>
should produce:
<label for="model_address_1"><span class='req'>•</span> Address 1:</label>
rather than:
<label for="model_address_1" req="true">Address 1:</label>
as it does now. I realise I may have to override the default form builder or create my own form builder, but don't know how to do this. Any suggestions? Thanks in advance!
Update: I'm doing this in an attempt to DRY up my code, and I realise that I could just paste the span snippet above into all the labels in all of my views but I'd like to avoid that.
This is untested, but something along these lines should work.
# in lib/labeled_form_builder.rb
class LabeledFormBuilder < ActionView::Helpers::FormBuilder
def label(field_name, label = nil, options = {})
if options.delete(:req)
label ||= field_name.to_s.humanize
label = #template.content_tag(:span, "•", :class => "req") + " " + label
end
super(field_name, label, options)
end
end
And then use that builder in your view
<%= form_for #item, :builder => LabeledFormBuilder do |f| %>
You might be interested in Episode 3 of my Mastering Rails Forms screencast series where I go into detail on creating form builders.
Small change to ryanb's to get it to work in Rails 3. You just need to tell content_tag to not escape the bullet.
class LabeledFormBuilder < ActionView::Helpers::FormBuilder
def label(field_name, options = {}, label = nil)
if options.delete(:req)
label ||= field_name.to_s.humanize
label = #template.content_tag(:span, "•", {:class => "req"}, false) + " " + label
end
super(field_name, label, options)
end
end

Resources