Friendly_Id ile Neşeli Parametreler

Selamlar,

Çok basitçe, bilmeyenler için anlatmak gerekirse friendly_id gem’i users/12312 tarzı route’ları users/yigitsadic şekline dönüştürmemize (aslında çok daha güçlü bir gem, bu sadece çok basit bir örnek) yarıyor.

Gereklilikler

Rails 5

Şehirler Projesi

Varsayalım ki şehirler üzerinde CRUD (create read update destroy) işlemleri yapmamız gerekiyor.

Öncelikle projemizi ve şehirler için bir iskelet oluşturalım.

$ mkdir sehircilik_bakanligi && cd sehircilik_bakanligi
$ rails new .
$ rails generate scaffold city title:string:uniq code:string

Şeklinde bir scaffold (iskelet) oluşturalım. Bu komut ile controller, model gibi ihtiyacımız olanlar oluşacaktır.

Veritabanı dosyamızı migrate edelim.

$ rails db:migrate
$ rails db:test:prepare

Testlerimizi çalıştıralım.

$ rails test

Testler hata vermeli. Neden? Çünkü fixtures dosyalarımız benzersiz değil. (scaffold ederken unique index ekledik, o nedenle hata veriyor) test/fixtures/cities.yml dosyasını açalım. Aşağıdaki gibi bir sonuç ile karşılaşacaksınız.

# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
title: MyString
code: MyString
two:
title: MyString
code: MyString

Bunu şöyle değiştirelim.

one:
title: Edirne
code: 22
two:
title: İstanbul
code: 34

Ne yazık ki hala testlerimiz geçmiyor. Çünkü controller testimiz benzersiz bir kaydı tekrar oluşturmaya çalışıyor. test/controllers/cities_controller_test.rb dosyasında şu bölümü, şöyle değiştirelim.

test "should create city" do
assert_difference('City.count') do
# Eski hali
# post cities_url, params: { city: { code: @city.code, title: @city.title } }
# Yeni hali
post cities_url, params: { city: { code: '6', title: 'Ankara' } }
end
    assert_redirected_to city_url(City.last)
end

Testlerimizi çalıştıralım.

$ rails test

Şehir modeli

Şehirler için bazı kısıtlamalara ihtiyacımız var, mesela şehir adı ve plaka kodu benzersiz olmalı.

Önce testlerimizi yazalım. test/models/city_test.rb dosyamızı açalım ve ekleyelim.

require 'test_helper'
class CityTest < ActiveSupport::TestCase
setup { @city = City.new(title: 'Kırklareli', code: '39') }
test 'yeter şartlar sağlandığında geçerli olmalı' do
assert @city.valid?
end
test 'title alanı boş olmamalı' do
@city.title.clear
refute @city.valid?
end
test 'title alanı benzersiz olmalı' do
@city.title = cities(:one).title
refute @city.valid?
end
test 'code alanı boş olmamalı' do
@city.code.clear
refute @city.valid?
end
test 'code alanı benzersiz olmalı' do
@city.code = cities(:one).code
refute @city.valid?
end
end

Yukarıdaki kodlar,

  • title alanının boş olarak geçerli olmaması,
  • title alanının benzersiz olmayarak geçerli olmaması,
  • code alanının boş olarak geçerli olmaması,
  • code alanının benzersiz olmayarak geçerli olmaması gerektiğini test ediyor.

Çalıştıralım.

$ rails test
...
Finished in 1.176832s, 10.1969 runs/s, 11.8963 assertions/s.
12 runs, 14 assertions, 4 failures, 0 errors, 0 skips

Kodlarımız çakılıyor. Haydi bu özellikleri ekleyelim. Bunu yapmak için app/models/city.rb dosyamızı (scaffolding ile oluşturuldu) açalım.

class City < ApplicationRecord
end

Bu hali ile herhangi bir doğrulama, aslında hiçbir şey barındırmıyor. İsteklerimize göre düzenleyelim.

class City < ApplicationRecord
validates :title, :code, presence: true, uniqueness: true
end

Ve testlerimizi tekrar çalıştıralım.

$ rails test
...
Finished in 1.312931s, 9.1399 runs/s, 10.6632 assertions/s.
12 runs, 14 assertions, 0 failures, 0 errors, 0 skips

İsteklerimiz doğrultusunda çalışıyor.

Çalıştırıp bir inceleyelim.

$ rails server

Tarayıcımızdan localhost:3000/cities adresine girelim.

Scaffolding çalışıyor.

Seed Data

Veritabanımıza başlangıç için bir kaç şehir eklemek için db/seeds.rb dosyasını açıp içine aşağıdakileri ekleyelim.

City.delete_all
City.create title: 'Edirne', code: '22'
City.create title: 'Ankara', code: '6'
City.create title: 'Kırklareli', code: '39'
City.create title: 'İstanbul', code: '34'
City.create title: 'Tekirdağ', code: '59'

Veritabanına aktaralım bunu.

$ rails db:seed

friendly_id kurulumu

Öncelikle, Gemfile dosyamızı açıp, aşağıdaki satırı ekleyelim.

gem 'friendly_id', '~> 5.1.0'

Kuralım.

$ bundle
$ rails generate friendly_id
$ rails db:migrate
$ rails db:test:prepare

Ayarlar

Burada çok detaylı bir şekilde bahsetmeyeceğim fakat friendly_id ile bir çok ayar, özelleştirme yapabilirsiniz. Biz basitçe ihtiyaçlarımızı karşılayacak şekilde kullanalım.

Öncelikle modelimize slug adında bir alan ekleyelim. “Bu güzel bir başlıktır” şeklindeki bir metni “bu-guzel-bir-basliktir” şeklinde tutacağımız alan olacak.

$ rails generate migration add-slug-to-cities slug:string:uniq
$ rails db:migrate
$ rails db:test:prepare

Model ayarları

app/models/city.rb dosyamızı şu şekilde değiştirelim.

class City < ApplicationRecord
# ...
extend FriendlyId
friendly_id :title, use: :slugged
end

Not: Veritabanında olan kayıtların slug alanını güncellemek için City.all.each(&:save) kodunu kullanabiliriz.

Bu ayarlar yapıldıktan sonra artık aşağıdaki iki şekilde de ulaşabileceğiz.

City.find(1)
=> #<City id: 1, title: "Edirne", code: "22", created_at: "2016-11-21 16:25:10", updated_at: "2016-11-21 16:25:10", slug: "edirne">
City.friendly.find('edirne')
=> #<City id: 1, title: "Edirne", code: "22", created_at: "2016-11-21 16:25:10", updated_at: "2016-11-21 16:25:10", slug: "edirne">

Controller düzenlemesi

Şu anda id ile bulunuyor kayıtlar, bunu şehir adı ile değiştirmek için app/controllers/cities_controller.rb dosyamızı açıp, aşağıdaki değişikliği yapalım.

def set_city
# Eski
# @city = City.find(params[:id])
# Yeni
@city = City.friendly.find(params[:id])
end

Sonuç

db:seed ile oluşturulmuş kayıtlar
İstediğimiz gibi çalışıyor.

Yazıya bir devam yazısı daha yazacağım. Şimdilik,

Sevgi ile kalın.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.