İki Veri Arasında ki Benzerliğin Hesaplanması – Ruby

Bir RoR projesinde, iki farklı veritabanında bulunan ad-soyad ve kimlik numarası verilerinin birbirlerine ne kadar benzediğinin hesaplanması ve farklı veri setlerinin birbiriyle aynı olma olasılığının tespiti gibi bir ihtiyacım olmuştu.

Örneğin aşağıda ki iki veri birbirine ne kadar benziyor, bu kişiler gerçekten aynı kişiler olabilir mi hesaplamam gerekiyordu:

Bu hesaplamayı yapabilmek için Elasticsearch ve Ruby’nin marifetleri yeterli oldu. Elasticsearch’ün Ruby için sağladığı “records.each_with_hit” metodu ile herhangi iki veri birbirlerine ne kadar benziyor (yakınsıyor) kontrol edebilir ve benzerlik oranını 0-2 aralığında matematiksel olarak alabilirsiniz.

Örnek betik şu şekilde:

Betikte bulunan “1.2” değeri, tamamen benim istediğim yakınlık derecesini ifade etmekte. Daha yüksek yakınlığa sahip verileri tespit etmek için bu değeri arttırabilir, daha geniş bir aralık almak için azaltabilirsiniz. Betik çalıştıktan sonra şöyle bir çıktı veriyor:

Kolaylıklar.

Nginx'e Rails Uygulamasının Deploy Edilmesi

Phusion Passenger üzerinde bir Rails (veya herhangi bir Rack uygulaması) deploy edebilmek için uygulamanın bulunduğu dizinde üç dosyanın bulunması zorunludur:

  • config.ru dosyası
  • public/ klasörü
  • tmp/ klasörü

Yani /herhangi/bir/klasor/‘de bulunan Rack uygulamanızın minimum görünümü şu olmalıdır:

Uygulamanız çalışabilmesi için nginx konfigürasyon dosyanızı (/etc/nginx/nginx.conf) yapılandırmanız gereklidir:

Daha sonra nginx ve passenger’ı restart etmelisiniz:

En temel düzeyde bir Rails uygulaması bu şekilde deploy edilebilir. Uygulamanın kurulu için, bulunduğu dizine düşerek, aşağıdaki adımları takip edin.

Bundle et:

Uygulama config dosyasını düzenle:

Dosya izinlerini güncelle:

Uygulamayı kur:

Son olarak:

Hepsi bu kadar.

Nginx ve Passenger Kurulumu – Ubuntu ve Debian

Nginx ve Passenger Kurulumu

Nginx ve passenger kurulumu ile ilgili internette pek çok İngilizce döküman bulunuyor ancak bunların pek çoğu resmi Passenger dökümanında anlatılan yolların dışında yöntemler kullanmışlar. Bunları uygulayıp, ne gibi zorluklara yol açtığını gördüğüm için, Passenger ve Nginx’in tüm dökümanlarını baştan okuyup bu yazıyı hazırladım. Öncelikle sisteminizde Ruby ve Rails kurulu değilse rbenv aracını kullanarak kurulumu yapmanız gerekiyor.

Passenger tarafından Ubuntu ve Debian için official APT reposu sağlanmakta. Bu repoyu kullandığınızda hem kurulumu kolayca yapabilirsiniz hemde güncelleştirmeleri kolayca takip edebilirsiniz. Aşağıda anlatacağım adımları takip ettiğiniz taktirde passenger-install-apache2-module veya passenger-install-nginx-module araçlarını kullanmanıza gerek kalmayacaktır.

İlk olarak PGP anahtarını sisteminize ekleyin:

Passenger reposu HTTPS’ten bağlantı kurduğu için sisteminize HTTPS desteğini kurun:

/etc/apt/sources.list.d/ klasörü altında passenger.list isminde bir dosya oluşturun ve kurulumu yapmak istediğiniz işletim sistemine uygun olarak aşağıdaki satırlardan sadece bir tanesini! ekleyin:

passenger.list dosyasının izinlerini düzenleyin ve paket listenizi güncelleyin:

