How can I collapse this very repetitive Ruby/Rails code? - ruby-on-rails

I've got two small structural issues that I'm not sure how to handle given my relative newbie-ness with RoR.
First issue: In one of my views, I have code that looks like this:
<ul style="list-style-type: circle">
<li><%= #apples.size %> apples</li>
<li><%= #oranges.size %> oranges</li>
<li><%= #bananas.size %> bananas</li>
<li><%= #grapefruits.size %> grapefruits</li>
</ul>
Is it possible to refactor this so that I only need to iterate once over some list of different kinds of fruit, and have the appropriate <li>'s be automatically generated? Edit: I forgot to add that #apples, #oranges, etc., might be nil. Is there an idiomatic way to handle that?
Second issue: In my controller, I have code that looks like this:
#apples = Apple.find(:all)
#apples.each { |apple| apple.do_stuff(:xyz) }
#bananas = Banana.find(:all)
#bananas.each = { |banana| banana.do_stuff(:xyz) }
# ... &c
As you can see, the same operation is invoked many times in exactly the same way. Is there a way to shorten this to something like [Apple.find(:all), ...].each { |fruit| ... } and have that work instead?
Thanks very much for your help!

I'd do this in a helper
def fruit_size(fruit)
list = #fruits[fruit]
return if list.empty?
content_tag(:li, "#{list.size} #{fruit}")
end
And this in the view:
<% ["apples", "oranges", "bananas", .....].each do |fruit| %>
<%= fruit_size(fruit)
<% end %>
In your controller:
#fruits = {}
["apples", "oranges", "bananas", ......].each do |fruit|
#fruits[fruit] = fruit.classify.constantize.find(:all).each {|record|
record.whatever_here
end
end
It makes sense to store all the items in a hash, #fruits, so that you don't have to use instance_variable_get and stuff.
Perhaps you also want to define that array somewhere, so that you don't have to repeat it in the controller and in the view. Let's pretend that you have a fruit model.
class Fruit < ActiveRecord::Base
FRUITS = ["apples", "oranges", "bananas", ....]
end
Then, use Fruit::FRUITS in the view and controller.

For the first part:
#li = ''
[#apples, #oranges, #bananas, #grapefruit].each{|fruit|
#li << "<li>#{fruit.size}</li>"}
<ul style="list-style-type: circle">
<%=#li%>
</ul>

You can actually do it pretty simply.
In your controller:
def whatever
#fruits = {
:apples => Apple.find(:all).each{ |a| a.do_stuff(:xyz) },
:bananas => Banana.find(:all).each{ |a| a.do_stuff(:xyz) } # ...
}
end
In your view:
<% #fruits.each |k, v| %>
<li><%= v.nil? ? 0 : v.size %> <%= k.to_s %></li>
<% end %>
Although you might want to consider whether do_stuff is something that could be done via a more complex finder, or by named scope.

Related

Getting data out of a select box and passing it into params

