29 Mart 2015 Pazar

Rails 2015 B3

Maykılın kitabına devam. Tavsiye ettiğim gibi c9.io üzerinde geliştirme yaparsanız daha iyi bence, acaba benim kurulumda bir enayilik mi var deyip durmadan öğrenmeye devam edersiniz.

Önce yeni bir örnek uygulama tanımlıyoruz:
$ cd ~/workspace
$ rails _4.2.0_ new sample_app
$ cd sample_app/
Şimdi de uygulama klasörü içindeki "Gemfile" isimli dosyayı kullanacağımız gemlere göre değiştirelim:
source 'https://rubygems.org'

gem 'rails',                '4.2.0'
gem 'sass-rails',           '5.0.1'
gem 'uglifier',             '2.5.3'
gem 'coffee-rails',         '4.1.0'
gem 'jquery-rails',         '4.0.3'
gem 'turbolinks',           '2.3.0'
gem 'jbuilder',             '2.2.3'
gem 'sdoc',                 '0.4.0', group: :doc

group :development, :test do
  gem 'sqlite3',     '1.3.9'
  gem 'byebug',      '3.4.0'
  gem 'web-console', '2.0.0.beta3'
  gem 'spring',      '1.1.3'
end

group :test do
  gem 'minitest-reporters', '1.0.5'
  gem 'mini_backtrace',     '0.1.3'
  gem 'guard-minitest',     '2.3.1'
end

group :production do
  gem 'pg',             '0.17.1'
  gem 'rails_12factor', '0.0.2'
end
Production modunun Heroku benzeri biryerde çalışacağını düşünerek PostgreSQL seçimi yaptık. Şimdi Production mod hariç olarak gereken gemleri yüklemek için:
$ bundle install --without production
Gemfile içindeki tüm gemlerin doğru versiyonlarında olduğundan emin olmak için:
$ bundle update
Hazırlıklar bitti, şimdi uygulamayı geliştirmeye başlayabiliriz. Bu kısımda Rails eylemleri ve görsellerini statik HTML dosyalar kullanarak oluşturacağız. Bu kısımda çoğunlukla app/controllers ve app/views klasörleri içindeki dosyalarla çalışacağız.

Statik sayfalarımızı hazırlamak için scaffolding kullanacağız. İlk planda home, help ve about syfalarımız olsun istiyoruz. Örnek vermek üzere sadece home ve help sayfalarını üretip about sayfasını sonradan kontrolöre nasıl ekleyeceğimizi görmek üzere bırakıyoruz:
$ rails generate controller StaticPages home help
      create  app/controllers/static_pages_controller.rb
       route  get 'static_pages/help'
       route  get 'static_pages/home'
      invoke  erb
      create    app/views/static_pages
      create    app/views/static_pages/home.html.erb
      create    app/views/static_pages/help.html.erb
      invoke  test_unit
      create    test/controllers/static_pages_controller_test.rb
      invoke  helper
      create    app/helpers/static_pages_helper.rb
      invoke    test_unit
      create      test/helpers/static_pages_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/static_pages.js.coffee
      invoke    scss
      create      app/assets/stylesheets/static_pages.css.scss
Komut satırında "rails generate" yerine kısaltılmışı olan "rails g" de kullanabiliriz. Aşağıda kısaltılmış Rails komutlarının bazıları var:

Tam KomutKısası
$ rails server$ rails s
$ rails console$ rails c
$ rails generate$ rails g
$ bundle install$ bundle
$ rake test$ rake

"generate" komutuyla ürettiğiniz şeleri "destroy" komutuyla yok edebilirsiniz (aynı satırı destroy ile yazarak). Şimdi server'ı çalıştıralım:
$ rails server -b $IP -p $PORT    # Kendi PC'nizdeyseniz sadece `rails server` yeterli
Uygulamamızın "/static_pages/home" adresine gidersek şunu görürüz:


Statik sayfalarımızla ilgili kontrolör ve görsel dosyalarımıza bir göz atalım. app/controllers/static_pages_controller.rb :
class StaticPagesController < ApplicationController

  def home
  end

  def help
  end
end
Gördüğünüz gibi sayfalara karşı gelen eylemlerin metod tanımlamaları boş duruyor. Şimdi de sayfalarımızın görsellerine bakalım. Görsel sayfaları aslında nerede olduklarını kendileri söylemiş (resime bakarsanız). app/views/static_pages/home.html.erb :
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
app/views/static_pages/help.html.erb :
<h1>StaticPages#help</h1>
<p>Find me in app/views/static_pages/help.html.erb</p>
Rails görselleri basit statik HTML kodlarını yayınlayabilir. Bu sayede Rails bilmeden home ve help sayfalarımızı düzenleyebilirsiniz. Öyleyse sayfalarımızı şu hale getirelim:
app/views/static_pages/home.html.erb
<h1>Örnek Uygulama</h1>
<p>
  Bu sayfa 
  <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
  örnek uygulaması için ana sayfadır.
