Kwiatki w kodzie produkcyjnym

15-03-2011   |   Krzysiek   |   Bez kategorii   |   Komentarzy: 721

Czasami są takie chwile, kiedy to w głowie pojawia się myśl „co ja tutaj robię”… Dzisiejsze zwątpienie opanowało mnie w momencie, gdy moim oczom ukazał się widok, jakże wspaniałego kwałka kodu, istniejącego na środowisku produkcyjnym od prawie 2. lat… Od czasu do czasu, generował on jakieś „mało istotne” błędy ConcurencyException, którymi nikt się nie przejmował, bo przecież aplikacja działała…

for(VipRetentionGPProduct product : products){
   ...
   if( costam ) {
     products.remove(product);
   }
   ...
}

Niewtajemniczonym i niedouczonym chciałbym wyjaśnić, że usuwanie elementów z list w trakcie ich procesowanie możliwe jest jedynie przy wykorzystaniu iteratorów (nie bójcie się z nich korzystać, to nic strasznego):

for(Iterator<VipRetentionGPProduct> i = products.iterator(); i.hasNext();){
  VipRetentionGPProduct product = i.next();
  ...
  if( costam ) {
    i.remove();
  }
  ...
}

Napawającym optymizmem jest fakt, że to jeden z nielicznych wyjątków różnych od NullPointeException z jakimi spotykam się na co dzień.

Proste rozwiązania…

23-11-2010   |   Krzysiek   |   Bez kategorii   |   Komentarzy: 723

Kilka dni temu dostałem bardzo błahe zadanko polegające na dodania kilku wpisów do bazy DB2 (tak, doskonale wiem, że w oracle można łatwiej). Prosty insercik i po sprawie, ale… okazało się że jedno z pól varchar powinno zawierać dokładny czas wykonania operacji następującym YYYYMMDDHH24MISSSSS. Niestety wyszukiwanie metod które pozwoliłyby przekonwertować timestamp na varchar wg ustalonego wzorca, zakończyło się fiaskiem i jednym wyjściem pozostało stworzenie własnej konwersji.

# przykład 1
CONCAT(
    CONCAT(
        CONCAT(
            CONCAT(
                CONCAT(
                    CONCAT( substr(digits (year(current_timestamp)), 7), 
                        substr(digits (month(current_timestamp)), 9) ), 
                    substr(digits(day(current_timestamp)), 9)), 
                substr(digits (hour(current_timestamp)), 9)), 
            substr(digits (minute(current_timestamp)), 9)), 
        substr(digits (second(current_timestamp)), 9)), 
    substr(digits (microsecond(current_timestamp)), 5, 3)
)
 
# przykład 2
SUBSTR(CHAR(CURRENT_TIMESTAMP),1,4) ||     
SUBSTR(CHAR(CURRENT_TIMESTAMP),6,2) ||     
SUBSTR(CHAR(CURRENT_TIMESTAMP),9,2) ||
SUBSTR(CHAR(CURRENT_TIMESTAMP),12,2) ||
SUBSTR(CHAR(CURRENT_TIMESTAMP),15,2) ||
SUBSTR(CHAR(CURRENT_TIMESTAMP),18,2) ||
SUBSTR(CHAR(CURRENT_TIMESTAMP),21,5)

Czy naprawdę nie ma prostszego rozwiązania?

Wyświetlanie wartości obiektu w label’u

09-11-2010   |   Krzysiek   |   Programowanie, Rails   |   Komentarzy: 2

W pierwszym poście chciałbym się z Wami podzielić problemem, z jakim przyszło mi się zmierzyć kilka tygodni temu podczas tworzenia mojego pierwszego projektu w technologii rails. Głównym zamierzeniem było zbudowanie zagnieżdżonej formy z komentarzami, która oprócz dodawania opinii do zdjęcia, pozwalałaby także ocenić je według całej listy przypisanych do niego kryteriów oceny.

# code: 1
class Opinion < ActiveRecord::Base
  belongs_to :foto
  has_many :marks
  has_many :criteria, :through => :marks
  accepts_nested_attributes_for :marks
 
  def self.new_with_marks(foto)
    opinion = Opinion.new
    foto.criteria.each do |criterium|
      mark = Mark.new
      mark.criterium = criterium
      opinion.marks.push mark
    end
    opinion
  end
end
# code: 2
<% form_remote_for [foto, Opinion.new_with_marks(foto) ], :html => { :id => 'new_opinion_form' } do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :comment %><br />
    <%= f.text_field :comment %>
  </p>
  <% f.fields_for :marks do |builder, index| %>
    <p>
      <%= builder.hidden_field :criterium_id %>
      <%= builder.label /* nazwa kryterium */ %>
      <%= builder.text_field :note %>
    </p>
  <% end %>
  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>

O ile zbudowanie takiej formy nie było jakimś wielkim wyczynem, tym bardziej, że jest to bardzo dobrze przedstawione w jednym z railscast’ów, to wyciągnięcie nazwy kryterium criterium_name z zagnieżdżonego obiektu builder (linia #2.9), i wyświetlenie w label’u doprowadziło mnie niemal do szału. Przecież to nie możliwe by tak ‘wspaniały’ freamework nie oferował tak podstawowej rzeczy out of the box. Po wielogodzinnej furii, czytaniu forów, blogów, głupich porad itp… kombinowaniu (dawno już nie patrząc na estetykę kodu) jak rozwiązać tą nie do końca banalną zagwozdkę, udało mi się wypracować taki mały, ale jakże niesamowity workaround (linia #3.12):

# code: 3
<% form_remote_for [fotos, o = Opinion.new_with_marks(fotos) ], :html => { :id => 'new_opinion_form' } do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :comment %><br />
    <%= f.text_field :comment %>
  </p>
  <% index = 0 %>
  <% f.fields_for :marks do |builder| %>
    <p>
      <%= builder.hidden_field :criterium_id %>
      <%= builder.label :note, o.marks[index].criterium.name %>
      <%= builder.text_field :note %>
    </p>
    <% index += 1 %>
  <% end %>
  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>

Po pewnym czasie okazało się jednak, iż największym problemem była oczywiście niewiedza, zarówno moja jak i wujka google’a. Railsy dostarczają bowiem bardziej cywilizowanego sposobu do wykonywania tego typu manewrów. Z obiektu formularza możemy dobrać się do źródłowego obiektu wywołując object (linia #4.5).

# code: 4
<% f.fields_for :marks do |builder| %>
  <p>
    <%= builder.hidden_field :criterium_id %>
    <%= builder.label :note, builder.object.criterium_name %>
    <%= builder.text_field :note %>
  </p>
<% end %>

site tracking with Asynchronous Google Analytics plugin for Multisite by WordPress Expert at Web Design Jakarta.