Nginx paketlerini kurun:

Daha sonra, /etc/nginx/nginx.conf dosyasını düzenleyerek, passenger_root ve passenger_ruby değişkenlerini uncomment edin.

Önerdiğim şekilde Ruby kurulumunu rbenv aracı ile yaptıysanız, bu iki değişken şu şekilde olacaktır:

Nginx’i restart edin:

Şuan herşey yolundaysa nginx çalışıyor olmalıdır.

Passenger’ın çalışması için yapmamız gereken bir kaç şey kaldı:

Hepsi bu kadar. Şuan nginx ve passenger sorunsuz çalışıyor olmalı.

Nginx konfigürasyonu şurada bulunur:

Nginx hata logları şurada bulunur:

Deploy işlemleri ve Nginx konfigürasyonunu bir sonraki yazıda anlatacağım.

Rbenv ile Ruby ve Rails Kurulumu – Debian 7

Rbenv Kurulumu

Rbenv, RVM gibi ancak RVM’ye göre çok daha basit bir şekilde, birden çok Ruby versiyonunu birlikte kullanmak için geliştirilmiş bir araçtır. Sisteminizde tek bir Ruby sürümüne ihtiyaç duyuyorsanız dahi, rbenv ile kurulum yapmanızı öneririm.

Öncelikle rbenv’i /home/foo altına klonlayın:

Daha sonra PATH’e, rbenv değişkenlerini ekleyin:

Ruby sürümleri ve diğer şeyler için otomatik tamamlamayı etkinleştiren aşağıdaki komutu çalıştırın:

Terminalinizi yeniden başlatın. Daha sonra;

komutunu çalıştırdığınızda:

çıktısını görüyorsanız kurulum başarıyla tamamlanmış demektir.

Rbenv’in ruby-build eklentisini kurarak, Ruby kurulumu için ortamı hazır edelim:

Rbenv’in çalışma mantığı gereği, herhangi bir GEM kurduktan sonra her seferinde “rbenv rehash” komutunu çalıştırmamız gerekiyor. Ancak bu can sıkıcı bir iş olduğu için, bunun içinde bir eklenti yazmışlar. Bunu da sistemimize çekelim:

Rbenv kurulum işlemleri bu kadar. Şimdi Ruby’yi kuralım.

Ruby Kurulumu

Ruby için gerekli temel paketleri kurun:

Rbenv’de listelenen Ruby sürümlerine bakın:

Bunlardan kurmak istediğiniz sürümü kendiniz seçebilirsiniz. Ben bu yazının yazıldığı tarihteki en kararlı sürüm olan Ruby 2.1.5’i kullanacağım:

Herşey yolundaysa sisteminize Ruby kurulmuş olmalıdır. Rbenv ile, kurulan bu Ruby sürümünü ister sistem çapında, istersenizde uygulama çapında kullanabilirsiniz.

Sistem çapında bu sürümü kullanmak için:

Uygulama çapında kullanmak için, uygulamanızın olduğu dizine düştükten sonra, o dizin içerisinde:

komutlarını kullanabilirsiniz.

Kurulumu kontrol edin:

Rails Kurulumu

Rails kurulumunda özel bir durum bulunmamaktadır. GEM olarak kurmanız yeterlidir:

Kurulumunuz başarıyla tamamlandıysa “rails -v” komutu ile kurulmuş olan Rails sürümünü görebiliyor olmanız gerekir.

Debian ve Ubuntu – ElasticSearch Kurulumu

ElasticSearch kurulumu yapabilmek için öncelikle sisteminizde OpenJDK kurulu olmalıdır. Kurulum için: http://www.serhatdundar.com/debian-icin-openjdk-kurulumu

OpenJDK’yı kurduktan sonra ElasticSearch kurulumuna geçebilirsiniz.

Öncelikle GPG anahtarını ekleyin:

Aşağıda ki satırı /etc/apt/sources.list dosyanıza ekleyin:

Kurulumu gerçekleştirin:

