Transformacja remote_function na AJAX w JQuery

W helperze mam:

def toggle_value(object) remote_function(:url => url_for(object), :method => :put, :before => "Element.show('spinner-#{object.id}')", :complete => "Element.hide('spinner-#{object.id}')", :with => "this.name + '=' + this.checked") end
widok:

<%= check_box_tag 'user[accept]', "1", @user.accept, :onclick => toggle_value(@user) %>

Teraz chcę to przerobić na ajax-a w jQuery, dodałem sobie AUTH_TOKEN wg: http://henrik.nyh.se/2008/05/rails-auth … ith-jquery
I próbuję:

jQuery('#user_accept').bind('click', function() { $.ajax({ async:true, type:'put', dataType:'script', success: function(){..}, error:function(request){ alert('Sorry, there was an error')}, url: ...??? }) })
Jakieś podpowiedzi jak zdefioniować ‘url’-a i resztę…?

Zmodyfikowałem ajax-a:

jQuery('#user_accept').bind('click', function() { jQuery.ajax({ async:true, url:'/users/2', type:'POST', data: { _method:'PUT', user: { accept: jQuery(this).is(':checked') }}, success: function(){alert('ok')}, error:function(request){ alert('Sorry, there was an error!!!')} }) return false })
Wysyła:

Processing UsersController#update (for 127.0.0.1 at 2009-10-08 21:48:04) [PUT] Parameters: {"authenticity_token"=>"...", "id"=>"2", "user"=>"[object Object]"}
Wszystko się zgadza z wyjątkiem object Object.
Czy jest potrzebna serializacja, żeby wysyłało “user”=>{“accept”=>“false/true”} …???

[quote=newman]Wszystko się zgadza z wyjątkiem object Object.
Czy jest potrzebna serializacja, żeby wysyłało “user”=>{“accept”=>“false/true”} …???[/quote]

{ data: { "user[accept]": jQuery(this).is(':checked') } }

Dzięki! :slight_smile:
Alert pokazał przyjemne “ok”.
Dziwne, trafiłem na kilka postów na “zagramanicznych” forach i wszędzie kombinują z serializacją, wysyłaniem przez JSON etc. …trochę mnie to źle ukierunkowało.

Zachciało mi się jQuery :wink:
Na Amazonie trafiłem na książkę Rails i jQuery (nie pamiętam w tej chwili tytułu) - data publikacji: Feb 2010(!)

Zastanawiam się jak przekazujecie “id” obiektu do ajax-a.
Czy wrzucacie to w atrybut check box-a (w moim przypadku)? np id=“cb_2”, czy są inne, lepsze sposoby?

[quote=newman]Zastanawiam się jak przekazujecie “id” obiektu do ajax-a.
Czy wrzucacie to w atrybut check box-a (w moim przypadku)? np id=“cb_2”, czy są inne, lepsze sposoby?[/quote]
Jest dużo możliwości, ale jeżeli chodzi o samo id, to tak najłatwiej. Masz metodę dom_id, a w javascripcie możesz napisać helper, który wyciąga id z każdej tego typu nazwy:

  "kilkuczlonowe_id_1".split("_").slice(-1)[0];

@drogus: dzięki za wskazówki!

Mam kolejne pytanie. Po aktualizacji danych, która idzie przez ajax-a, chciałbym odświeżyć fragment strony gdzie te dane są wyświetlane. Próbowałem:

