Obecny trend / dobra praktyka w pisaniu JS, czyli tzw. unobtrusive javascript, separuje kod widoku (szablon erb/haml) od podpinanego kodu javascript. Poza oczywistymi zaletami ma to jedną wadę: nie sposób w kodzie javascript mieć dostęp do zwyczajnie dostępnych w widokach helperów, zwłaszcza ścieżkowych.
Przykład kodu mieszanego, w którym można:
<%= check_box_tag "images[#{i.id}]", "mark", false, :onchange => "new Ajax.Request('#{mark_image_path(i)}', {asynchronous:true, evalScripts:true, method: 'get'}); " %>
W unobtrusive nie da rady, bo jest wykonywany poza kontekstem renderowania widoku:
<%= check_box_tag "images[#{i.id}]", "mark", false %>
function activate_image_checkboxes_for_marking()
{
$$('#images input[type=checkbox]').each(function(cbox) {
cbox.observe('change', function(ev) {
new Ajax.Request(I_CO_TERAZ_GOŚCIU, {asynchronous:true, evalScripts:true, method: 'get'});
return false;
});
});
}
Zakładając, że nie chcemy na pałę składać ścieżki z poziomu javascriptu (fuj!), możliwe są dwa obejścia tego braku:
- Element siostrzany: każdemu elementowi (np. check_boxowi) dorzucamy “siostrzany” hidden_field, z odpowiednim name, id oraz wartością równą stringowi (np. ścieżka z RESTowego helpera), z którego ma skorzystać javascript.
Podobny patent stosowany jest przez railsy do obejścia problemu z “niewysyłanymi” wartościami niezaznaczonych checkboxów przez przeglądarki. - (mój ulubiony) Ekstra atrybut: HTML i JS/Prototype łykną sporo, także dodanie checkboxowi ekstra atrybutu, z którego sobie skorzystamy w javascripcie:
<%= check_box_tag "images[#{i.id}]", "mark", false, :mark_path => mark_image_path(i) %>
I potem można wygodnie skorzystać z prototype’owego readAttribute:
function activate_image_checkboxes_for_marking()
{
$$('#images input[type=checkbox]').each(function(cbox) {
cbox.observe('change', function(ev) {
new Ajax.Request(cbox.readAttribute('mark_path'), {asynchronous:true, evalScripts:true, method: 'get'});
return false;
});
});
}