Sistem başladığında elasticsearch hizmetinin de otomatik olarak başlamasını istiyorsanız:

veya manuel olarak elasticsearch’ü başlatmak için;

Şuan herşey yolundaysa ElasticSearch çalışıyor olmalıdır. Rails uygulamalarınızda ElasticSearch ile arama yapabilmek için modelinizde ElasticSearch’ü include etmeniz gerekir. Örneğin “User” modelimize bunu include edelim:

Ardından, arama yapacağınız controller action’unda (çoğunlukla index) ElasticSearch’ü çağırmanız gerekmektedir:

Rails console’dan elasticsearch’ün çalışıp çalışmadığına aşağıdaki şekilde bakabilirsiniz;

Herşey yolundaysa status olarak green dönecektir. Elasticsearch çalışıyor ancak performans sorunları varsa yellow dönecektir.

Bonus: View Tarafı:

TurEng Konsol Uygulaması

Konsolda çalışırken bir kelimenin İngilizce’sine bakmak için web tarayıcıya geçmekten sıkıldığım için ve tureng sözlük uygulamasının konsoldan çalışabilen ufak bir betik halini yazdım:

https://github.com/msdundar/tureng

Bu uygulama kısaca, tureng sözlük’ten ilgili kelimeyi aratıyor ve dönen sayfaları Nokogiri ile parse ediyor. Daha sonra parse ettiği sonuçları ise “text-table” ile tablolayarak tekrar konsola basıyor. TurEng bizlere bir API sunmadığı için böyle bir yola başvurdum.

Görüntüsü şöyle =>

687474703a2f2f692e696d6775722e636f6d2f6b674f48656f462e706e67

Daha sonra betiği Ruby Türkiye grubunda paylaştığımda Yusuf Yalım ve Ahmet Kapıkıran‘da projeyi forklayarak bir takım katkılar (cümle çevirileri gibi) sağladı.

Son olarak Uğur Özyılmazel ise betiği GEM’leştirerek daha stabil bir sürümünü paylaştı.

ile kurabilir ve aşağıdaki örneklerdeki gibi kullanabilirsiniz:

Yapmak istediğiniz değişiklikler için vigo/tureng’i forklayıp daha sonra pull request yapabilirsiniz.

Güle güle kullanın.

GEM – Unicode Utils

Ruby Upcase Metodunda Türkçe Karakter Problemi

MERNİS’e yaptığım bir request’te, Ruby’nin upcase metodu kaynaklı Türkçe karakter problemi ile karşılaştım.

SOAP request’ini incelediğimde “ü” karakterinin büyük harfe çevrilemediğini gördüm:

Çözüm (Unicode Utils)

unicode_utils GEM’ini kurun.

* Alternatif olarak “unicode” GEM’ini de kurabilirsiniz. Aynı ölçüde başarılılar.

Deneme betiği hazırlayalım:

Betiği çalıştırdığınızda sonucun başarılı olduğunu göreceksiniz:

Rails – Callbacks

Kullanıcılardan herhangi biri hesabını iptal ettiği zaman adminlere bilgilendirme maili gitmesi, bir işlem tetiklendiğinde – başka bir işlemin de gerçekleşmesi veya bir model nesnesi oluşturduğunuzda, başka bir model nesnesinin de onla ilişkili olarak oluşması gibi durumları tanımlarken ihtiyaç duyduğumuz metodların en sık kullanılanları Rails’te 6 tanedir. Bunlar:

  • before_create
  • after_create
  • before_save
  • after_save
  • before_destroy
  • after_destroy

Zaten bu ifadelerin ne iş yaptığı isimlerinden de anlaşıldığı için tekrarlamayacağım.

before_” ile başlayan herhangi bir callback false döndürdüğü taktirde, uygulamanızın çalışma sürecini durdurabileceği için dikkatli kullanılmalıdır.

İlerde uygulamanız dallanıp budaklandığında modeliniz kayıt işlemi yapmıyorsa öncelikli olarak “before_*” ifadelerini kontrok faydalı olabilir.