format.js { render :partial => ...

“render” jest poprawnie wywoływany, ale nic się nie dzieje! Zmieniłem to na “redirect” i też nic mimo, że w logach widzę, że wszystko przechodzi bezbłędnie …???

Mogę się mylić, ale czy nie powinno być coś w stylu: format.js { page.replace_html 'tu id diva, czy co tam masz', render :partial => ...

@sebcioz: pewnie to miałeś na myśli :slight_smile:

format.js { render :update do |page| page.replace_html "id_div", :partial => "..." end }
Podobnie jak poprzednio, wszystko chodzi bez błędów, ale dane na stronie nie odświeżają się :-/

... success : function(response) { $("#zmieniany_div").html = response; alert("Ok!"); }, ...
A w kontrolerzerender.js :partial => 'costam'
Wszystko raczej po stronie application.js. replace_html jest helperem od Prototype, a nie jQUery(chyba, ze ktos mnie wyprowadzi z błędu, że to się inaczej robi jednak). Z tego co wiem to jest jakiś plugin, który zastępuje helpery standardowe na takie, które korzystają z jQuery.

masz rację, nie zauważyłem, że nie korzysta z prototype’a…

@newman radze oglądnąć screencast http://railscasts.com/episodes/136-jquery - dobrze opisane podstawy, w sam raz na początek

EDIT: co do tego pluginu - istnieje, nazywa się jRails, aktualnie nierozwijany (chyba, w każdym razie stronę trzeba z cache’a google otwierać) http://209.85.129.132/search?q=cache:CO2fzAs4a2UJ:www.ennerchi.com/projects/jrails+jquery+rails&cd=1&hl=pl&ct=clnk&gl=pl&client=opera

@Yax: działa!
mała poprawka:

$("#zmieniany_div").html(response);

teraz jest wszystko po stronie app.js i to chciałem osiągnąć.

Wszystko ładnie pięknie, ale czasami robienie każdej odpowiedzi po stronie klienta jest czasochłonne i trudne. Nie po to używamy railsów, żeby nie korzystać z ich dobrodziejstw.

Przy używaniu javascripta najlepszy moim zdaniem sposób o zwykłe templat’y js.erb. Czyli:

respond_to do |wants| wants.js # renderuje się domyślny widok czyli create.js.erb end
a w create.js.erb np:

  $("#posts").append(<%=js render(:partial => @post) %>);

przy czym js to helper:

def js(data) if data.respond_to? :to_json data.to_json else data.inspect.to_json end end
Akurat ten przykład jest banalnie uzyskać i bez js.erb, ale jest dużo momentów, w których ten sposób się bardzo przydaje.

newman: jeżeli ten kod nie wykonuje się, to znaczy, że coś masz pewnie nie tak z zapytaniem ajaxa, najlepiej wklej kod jquery, którego używasz.

@drogus: dzięki. Dużo mi to rozjaśniło. Poczułem power jQuery i pewnie dlatego chętnie przenoszę wszystko na tą stronę (“ciemną stronę …mocy” :wink:

Możliwe, że ten render na wstępie mi nie działał z innej przyczyny. Nie zamieściłem całego kodu bo sytuacja jest dość zagmatwana (możliwe, że problemem są “Nested Resources”) i bym musiał zbyt dużo kody wklejać, a wiem z doświadczenia, że krótszy post szybciej doczeka się odzewu (usability :wink:

Mam kolejne pytanie. W jQuery mam podpięty checkbox:

jQuery('#comment_1').bind('click', function() {...

Po wyrenderowaniu (render.js :partial…) i aktualizacji za pomocą:

... jQuery("#my_div").html(response);
…mój checkbox zawarty w tym renderowanym fragmencie przestaje działać…!?

Wrzucam cały kod funkcję podpiętą pod checkboxa

jQuery('#comment_2').bind('click', function() { var ids = 2; var c_ids = 2; busy.show(); var ch = jQuery(this).is(':checked'); jQuery.ajax({ async:true, url:'/users/' + ids + "/comments/" + c_ids, type:'POST', data: { _method:'PUT', "comment[accept]": ch }, success: function(response){ jQuery("#my_list").html(response); }, error:function(request){ alert('Błąd!')} }) return false })
Co więcej nawet tego typu handler przestaje działać po renderowaniu:

jQuery("#add-comment").click(function(){ jQuery("#add-comment").hide(); })
Gdzie robię błąd …?
Wygląda na to, że po każdym renderze muszę w tym odświeżonym fragmencie ponownie przypisać wszystkie akcje w jQuery. Może jest jakiś sprytny reload? :wink:

Zmieniłem podejście i wrzuciłem plik update.js.erb, a w nim:

alert("works!");

We view teraz mam:

format.js

W application.js mam:

jQuery.ajaxSetup({ 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")} })
…ajaxSetup mialem to już wcześniej, żeby nie było wątpliwości :wink:
dalej

jQuery('#comment_2').bind('click', function() { var ids = 2; var c_ids = 2; var ch = jQuery(this).is(':checked'); jQuery.ajax({ async:true, url:'/users/' + ids + "/comments/" + c_ids, type:'POST', data: { _method:'PUT', "comment[accept]": ch }, success: function(response){ alert('ok!') }, error:function(request){ alert('Błąd!')} }) return false })
Alert w update.js.erb nie jest wykonywany …??

Mam!
Zabrakło mi takiej magicznej linijki w jQuery.ajax:

dataType: 'script'

Chodzi!

nie chcę dodawać nowego tematu o jRails więc podepnę się tutaj… Próbuję przepisać cos żeby używało jQuery. Mam zainstalowany plugin JRails i dodany w head,
link wygląda tak

<%= link_to "Add option", new_question_option_path %>

w kontolerze mam

def new @question_option = QuestionOption.new respond_to do |format| format.js end end
jednak co bym nie umieścił w new.js.erb to wypluwa mi to jako zwykły tekst zamiast odpalic tam javascript czy metody jQuery. Może coś w routes brakuje ?

[quote=Artur79]<%= link_to "Add option", new_question_option_path %>
[/quote]
link_to zawsze generuje normalnego linka, bez javascriptu. jRails nadpisuje helpery które użyawją domyślnie prototype tak aby uzywały jQuery. Czyli użyj:

<%= link_to_remote "Add options", ..... %>