</p>
app/views/static_pages/help.html.erb
<h1>Yardım</h1>
<p>
  Ruby on Rails Tutorial hakkında yardım almak için 
  <a href="http://www.railstutorial.org/#help">Rails Tutorial help bölümü</a>.
  Bu örnek uygulama hakkında yardım almak için 
  <a href="http://www.railstutorial.org/book"><em>Ruby on Rails Tutorial</em>
  kitabı</a>.
</p>
Şimdi her iki sayfayı tarayıcıda açıp sonucunu görelim.

Biraz da test işlemlerine bakalım. Komut satırında:
$ ls test/controllers/
static_pages_controller_test.rb
Rails generate komutu bizim için gerekli olan test dosyalarını otomatik olarak üretmiş. İçine bakarsak:
require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase

  test "should get home" do
    get :home
    assert_response :success
  end

  test "should get help" do
    get :help
    assert_response :success
  end
end
Bu dosyadaki komutları zamanla anlarız inşallah. Burada anlatılmak istenen, home ve help adında iki geçerli web sayfası olması test edilecek. Testi çalıştırmak için:
$ bundle exec rake test
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
Şimdi test işlemimizin çuvallaması için şöyle bir ilave yapalım:
require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase

  test "should get home" do
    get :home
    assert_response :success
  end

  test "should get help" do
    get :help
    assert_response :success
  end

  test "should get about" do
    get :about
    assert_response :success
  end
end
Test edersek:
$ bundle exec rake test
3 tests, 2 assertions, 0 failures, 1 errors, 0 skips
About isimli sayfanın yolunu bulamadığını belirten bir hata verecektir:
$ bundle exec rake test
ActionController::UrlGenerationError:
No route matches {:action=>"about", :controller=>"static_pages"}
Bunu önlemek için gidip bir route tanımlasak?
Rails.application.routes.draw do
  get 'static_pages/home'
  get 'static_pages/help'
  get 'static_pages/about'
  .
  .
  .
end
Testi bir daha çalıştırdığımızda:
$ bundle exec rake test
AbstractController::ActionNotFound:
The action 'about' could not be found for StaticPagesController
Şimdi de kontrolörde about bulamadım diyor. app/controllers/static_pages_controller.rb dosyasına about eklemesi yapalım:
class StaticPagesController < ApplicationController

  def home
  end

  def help
  end

  def about
  end
end
Hadi bir daha test:
$ bundle exec rake test
ActionView::MissingTemplate: Missing template static_pages/about
Şablon görüntü dosyası yok. Herşeyi kendimiz tanımlıycaz dersek böyle olur işte. Bu görüntü dosyasını da üretelim bakalım:
$ touch app/views/static_pages/about.html.erb
Bu komut yeni görüntü dosyasını üretti ancak içini de doldurmak lazım app/views/static_pages/about.html.erb :
<h1>Hakkında</h1>
<p>
  <a href="http://www.railstutorial.org/"><em>Ruby on Rails
  Tutorial</em></a> bir
  <a href="http://www.railstutorial.org/book">kitaptır</a> ve
  <a href="http://screencasts.railstutorial.org/">screencast videoları</a>
  <a href="http://rubyonrails.org/">Ruby on Rails</a> ile web geliştirmeyi öğretir.
  Bu uygulama da bu öğretici siteden örnek bir uygulama.
</p>
ve sonunda test başarılı olur:
$ bundle exec rake test
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
Ama yine de sayfayı tarayıcıda bir ziyaret etmek iyi olur.

Test bize yeşil ışık yaktığına göre uygulamayı geliştirmeye devam edebiliriz. Bu sevgili statik sayfalarımızı azcık dinamik içerik haline getirelim. Sayfalara tarayıcıda bakarsanız tepedeki etiketin sürekli SampleApp yazdığını görürsünüz. Şimdi her sayfanın kendi etiketini göstermesini sağlayacağız.

Rails new komutu default bir yerleşim (layout) dosyası üretir.Biraz öğrenim amaçlı bu dosyanın adını değiştireceğiz:
$ mv app/views/layouts/application.html.erb layout_file   # geçici değişiklik
Normalde bir uygulamada bunu yapmayız, fakat yerleşim dosyasını anlayabilmek amacıyla bunu yapıyoruz.
SayfaURLAna EtiketDeğişken Etiket
Home/static_pages/home"Ruby on Rails Tutorial Sample App""Home"
Help/static_pages/help"Ruby on Rails Tutorial Sample App""Help"
About/static_pages/about"Ruby on Rails Tutorial Sample App""About"