Örneğin kullanıcılardan biri blog yazınıza yorum yazdığı zaman, yazının yazarına bilgilendirme emaili gitmesini istiyorsunuz varsayalım. Comment modeli içerisinde böyle bir durumu aşağıdaki gibi kurgularız:

create” işleminden sonra yapılmasını istediğiniz işleri doğrudan “after_create” metodu içerisine yazabilirsiniz. Ancak bu yöntem oldukça pratik olmasına rağmen, farklı işlemleri yapmak için çalışan kodları ard arda yazdığınızda kodunuzun okunabilirliği azalacaktır. Bu yüzden aşağıdaki gibi bir yol izleyerek her bir eylemi ayrı metod olarak tanımlamak ve daha sonra bunları after_create‘ten sonra virgülle ayırarak çağırarak daha mantıklı olur:

User Modelinin Güncellenmesi

User modelimizin altında bulunan “password” alanı, şifreleri plain-text olarak muhafaza ettiği için güvenlik zaaflarına sebebiyet verebilir. Bu tür hassas dataları her zaman encrypt etmek gereklidir. Bu yüzden öncelikle veritabanında ki “password” alanını “hashed_password” olarak tekrar adlandıralım:

Şimdi migration dosyamızı hazırlayalım:

Migration’ı çalıştıralım:

Şimdi ise User modelimizi bu değişikliğe uygun şekilde hazırlayalım:

Ruby’nin built-in kütüphanelerinden biri olan Digest ile şifreleri hash’leyebiliriz ancak bu örnekte kullanılan SHA1 şifreleme algoritmasının production ortamı için pekte kullanışlı olduğu söylenemez. Production için BCrypt kullanımı düşünülebilir:

https://github.com/codahale/bcrypt-ruby

Şimdi hazırladığımız User modelini satır satır inceleyelim:

  • require ‘digest’ => Şifreleri encrypt edebilmek için Ruby’nin built-in kütüphanelerinden biri olan Digest’i çağırdık.
  • attr_accessor :password => Burada Ruby’ye “password” için reader ve writer metodları oluşturmasını söyledik çünkü veritabanımızda artık “password” diye bir alan bulunmuyor ve bu yüzden de “password” isminde bir metod Active Record tarafından otomatik olarak oluşturulmuyor. Sonuç olarak “password“ü hala bir şekilde encrypt edilmeden önce set etmeye ihtiyacımız olduğu için kendi “niteleyicimizi (attribute)” oluşturduk. Bu niteleyici herhangi bir model niteleyicisi gibi çalışmasına rağmen, model kaydedildiğinde veritabanına kayıt edilmez.
  • before_save :encrypt_new_password => Burada ki “before_save” callback’i Active Record’a, kayıt yapmadan önce “encrypt_new_password” metodunu çalıştırmasını söylüyor. Burada kayıt yapmaktan kasıt hem create hemde update işlemi.
  • encrypt_new_password => Bu metod sayesinde yalnızca “password” alanı dolu ise şifrenin hashlenmesi sağlanır. Aksi halde mevcut olan şifre korunur. Böylece, kullanıcı şifresini güncellemek istemediğinde şifresini encrypt etmemiş oluruz. Eğer password alanı boş ise, “return if password.blank?” ile metoddan işlem yapmadan dönebiliriz. Ancak password alanı dolu ise metodumuz “self.hashed_password = encrypt(password)” ile girilen password’ü şifreyecektir.
  • encrypt => Bu metod Digest kütüphanesini kullanarak, ona gönderilen veriyi SHA1 ile şifreler. Ayrıca şifreleme sonucunu yani hash‘i döndürür.
  • password_required? => Kullandığımız validasyonları pratikleştirmek için hazırladığımız bir metodtur. Bu metod sayesinde “hashed_password” niteleyicisinin boş olup olmadığını – veya “password” erişicisinin (accessor) yeni bir şifrenin oluşturulmasında kullanılıp kullanılmadığını kontrol ettirebiliriz.
  • self.authenticate => Metodun ismine bakarak bunun bir class metodu olduğunu yani instance yerine doğrudan bir class üzeride çalıştığını söyleyebiliriz. Yani bu metoda bir instance üzerinden değil, doğrudan class üzerinden erişiriz. Örneklemek gerekirse; “@user = User.new & @user.authenticate” şeklinde erişmek yerine doğrudan “self.authenticate” şeklinde erişim sağlarız. Authenticate metodumuz biri e-mail adresi diğeri ise plain-text şifre olmak üzere iki tane argüman alıyor ve “find_by_email” metodu sayesinde ilgili e-mail adresi ile eşleşen kullanıcının bulunabilmesini sağlıyor. Eğer metod sayesinde kullanıcı bulunduysa zaten “user” değişkenine atanıyor, bulunamadıysa bu değişken “nil” olarak kalıyor. Metod içerisinde belirtilen “return user if user && user.authenticated?(password)” ifadesi sebebiyle metodumuz ancak user bulunabildiğinde ve bu user authenticated olduğunda true döndürecektir.
  • authenticated? => Bu metod basitçe; girilen password’ü önce hash‘ler, daha sonra ise saklanmış olan mevcut hash ile karşılaştırır. Eğer bunlar eşleşiyorsa true döndürür, eşleşmiyor ise false döndürür.

