2009-04-24 11 views
1

J'ai deux petits problèmes structurels que je ne suis pas sûr de savoir comment gérer compte tenu de mon relative newbie-ness avec RoR.Comment puis-je réduire ce code Ruby/Rails très répétitif?

Première question: Dans un de mes vues, j'ai le code qui ressemble à ceci:

<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> 

Est-il possible de refactoriser cela pour que je ne dois itérer une fois sur une liste des différents types de fruits, et avez les <li> appropriés être générés automatiquement? Modifier: J'ai oublié d'ajouter que @apples, @oranges, etc., pourrait être nil. Existe-t-il une façon idiomatique de gérer cela?

Deuxième question: Dans mon contrôleur, j'ai le code qui ressemble à ceci:

@apples = Apple.find(:all) 
@apples.each { |apple| apple.do_stuff(:xyz) } 

@bananas = Banana.find(:all) 
@bananas.each = { |banana| banana.do_stuff(:xyz) } 

# ... &c 

Comme vous pouvez le voir, la même opération est invoquée à plusieurs reprises exactement de la même manière. Y at-il un moyen de raccourcir cela à quelque chose comme [Apple.find(:all), ...].each { |fruit| ... } et avoir ce travail à la place?

Merci beaucoup pour votre aide!

Répondre

5

Je ferais cela dans une aide

def fruit_size(fruit) 
    list = @fruits[fruit] 
    return if list.empty? 

    content_tag(:li, "#{list.size} #{fruit}") 
end 

Et ceci dans la vue:

<% ["apples", "oranges", "bananas", .....].each do |fruit| %> 
    <%= fruit_size(fruit) 
<% end %> 

Dans votre contrôleur:

@fruits = {} 
["apples", "oranges", "bananas", ......].each do |fruit| 
    @fruits[fruit] = fruit.classify.constantize.find(:all).each {|record| 
    record.whatever_here 
    end 
end 

Il est logique de stocker tous les éléments dans un hachage, @fruits, de sorte que vous n'avez pas besoin d'utiliser instance_variable_get et autres. Vous pouvez également définir ce tableau quelque part, de sorte que vous n'ayez pas à le répéter dans le contrôleur et dans la vue. Faisons semblant d'avoir un modèle de fruit.

class Fruit < ActiveRecord::Base 
    FRUITS = ["apples", "oranges", "bananas", ....] 
end 

Ensuite, utilisez fruits :: fruits dans la vue et le contrôleur.

+0

Merci beaucoup pour votre réponse. C'est semblable à ce que j'ai fini par faire. J'ai effectivement un modèle Fruit, et Apple, Banana, et al., Tous en dérivent. Mais je voulais juste appeler "do_stuff" sur certains types de fruits, pas tous. Woot! –

0

Pour la première partie:

@li = '' 
    [@apples, @oranges, @bananas, @grapefruit].each{|fruit| 
     @li << "<li>#{fruit.size}</li>"} 

    <ul style="list-style-type: circle"> 
    <%[email protected]%> 
    </ul> 
0

Vous pouvez réellement le faire assez simplement.

Dans votre contrôleur:

def whatever 
    @fruits = { 
    :apples => Apple.find(:all).each{ |a| a.do_stuff(:xyz) }, 
    :bananas => Banana.find(:all).each{ |a| a.do_stuff(:xyz) } # ... 
    } 
end 

À votre avis:

<% @fruits.each |k, v| %> 
    <li><%= v.nil? ? 0 : v.size %> <%= k.to_s %></li> 
<% end %> 

Bien que vous voudrez peut-être examiner si do_stuff est quelque chose qui pourrait être fait au moyen d'un viseur plus complexe, ou par la portée du nom .

Questions connexes