Etiket değiştirmesinden önce bir web sayfasının neye benzediğini öğrenelim:
<!DOCTYPE html>
<html>
  <head>
    <title>Greeting</title>
  </head>
  <body>
    <p>Hello, world!</p>
  </body>
</html>
En başta hangi versiyon HTML kullandığımızı tarayıcıya söylüyoruz (Burada HTML5). head bölümü sayfanın özelliklerini içeriyor. title tag ile etiketimizi belirti,yoruz, burada sayfa etiketi "Greeting". body bölümünde sayfanın içeriği yeralır, burada p tag'i içinde "Hello, world!" yazıyor. Satırlardaki girintiler sadece yazılımcının daha rahat kodu okuyabilmesi için , tag'ler arası boşluklar ve girintiler HTML işlenirken dikkate alınmaz. 

Şimdi işimiz gücümüz yok sayfa etiketlerini kontrol için test yazacağız. 
assert_select "title", "Home | Ruby on Rails Tutorial Sample App"
Yukarıdaki kod satırı title adında bir tag ve içeriğinde "Home | Ruby on Rails Tutorial Sample App" yazmasını test eder. Bu basit kontrolü her sayfamıza yapalım:
test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase

  test "should get home" do
    get :home
    assert_response :success
    assert_select "title", "Home | Ruby on Rails Tutorial Sample App"
  end

  test "should get help" do
    get :help
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

  test "should get about" do
    get :about
    assert_response :success
    assert_select "title", "About | Ruby on Rails Tutorial Sample App"
  end
end
Bu testi çalıştırdığımızda hata olduğunu görürüz:
$ bundle exec rake test
3 tests, 6 assertions, 3 failures, 0 errors, 0 skips
Test hazretlerini başarılı çıkarmak için her sayfaya bir title tag ekleyelim:
app/views/static_pages/home.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Home | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Örnek Uygulama</h1>
    <p>
      Bu sayfa 
      <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial </a>
      örnek uygulaması için ana sayfadır.
    </p>
  </body>
</html>
app/views/static_pages/help.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Help | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Yardım</h1>
    <p>
      Ruby on Rails Tutorial hakkında yardım almak için 
      <a href="http://www.railstutorial.org/#help">Rails Tutorial help
      bölümü</a>. 
      Bu örnek uygulama hakkında yardım almak için 
      <a href="http://www.railstutorial.org/book"><em>Ruby on Rails
      Tutorial</em> kitabı</a>.
    </p>
  </body>
</html>
app/views/static_pages/about.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>About | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Hakkında</h1>
    <p>
      <a href="http://www.railstutorial.org/"><em>Ruby on Rails
      Tutorial</em></a> bir 
      <a href="http://www.railstutorial.org/book">kitaptır</a> ve 
      <a href="http://screencasts.railstutorial.org/">screencast videoları </a>
      <a href="http://rubyonrails.org/">Ruby on Rails</a> ile web geliştirmeyi öğretir.
      Bu uygulama da bu öğretici siteden bir örnek uygulama.
    </p>
  </body>
</html>
Hadi bakalım bir daha test:
$ bundle exec rake test
3 tests, 6 assertions, 0 failures, 0 errors, 0 skips
Artık yine refaktor zamanı. Bu kodlar çok dağıldı azcık toplamak lazım. Şimdiye kadar üç tane statik sayfa tanımladık ve içeriklerini biraz geliştirdik. Fakat daha Ruby on Rails avntajlarından hiç yararlanmadık, sayfaların tamamı statik HTML olarak yazıldı. Bir sürü de tekrarlama yapıldı:

  • Sayfa etiketleri nerdeyse aynı gibi.
  • "Ruby on Rails Tutorial Sample App" tüm etiketlerde ortak. 
  • Sayfaların HTML yapısı iskeleti birbirinin aynı.