Hazırladığımız uygulamayı test edelim:

Sürecin Özeti

  • Authenticate metoduna email adresi ve plain-text şifre olmak üzere iki parametre gönderiyoruz.
  • Gönderdiğimiz şifre metod tarafından hashlenir ve veritabanında hash’li olarak tutulan şifreyle karşılaştırır.
  • Eğer hash’ler eşleşirse authentication başarılı olur, eşleşmez ise başarısız olarak “nil” döndürür.

Son olarak, eklediğimiz bu yeni özellikler için db/seeds.rb dosyamızı düzenleyelim:

KPS & MERNİS Sorgulama – Ruby, Savon ve SOAP

Geçtiğimiz hafta hem TTMesaj servisini hemde KPS’i (Kimlik Paylaşım Sistemi) Rails uygulamalarına entegre etme ihtiyacımızla birlikte, ismini pek sık duyduğum SOAP ile haşır neşir olmak durumunda kaldım. Üç-dört gün sonunda SOAP bana herhangi bir üçüncü dünya ülkesinin beyaz yakalı “plaza” çalışanını çağrıştırıyor. Bu çağrışımda ülkemizdeki SOAP servisleri ile haberleşen kod örneklerinin büyük çoğunlukla C#, ASP.Net ve Java ile yazılmış olmasının payı büyük.

Ruby tarafında ise Savon GEM’i olmasa halimiz yamanmış. Eğer sizde benim gibi SOAP hakkında zerre bilgi sahibi değilseniz ve bir şekilde bu servis ile haberleştirmek zorunda olduğunuz bir Ruby uygulamanız varsa ilk önce SOAP UI ile denemeler yapmanızı tavsiye ederim.

Bu uygulama içerisinde File -> New Project yolunu takip ederek, haberleşmeye çalıştığınız WSDL adresini yazın. Daha sonra WSDL’in sunduğu operasyonlara request aracı ile envai çeşit request yapmayı deneyerek dönen response’ları inceleyebilirsiniz.

İkinci bakmanız gereken yer ise Savon SOAP Client. Sırayla basitten zora, önce TTMesaj servisiyle haberleşmeyi – sonra ise KPS ile haberleşmeyi örnekleyeceğim.

TTMesaj SOAP Client

İlk önce WSDL üzerindeki mümkün tüm operasyonları listeyelim:

Request
Response

İlgili WSDL sayfasını ziyaret ederek bu operasyonlardan herhangi birini inceleyerek nasıl bir request yapmamız gerektiğini inceleyelim. Örneğin “send_single_sms” operasyonuna bakalım:

Parametre isimlerini dikkate alarak SOAP mesajımızı hazırlayalım:

Bu çağrı sonucunda mesajınızın başarıyla iletildiğine dair “OK*” işaretli bir response alacaksınız. Uygulamanın tümüne şuradan erişebilirsiniz:

