Dosyć często spotykam się z użyciem zmiennych lokalnych w widokach Rails’ów. W większości wypadków po dokładniejszej analizie okazuje się, że możliwe jest pozybycie się zmiennych lokalnych w widokach i zastąpienie ich np. wywołaniem metody czy utworzeniem specjalnego obiektu).
Dzisiaj przykład, z którym spotykam się dosyć często w kodzie pisanym przez świeżo upieczonych koderów Rails:
<% colour_message = nil %>
<% f.fields_for :widget_attributes do |waf| -%>
<% if waf.object.name.downcase =~ /colour\Z/ and colour_message.nil? %>
Standard colours are as follows:
Red
Light blue
<% colour_message = :shown -%>
<% end %>
<% end -%>
Tutaj zmienna colour_message została użyta do przechowania stanu wyświetlenia wiadomości (chodzi o to, że “Standard colours” powinna zostać wyświetlona tylko 1 raz, pomimo tego, że jest wołana w pętli (fields_for :widget_attributes możemy spokojnie zastąpić dowolną pętlą).
Czy można poprawić ten kod?
Korzystając z bloków, możemy napisać metodę helpera której zadaniem będzie wywołanie bloku tylko 1 raz niezależnie od tego ile razy ona sama zostanie wywołana:
widok:
<% f.fields_for :widget_attributes do |waf| -%>
<% if waf.object.name.downcase =~ /colour\Z/ %>
<% once do -%>
Standard colours are as follows:
Red
Light blue
<% end -%>
<% end %>
<% end -%>
[code=ruby]module ApplicationHelper
def once(name = “default”)
name = name.to_s
yield unless instance_variable_get("@_once#{name}")
instance_variable_set("@_once#{name}", true)
end
end[/code]
Dzięki tej metodzie, możemy pozbyć się zmiennej lokalnej w widoku i oczywiście wykorzystać ten wzorzec w innych widokach w aplikacji. Warto jeszcze dodać, że jeśli chcemy w jednym widoku skorzystać z “once” więcej niż 1 raz to musimy nazwać każde jej wywołanie, np:
[code=ruby]<% for i in (1…10) do -%>
<% once(:something) do -%>
# do something only once
<% end -%
<% end -%>
<% for i in (1…10) do -%>
<% once(:something_else) do -%>
# do something else only once
<% end -%
<% end -%>[/code]