I am doing this for a school project and it is not working. :(
How do I get out the selected[petowner_id] from the view and make it usable in a ruby controller?
How do I make the #selected_pet = params([petowner_id]) in the controller that comes in from the view to function? Currently it renders an error message when I try to set it. :(
I am getting very tired of it not working.
The controller from Pets controller
class PetsController < ApplicationController
# GET /pets
# GET /pets.json
def monsters
#Finds the current user
if current_user
#user = current_user
#pets_kept = [] #why?
##petowner = Petowner.find(params[:petowner][:id])
#if(params[:commit])
#end
#monster = "Eeeep"
#mypets=[]
#all_my_pets = #user.petowners
#options value = 2
#params { selected_petowner[petowner_id]}
#selectpet = params{[selected][petowner_id]}
#petowner = Petowner.find_by_id(params[:id])
#pet = Pet.find_by_id(params[:pet_id])
#Find the petowners that the user currently has
##mypets = #user.petowners
#This is my way of doing things in a C++ fashion, I don't get all ruby things
#user.petowners.each do |pet|
##selected_pet = pet.find(params[:selected])
# if pet.hp != 0
# #pets_kept << pet #Dont recall seeing the << before in ruby but for C++ statement used for cout statements
#if pet.select
# #selected_pet = pet.select
#end
end
##selected_pet = Petowner.find(params[:petowner][:selected])
#end
#selected_pet = 1 ##user.petowners.find(params[:id])
#mypets = current_user.petowners.select{|pet| pet.hp !=0}
#raise "I am here"
##selected_pet = #mypets.find(params[:id][:selected])
##mypets = #pets_kept
end
The code from the view that doesn't go back to the controller variable and set it. :(
<select id="petowner_id" name="selected[petowner_id]">
<%= #all_my_pets.each do |pet| %>
<option value="<%= pet.id %>"><%= pet.pet_name %></option>
<% end %>
</select>
Previous step from pets/monsters view that doesn't work at all from previous collection. :(
<%= form_for :petowner, :url => petowner_fights_path(#selected_pet, #pet) do |f| %>
<p>Select a pet <%#= f.collection_select(:petowner, :petowner_id, #user.petowners, :petowner_id, :pet_name) %></p>
<%= render 'monsterinfo' %>
<div class="outer"></div>
<%= f.submit "Fight Selected Monster" %>
<% end %>
You probably want params[:petowner][:petowner_id]. Definitely don't construct the select with html in a view.
By the way, it's really helpful to see all of the params passed in to a controller action. I tend to raise params.to_yaml when I need to do that.

Rails - Setting up a helper to display user by gender

I have my user gender stored as a string male/female (as this is how it is retrieved from Facebook API)
The goal is to render a partial showing users by gender depending on the gender of the logged in user, but I'm having a little trouble setting up a helper
def male
#male = #user.gender.male
end
then my view..
<% #users.male.each do |male| %>
<ul>
<li><%= male.firstname %></li>
<li><%= male.age %></li>
<li><%= male.location %></li>
</ul>
What am I doing wrong, been stuck on this for ages :(
You can use scopes:
class User < ActiveRecord::Base
scope :male, -> { where gender: 'male' }
scope :female, -> { where gender: 'female' }
end
Controller:
def index
#users = User.all
#males = #users.male # or use User.male, but #users might already be filtered
#females = #users.female
end
And in your view:
<%= #males.each do |user| %>
...
<% end %>

Link in controller to my view with Rails

I have a controller and I need to make a link to my view:
#projeto.atividades.each do |a|
#mapa[:tasks] << {
id:a.id,
name:<%= link_to a.descricao, edit_atividade_path(atividade) %>
}
end
a.descricao = the word that I want to be the link.
edit_atividade_path(atividade) = my view.
What is the syntax?
Please try the following:
#mapa[:tasks] << {
id:a.id,
name: view_context.link_to(a.descricao, edit_atividade_path(atividade))
}
Also a point to remember is that in your controller you don't need the <% or %> scriptlets since its already ruby code.

Loop through data, store as array in Ruby on Rails

This is a very beginner question, but I've searched and can't find anything. I'm attempting to loop through an object, then store the information in an array (or object?) so that I can spit out a string of the items.
<% #da = [] %>
<% #report.data_items.each do |di| %>
<% if di.status == "Complete" %>
<% #da += di.url_metric.da %> #not sure how to append to the end of the array
<% end %>
<% end %>
Help? Should I use an array or object?
Seems that you're doing this in ERB template for some reason. Don't. Keep templates clear and simple. Do this kind of calculations in controller.
Here's a better version:
#da = #report.data_items.select {|di| di.status == 'Complete'}.
map{|di| di.url_metric.da }
#da = #report.data_items.collect{|di| di.url_metric.da if di.status == "Complete"}.compact
Here's shorted varian of what you're trying to accomplish:
#da = #report.data_items.select do |item|
item.status == "Complete"
end.map { |item| item.url_metric.da }.join(", ")

Getting Template::Error (Undefined method 'each') for nil:NIL Class

View:-
<% #dating_advices.each do |da| %>
<% if da['is-displayed'][0]['content'] == 'true' %>
<div class="dating_advice">
<h4><%= da['title'][0] %></h4>
<p><b><%= da['author'][0] %></b></p>
<p><%= da['content'] %></p>
</div>
<hr>
<% end %>
<% end %>
Controller:-
def dating_advices
#current_menu = "MatchMasters"
logger.debug "*** Current site id: #{#current_site.id}"
##hide_quick_search = true
#passed_args = {
'event_action' => 'ws',
'site_id' => #current_site.site_id
}
result = call_dating_advices_ws(#passed_args)
if result && result['errorcode'][0] == 'success'
#dating_advices = result['payload'][0]['payload']
end
end
Now when I click on dating advices on my webpage it gives an error"Getting Template::Error (Undefined method 'each') for nil:NIL Class"
You probably didn't get any #dating_advices -- which would mean you're calling each on an instance var that doesn't exist.
The way your controller is written, #dating_advices is never defined if the result variable is not defined.
You could quickly patch it with a #dataing_advices = [] (or a hash -- anything with an .each method) and figure out why your controller is failing.
You could do something like
if result && result['errorcode'][0] == 'success'
... your dating advice code
else
raise result
(or #dating_advice = {})
end
basically you need to always defined #dating_advice OR you need to handle that value not being defined in your view.

Resources