Ostatnio przeglądając kod Redmine’a natknąłem się na fajny kawałek kodu. Nigdy się nad tym nie zastanawiałem i w zasadzie, nigdy zbytnio nie potrzebowałem.

Jak za pomocą linka, zaktualizować wybrany atrybut instancji modelu?

Zazwyczaj do aktualizacji danej instancji korzystam z edit’a oraz forma odpowiedniego do tego. Dzisiaj jednak nadarzyła się  ku temu okazja.

Mam w systemie model o nazwie Cron który odpowiada za cykliczne odpalanie komend/metod które są w nim yieldowane. Np:

    Cron.backup{
      # Wykonaj nową kopię zapasową
      Backup.create
      # Usuń stare kopie zapasowe
      Backup.sweep(Setting::Cron.backup_lifetime)
    }

Powyższy “cron” o nazwie backup odpala się co 7 dni wykonując kopię zapasową systemu. Usuwa przy okazji kopie starsze niż backup_lifetime. Z ciekawostek warto wspomnieć, że dzięki “fajności” Rubiego, mogłem napisać sobie w bardzo prosty sposób własne mapowanie, nie po kolumnach a po wierszach. Właśnie dzięki temu metody modelu Cron są generowane dynamicznie. Ale to jest temat na oddzielną notkę.

Wracając do sedna sprawy. Model Cron korzysta z pola updated_at aby określić kiedy Cron był ostatnio odpalany. Jeśli było to dawniej niż zadana w instancji częstotliwość – uruchamia kod yieldowany.

Problem pojawił się kiedy chciałem dorobić “wymuszone” odpalenie instancji Crona. Najprostszą metodą do zrobienia tego, było wyedytowanie updated_at i nadanie mu wartości np. 1.year.ago. Rozwiązać można to było tworząc metodę w stylu force. Nie byłoby to jednak zgodne z RESTem. Bardzo fajnie rozwiązano to w Redminie. Mianowicie tworzony jest link_to który zawiera wszelkie potrzebne informacje. Jak taki link wygenerować? Bardzo prosto:

link_to "Wymuś", cron_path(task, 'cron[updated_at]' => 1.year.ago), :method => :put

Metoda link_to stworzy nam link który zostanie zrealizowany przez metodę update na instancji modelu Cron. Dzięki dodaniu parametru:

'cron[updated_at]' => 1.year.ago

informujemy Railsy, że ma naszemu cronowi przypisać datę ostatniego wykonania na rok wstecz. Dzięki temu, przy najbliższej możliwej okazji, kod z Crona zostanie zrealizowany.