(view original Railscast)
Other translations:
Rails 3 özelliklerini incelediğimiz serinin bu bölümünde unobstrusive Javascript'in kullanımını inceleyeceğiz. Unobtrusive Javascript ile web uygulamasında javascript kod ile içeriği birbirinden CSS de olduğu gibi ayrılır. Unobtrusive Javascript'i Rails'de kullanmaya başlamadan önce basit bir HTML döküman içinde kullanalım.
Aşağıdaki ekran görüntüsü üzerinde bir link olan bir web sayfasını gösteriyor. Link tıklandığında Javascript alarm popup açılır ve "Hello world!" mesajı verir.
Bu sayfanın HTML kodu şuna benzer:
<!DOCTYPE html> <html> <head> <title>UJS Example</title> </head> <body> <h1><a class="#">Sayfada bir linkimiz var ve onclick özelliğine de bir Javascript kod yazılmış. Script HTML içinde birleşik olduğundan unobtrusive değildir ve iyi bir şey değildir, çünkü içerik ve kod birbirine karışıyor. 1990'ların sayfalarında CSS olmadığı için <font> tag'i ile yazı görünümü değiştirilirdi, sayfada yüzlerce bunlardan olurdu. Tarayıcılar CSS kullanmaya başlayınca stil bilgileri stylesheet dosyalarında toplanmaya başladı ve hem değişiklik yapılması kolaylaştı hem daha anlaşılır oldu.
Aynısı Javascript'e de uygulanabilir. Küçük küçük Javascript kod parçaları HTML tagların özellikleri içinde yazılırsa değişiklik yapmak zorlaşır. Javascript'i ayrı bir dosyaya koyunca tekrarlayan kodlar azalır, düzenlemeler kolaylaşır ve karmaşık uygulamaları üretmek ve debug kolaylaşır.
Örneğimizi nasıl unobtrusive yapacağız? Ana adım, onclick özelliğindeki Javascript'i ayrı bir dosyaya taşımak ve bunun için bir Javascript framework kullanacağız. Burada JQuery ile elemanların olaylarını algılayacağız. Önce sayfanın değişmişini bir görelim sonra açıklayalım.
<!DOCTYPE html> <html> <head> <title>UJS Example</title> <script src="/img/spacer.gif">İlk Dikkat çeken nokta Javascript'i daha önce söylediğimiz gibi ayrı bir dosyaya çıkarmadık. Bunu sadece burda gösterim için yaptık.
Body içindeki elemanın
onclick
özelliğini kaldırıp ona birid
verdik. Bu sayede hedefe JQuery üzerinden bir bağlantı yapabiliriz. Daha sonra head bölümünde JQuery kütüphanesini yüklüyoruz ve bunun altında dış dosyaya koyacağımız script görünüyor. Script JQuery'nin $ fonksiyonunu bir fonksiyon argümanı ile çağırıyor. Argümandaki bu fonksiyon sayfa DOM yüklemesinde çağrılır. Bu fonksiyon JQuery ile elemanı id'sinden bulur ve click olayına bir fonksiyon bağlar. Bağlanan fonksiyon ise bir alert ile mesaj verir ve geriye false dönerek link bağlantısına gidilmesini engeller.Eğer sayfayı şimdi tazelersek aynen bir öncekinin yaptığını yapacaktır. Tıklanınca bir alarm verecektir.
Burda çok iş yapmamıza rağmen karşılığında pek bir şey elde etmedik. Burada Unobtrusive Javascript avantajlarını pek göremedik tek satır Javascript yerine 6 satır oldu. Bu örnek sadece Unobtrusive Javascript'in mantığını anlatmak için yapıldı. Unobtrusive Javascript'in avantajı sayfadaki Javascript sayısı arttıkça ortaya çıkmaya başlar. Tüm Javascript kodlarını ayrı bir dosyada tutmak sayesinde tekrarlamaların önüne geçilmeye başlanır.
Bu yaklaşımın bir sorunu var. JavaScript genellikle statik bir dosyaya yazılıyor. Bu durumda satır içine yazmadığımıza göre nasıl server tarafı dinamik JavaScript ekleyebileceğiz?
HTML 5 ile birlikte artık ısmarlama verileri ilgili eleman tag içine özellik olarak koyabiliyoruz. Bunlar aynı diğer özellikler gibi yazılıyor, tek farkları
data-
ile başlamaları. Mesela tıklanınca verilecek mesajı özellikte saklamak için şöyle yazın:<a class="#" id="alert" data-message="Hello from UJS">Click Here</a>
JavaScript'de alert satırını mesajı bu yeni özellikten alacak şekilde değiştirelim:
$(function () { $('#alert').click(function () { alert(this.getAttribute('data-message')); return false; }) });Eğer sayfayı tazelersek linki tıklayınca özeliikten gelen mesajı alabiliriz.
Rails 3 Data Özelliklerini Nasıl Kullanır
Rails 3 bu ısmarlama data özellikler ile veriyi JavaScript'e gönderir. Şimdi bunun bir Rails 3 uygulamasında nasıl olacağını inceleyelim. Uygulamamız içinde arama yapılabilecek ürünlerin listesi bulunan basit bir e-alışveriş uygulaması. Ayrıca ürünü düzenlemek ve silmek için de linkler var , ama silmek için olan çalışmıyor gibi.
Bu Rails 3 uygulamalarında sık karşılaşılan bir sorundur. Eğer eski bir versiyon uygulamayı upgrade ediyorsanız, JavaScript'lerin çalışmaması çok karşılaşılan bir durumdur.
Görsel dosyasındaki kod "Destroy" linkini standart link_to metodunu kullanarak üretir. :confirm opsiyonu ile bir JavaScript
confirm
alarmı üretilir ve:method
opsiyonu da:delete
olarak ayarlanmıştır. Böylece link tıklanınca GET yerine DELETE metoduna çağrı yapılacaktır./app/views/products/show.html.erb
<%= link_to "Destroy", @product, :confirm => "Are you sure?", :method => :delete %>Burada enteresan olan bu kodun ürettiği HTML kod:
<a class="/products/8" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Destroy</a>Rails 2'de destroy link oluşturmak için
link_to
kullanınca bir sürü JavaScript ileconfirm
diyaloğu oluşturuluyor ve bir form ile DELETE ya da PUT çağrısı yapılıyordu. Rails 3 koduna bakarsanız daha temiz ve daha önce gördüğümüz HTML 5 data özelliklerini kullanıyor. Onay mesajını içeren birdata-confirm
ve metodu saklayan bir data-method özelliği.Linkin çalışmama sebebi head bölümünde JavaScript fonksiyon tanımlanmadığı için , standart bir GET çağrısı yapılacak ve silme işlemi DELETE çağrılmadığı için gerçekleşmeyecektir.
Bunu düzeltmek için uygulamanın layout dosyasına aşağıdaki iki satırı eklemeliyiz:
/app/views/layouts/application.html.erb
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
Yukardaki ilk satır tanıdık gelecektir. Bir Rails uygulaması için standart JavaScript dosyaları yüklüyor. İkinci satır DELETE işlemlerini gerçekleştirmek için gerekli yetkilendirme bilgilerini taşıyan iki metatag üretir. Değişim sonrası sayfayı tazelersek üretilen iki satırı göreceğiz.
<script src="/img/spacer.gif">Şimdi sayfada tüm JavaScript dosyalara erişim ve cross-site saldırılara karşı tüm önlemler mevcuttur. Böylece PUT ve DELETE çağrılarının bir hacker tarafından değil doğru kişiden geldiğinden emin olabiliriz.
Bu iki satırla beraber bizim destroy linkimiz beklendiği gibi çalışacaktır.
Bir Arama Formuna AJAX Eklemek
Sonra index sayfasındaki arama formunu değiştirerek GET çağrısı yerine AJAX kullanmasını sağlıyacağız.
Index
görselindeki form için kod aşağıda gösteriliyor:/app/views/products/index.html.erb
<% title "Products" %> <% form_tag products_path, :method => :get do %> <p> <%= text_field_tag :search, params[:search] %> <%= submit_tag "Search", :name => nil %> </p> <% end %> <div id="products"> <%= render @products %> </div> <p><%= link_to "New Product", new_product_path %></p>Burada kullanılan form episode 37. de gösterilen teknikle arama yapmak içindir. Rails'in önceki versiyonlarında formun AJAX ile çalışması için
form_tag
ileform_remote_tag
değiştirilirdi. Bu metod şimdi sakınmaya çalıştığımız satır içi JavaScript'ten bir sürü üretecektir.Rails 3 ile beraber birçok remote helper metod artık kullanılamaz oldu. Eğer kullanmak istersek Prototype Legacy Helper plugin install etmeliyiz.
Bunu
form_remote_tag
ile yapmak yerine yineform_tag
, kullanıyoruz ama yeni bir parametre ile:remote
./app/views/products/index.html.erb
<% form_tag products_path, :method => :get, :remote => true do %> <p> <%= text_field_tag :search, params[:search] %> <%= submit_tag "Search", :name => nil %> </p>
<% end %>Bu
:remote
parametresi ayrıcalink_to
,button_to
veform_for
gibi diğer helper metodlarla da kullanılabilir. Eğer sayfayı tazeleyip kaynağı incelersek yeni form kodumuzun nasıl çalıştığını görürüz.<form action="/products" data-remote="true" method="get"> <p> <input id="search" name="search" type="text" /> <input type="submit" value="Search" /> </p>
</form>Form elemanı aynı ama bu sefer yeni bir
data-remote
özelliği var. Satır içi JavaScript yok, yeni özellikrails.js
içindeki JavaScript'e formun AJAX yoluyla gönderildiğini anlatmaya yeter.Sırada AJAX çağrısını işleyecek kodu yazmak var. Ürünlerin listesi bir
div
içersinde bulunuyor. Budiv
içeriğini update ederek sadece aranan ürünleri gösterebiliriz. FormProductController
’inindex
eylemine gönderiliyor ve tüm ihtiyacımız olan JavaScript isteklerini işleyecek birindex.js.erb
dosyası eklemek.
Bu kalıp dosyaya tarayıcıya dönüldüğünde çalışmasını beklediğimiz herhangi bir JavaScript kodu yazabiliriz. Yeni kalıp dosyamızdaki kod div içeriğini sonuca göre update edecek.
/app/views/products/index.js.erb
$("products").update("<%= escape_javascript(render(@products))%>");
Sayfayı tazelediğimizde ve formun gönderme düğmesine tıkladığımızda arama AJAX çağrısı ile yapılacak ve URL değişmeyecektir.
İşte böyle, Rails 3 ile unobtrusive JavaScript sadece :remote parametresi kullanarak yapılıyor. AJAX çağrısına bir server bir JavaScript ile dönüş yapıyor ve o da div içeriğini değiştiriyor.
Frameworkları Değiştirmek
Bu bölümü uygulamamızın kullandığı JavaScript Framework'u nasıl değiştirceğimizi göstererek kapatacağız. Uygulamamız şu anda Prototype kullanıyor, bu Rails'in parçası olarak geliyor , fakat JQuery kullanmak istiyorsak ne olacak?
İlkönce uygulama layout'da yer alan şu satırı değiştirmeliyiz.
/app/views/layouts/application.html.erb
<%= javascript_include_tag :defaults %>
şöyle değiştirin:
/app/views/layouts/application.html.erb
<%= javascript_include_tag "ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", "jquery.rails.js" %>Listedeki ilk dosya Google üzerinden JQuery'nin son versiyonu. Bu tek başına yeterli değil
rails.js
dosyasının JQuery eşleniğini de yüklememiz gerekiyor, yoksa unobtrusive uygulamalarımız çalışmaz. Bu dosyanın orjinalini jquery-ujs project on Github adresinde bulabilirsiniz. Bu projede indirip projemizde kullanabileceğimiz birrails.js
dosyası vardır. Bu dosyayı indirip uygulamamızın/public/javascripts
klasörüne koyalım ve adınıjquery.rails.js
yapalım ve bu dosya uygulamamızın Rails tarafından kullanılan unobtrusive JavaScript işlerini gerçekleştirir.Şimdi daha önce uygulamamıza bizim eklediğimiz Prototype'a göre olan JavaScript'imizi JQuery'ye uygun olacak şekilde değitirmek zorundayız. Daha önce ürettiğimiz
index.js.erb
dosyasında küçük bir değişiklik yapacağız. Div seçicisi olarakproducts
yerine#products
kullanarak ve Prototype'ınupdate
metodu yerine JQuery eşleniği olanhtml
kullanarak./app/views/products/index.js.erb
$("#products").html("<%= escape_javascript(render(@products))%>");
Uygulamamız artık kaputun altında Prototype yerine JQuery kullanıyor.
Estetiğin Kaybolması
Eğer bir kullanıcı JavaScript izin verilmeyen bir tarayıcı kullanarak uygulamamızı açarsa biraz estetik kaybı olacaktır. Buton normal bir GET çağrısı yapacaktır. Ürün silme linki de çalışmayacaktır. Bu genel bir problemdir, HTML linkleri sadece GET çağrıları yapabilir, bu yüzden Rails DELETE için biraz JavaScript kullanır. Bunun önüne geçmek için bir yöntem
button_to
kullanmaktır ama çirkin görünecektir, bu yüzden link olarak kalmalı. Tercih edilebilecek bir teknik olarak episode 77 de JavaScript izin verilmeyen tarayıcılarda silme işlemi için başka sayfa açan örnek var.Previous episode Next episode