Bu tekrarlanıp duran kodlar bizim DRY (Don't repeat yourself - kendini tekrarlama) ilkemize ters düşer. Racona uymak için kodlarımızı düzenleyeceğiz. Sonra da test ile doğruluklarını kontrol edeceğiz. Başlangıçta etiketi düzenlemek için sayfa görünüm dosyalarımıza Ruby kodlar enjekte edeceğiz. 
app/views/static_pages/home.html.erb

<% provide(:title, "Home") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Örnek Uygulama</h1>
    <p>
      Bu sayfa 
      <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
      örnek uygulaması için ana sayfadır.
    </p>
  </body>
</html>

provide metodu ile :title değişkenine "Home" değerini veriyoruz ve sonra yield metoduyla bu değişkeni görsel içine yazdırıyoruz. <% ... %> arasına yazılan Ruby kod çalıştırılır. <%= ... %> arasına yazılan Ruby kodu ise çalıştırılır ve sonuç işte bu kodun olduğu yere yazılır. Haydi test edelim:
$ bundle exec rake test
3 tests, 6 assertions, 0 failures, 0 errors, 0 skips
Yaşasın hala sıfır hata! İsterseniz sayfayı tarayıcı da açıp sonucu görebilirsiniz. Hatta sayfa üzerine sağ tıklayıp "Sayfa Kaynağını Göster" seçeneği ile baktığınızda sayfa kaynak kodunda Ruby kodlar görünmez, sadece sonuç, sanki statik HTML sayfasıymuış gibi görünür.

Sıra geldi diğer sayfalara da aynı işlemi yapmaya:
app/views/static_pages/help.html.erb
<% provide(:title, "Help") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Yardım</h1>
    <p>
      Ruby on Rails Tutorial hakkında yardım almak için 
      <a href="http://www.railstutorial.org/#help">Rails Tutorial help
      bölümü</a>.
      Bu örnek uygulama hakkında yardım almak için 
      <a href="http://www.railstutorial.org/book"><em>Ruby on Rails
      Tutorial</em> kitabı</a>.
    </p>
  </body>
</html>
app/views/static_pages/about.html.erb
<% provide(:title, "About") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Hakkında</h1>
    <p>
      The <a href="http://www.railstutorial.org/"><em>Ruby on Rails
      Tutorial</em></a> bir 
      <a href="http://www.railstutorial.org/book"> kitaptır</a> ve 
      <a href="http://screencasts.railstutorial.org/">screencast videoları </a>
      to teach web development with
      <a href="http://rubyonrails.org/">Ruby on Rails</a> ile web geliştirmeyi öğretir.
      Bu uygulama da bu öğretici siteden bir örnek uygulama.
    </p>
  </body>
</html>
Genel olarak oluşturduğumuz sayfa HTML kodlarına bakarsak şöyle bir yapı göreceğiz:
<% provide(:title, "Etiketimiz") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    İçerik
  </body>
</html>
Bir başka deyişle tüm sayfalar etiketleri ve body içeriği dışında aynı yapıya sahip. Bu ortak yapıyı kaydetmek için başlangıçta adını değiştirdiğimiz application.html.erb dosyası kullanılır. Hadi bu dosyayı geri yerine koyup üzerinde çalışalım:
$ mv layout_file app/views/layouts/application.html.erb
Yerleşimin çalışması için önce default etiket satırını kendi satırımızla değiştireceğiz:
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
Değişiklik sonrası yerleşim dosyamız şöyle olacaktır:
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
    <%= stylesheet_link_tag    'application', media: 'all',
                                              'data-turbolinks-track' => true %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
    <%= csrf_meta_tags %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>
Bu dosyada özel bir satır var:
<%= yield %>
Bu metod ile yerleşim dosyasının içine hangi sayfa açılıyorsa onun içeriği yazdırılır. Şimdi her sayfamızın kodunu tek tek açıp iskelete ait satırları çıkaracağız:
app/views/static_pages/home.html.erb
<% provide(:title, "Home") %>
<h1>Örnek Uygulama</h1>
<p>
  Bu sayfa 
  <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
  örnek uygulaması için ana sayfadır.
</p>
app/views/static_pages/help.html.erb
<% provide(:title, "Help") %>
<h1>Yardım</h1>
<p>
  Ruby on Rails Tutorial hakkında yardım almak için 
  <a href="http://www.railstutorial.org/#help">Rails Tutorial help
  bölümü</a>.
  Bu örnek uygulama hakkında yardım almak için 
  <a href="http://www.railstutorial.org/book"><em>Ruby on Rails
  Tutorial</em> kitabı</a>.
</p>
app/views/static_pages/about.html.erb
<% provide(:title, "About") %>
<h1>Hakkında</h1>
<p>
  The <a href="http://www.railstutorial.org/"><em>Ruby on Rails
  Tutorial</em></a> bir 
  <a href="http://www.railstutorial.org/book"> kitaptır</a> ve 
  <a href="http://screencasts.railstutorial.org/">screencast videoları </a>
  to teach web development with
  <a href="http://rubyonrails.org/">Ruby on Rails</a> ile web geliştirmeyi öğretir.
  Bu uygulama da bu öğretici siteden bir örnek uygulama.
</p>
Yine test yapmazsak gözlerimiz açık gider, hadi yapalım:
$ bundle exec rake test
3 tests, 6 assertions, 0 failures, 0 errors, 0 skips
Gördüğümüz üzere test işi bayağı bir yardımcı oluyor, her sayfayı tarayıcıda açıp tek tek bakmaktansa.

Devam etmeden önce uygulamamızın giriş satfasını ayarlayalım:
config/routes.rb
Rails.application.routes.draw do
  root 'static_pages#home'
  get  'static_pages/help'
  get  'static_pages/about'
end
root komutu uygulamanın ana sayfasını belirler.