https://github.com/msdundar/TTMesaj

KPS (Kimlik Paylaşım Sistemi)

KPS tarafında işler beni umduğumdan daha çok zorladı. 3-4 gün boyunca başarılı bir response almak için uğraştım. KPS servisi TTMesaj’dan farklı olarak, requestiniz içerisinde bir takım attribute’ler ve tamamen doğru kurgulanmış bir SOAP Header görmeyi bekliyor.

Öncelikle biraz önce yaptığımız gibi bir keşif turuna çıkalım. İlgili WSDL adresini ziyaret ettiğimizde beklenen request yapısını görebiliyoruz:

Burada farklı bir çok uygulama var. Öncelikle authentication “header” altında direk değil, header altında bulunan “KPSUserInfo” içerisinde “UserName” ve “Password” ile gerçekleşiyor.

Diğer farklı durum ise, “KPSUserInfo” ile birlikte “xmlns” adresininde attibute olarak verilmesi bekleniyor. Aynı durum body’de yine karşımıza çıkıyor. Orada ise “TCKimlikNoSorgu” altında mesajın verilmesi ve xmlns attribute’ü bekleniyor. Uzun araştırmalar sonucunda Savon ile bu işin nasıl yapılabileceğini buldum. Sonuçta ortaya şöyle bir uygulama çıktı:

Burada beni en çok zora sokan “:attributes!” hakkında Savon’un hiç dökümantasyon yapmamış olması, “username” yerine “UserName” gibi camel case takıntılı SOAP servisi, ve header ile body altında kullanılan alt parametreler oldu.

Uygulamanın tümüne şuradan erişebilirsiniz:

https://github.com/msdundar/kps_soap_client

Başarılar.

Rails – MVC Yapısı

Model

Rails’te model katmanı veritabanı ile olan ilişkilerden sorumludur. Genellikle her bir model, bir veritabanı tablosu ile iletişim halindedir. Örneğin Student modeli, veritabanında students tablosu ile ilişki kurar. Student modeli, bu tablo üzerinde CRUD yani Create, Read, Update ve Delete işlerini yapar. Örneğin tabloda arama yapmak için şöyle bir sorgu kullanırız:

Controller

Controller MVC modelinin en önemli kısmıdır. Rails’de controller, dış dünyadan yani kullanıcıdan istekleri kabul eder, gerekli işlemleri uygular ve sonuçları view katmanına gönderir. Web istekleri, değişkenlerin ve verilerin işlenmesi, çeşitli bilgiler için Model’e başvurulması, işlenen verilerin kayıt için tekrar Model’e yollanması gibi işlerin hepsi Controller sorumluluğundadır. Controller genellikle Model üzerindeki CRUD işlemlerini idare eder, view’da kullanılacak değişkenleri düzenler.

View

MVC yapısında View, uygulamanın kullanıcıya görünen yüzüdür. View’ın, Model ile yapacağı herhangi bir iletişim mutlaka Controller üzerinden gerçekleştirilmelidir! Bu sayede hem view temiz kalmış olur hemde MVC çatısından kopmamış oluruz.

View, bizim model nesnelerimizin kullanıcıya sunulması ve formatlanmasından sorumludur. Kullanıcıya sunduğu formlar, input kutuları, butonlar vb. ile kullanıcıyla iletişime girerler.

Rails yapısında birde Controller ve View’ı birbirine kolayca bağlamak için “helper”lar kullanılır. Helper’lar sayesinde örneğin bir kayıt validasyon kurallarından geçemediyse ve kullanıcıya hata göstermemiz gerekiyorsa Helper’lardan yararlanabiliriz.

Rails’i Oluşturan Kütüphaneler

Active Record: Veritabanı ile iletişimi yönetir.

Action View: HTML dosyalarını oluşturan templating sistemidir ve kullanıcıdan aldığı girdileri Rails uygulamasına paslar.

Action Controller: Hem uygulama akışını hemde veritabanından gelerek view’da gösterilecek olan verileri yönetir.