#415 Upgrading to Rails 4
- Download:
- source codeProject Files in Zip (63.4 KB)
- mp4Full Size H.264 Video (35.6 MB)
- m4vSmaller H.264 Video (17.7 MB)
- webmFull Size VP8 Video (18.6 MB)
- ogvFull Size Theora Video (46.4 MB)
Geçen haftaki RailsConf'da Rails 4.0'ın ilk candidate versiyonun çıktığı duyuruldu. Bu durum kendi projelerinizi Rails 4'e yükseltmeniz için mükemmel bir fırsat. Böylelikle bulduğunuz bugları rapor edebilirsiniz. Bölüm 400'de Rails 4'ün bir çok yeni özelliğinden bahsetmiştik. Bu bölümde ise bir Rails 3.2 uygulamasını Rails 4.0'a yükseltmeye çalışacağız. Bu bölümü kendi uygulamalarınız üzerinde de uygulayabilirsiniz.
İlk adım olarak Rails'ın son sürümü olan Rails 3.2 ile çalıştığımızdan ve gem'lerimizin hepsinin güncel olduğundan emin olmalıyız ve Ruby 1.9.3 ve sonrası ile çalışmamız gerektiğini unutmayalım. Versiyon yükseltmeye başlamadan önce testlerimizin hepsinin geçtiğine emin olmamız bizim açımızdan iyi olacaktır. Yoksa versiyon yükseltmek biraz zorlaşacaktır. Eğer otomatik testlerimiz yoksa, her yeni eklemeden sonra elle kendimiz manuel testler yapmak zorunda kalacağız. Versiyon yükseltmeye başlamadan önce biraz integration test ekliyoruz. Bütün testleri geçen bir uygulamamız var ve onu şimdi Rails 4'e yükseltmeye başlayabiliriz. Öncelikle bu çalışma için ayrı bir branch açmak iyi olcaktır.
$ git checkout -b rails4
Bir sonraki adımımız Rails 3.2.13
versiyonunu 4.0.0.rc1
'e taşımak olacaktır. İhtiyacımız olan versiyon değişikliğiden sonra ilgili gem'lerin özellikle assets
grubunun yeni versiyona göre ayarlanmasıdır. Rails 4 ile bu grup meselesi ortadan kalkıyor ve bütün gem'lerin içine bu grubu dahil ediyoruz.
gem 'rails', '4.0.0.rc1' gem 'sqlite3' gem 'sass-rails', '~> 4.0.0.rc1' gem 'coffee-rails', '~> 4.0.0.rc1' gem 'uglifier', '>= 1.3.0'
Varsayılan şekilde Rails 4 production modu hiç bir asset tarafından dinamik olarak oluşturulmayacaktır ve gene production modunda önceden derlenmiş asset'ler kullanılacaktır. Eğer asset'leri ön derleme yapmak için rake assets:compile
çalıştırırsak öncelikde ortamımızı production
olarak ayarlamamız gerekiyor.
$ RAILS_ENV=production bundle exec rake assets:precompile
Bu durumun iyi yanı uygulamanın config dosyasını düzelticek olmaktır. Rails 3'de sadece development
ve test
modunda bir çok asset'i yüklüyorduk. Şimdi ise bu kodu
if defined?(Bundler) # If you precompile assets before deploying to production, use this line Bundler.require(*Rails.groups(:assets => %w(development test))) # If you want your assets lazily compiled in production, use this line # Bundler.require(:default, :assets, Rails.env) end
ile değiştiriyoruz.
Bundler.require(:default, Rails.env)
Eğer production modda assetlerinizi derlemek istersiniz, bu dosya içinde kendinize göre değişiklikler yapabilirisniz.
Şimdi yeni versiyonu kurmak için bundle update
'i deniyoruz. Sonucun başarılı olması lazım ancak bazen bu komut beklenmedik hatalar ortaya çıkartabilir. Bu yüzden hangi gem'lerin versiyon dışı olduklarını görmek için bundle outdated
bu küçük kodu çalıştırıyoruz.
$ bundle outdated Fetching gem metadata from https://rubygems.org/......... Fetching gem metadata from https://rubygems.org/.. Resolving dependencies... Outdated gems included in the bundle: * builder (3.2.0 > 3.1.4) * paper_trail (2.7.1 > 1.6.4)
Uygulamamız için bunu çalıştırdığımızda iki adet güncel olmayan gem bulduk. builder
'ın versiyonu hemen hemen yakın ancak paper_trail
için aynısını söyleyemiyoruz ve Rails 4 için yeni bir versiyon bulamıyoruz. Gem dosyası içinde versiyon belirtmenin önemli olduğunu gösteren bir durum olduğunu görebiliyoruz. paper_trail
için sabit bir versiyon belirlememiştik. Şimdi bunu yapacağız.
gem 'paper_trail', '~> 2.7.1'
bundle update
'i çalıştırdığımız zaman versiyon çakışması hatası alıyoruz. Papertrail, ActiveRecord 3.0'ı veya ona yakın bir versiyonu istiyor ve bu yüzden Rails 4 ile uyumlu bir versiyon bulmaya çalışacağız. Papertrail, Rails 4 için bir Git branch'ine sahip Tek yapmamız gerekn gem dosyasında bu branch'i göstermek.
gem 'paper_trail', github: 'airblade/paper_trail', branch: 'rails4'
Bundle update komutunu çalıştırdığımız zaman Papertrail'in Github'daki proje ile eşleştiğini görebiliriz.
Şimdi biliyoruz ki gem'lerimiz güncel ve artık spec'lerimizi çalıştırabiliriz. Spec'lerimizi çalıştırdığımız zaman kötü bir şekilde hatalar alacağız. Çıktının bize gösterdiği caches_page
'in EpisodesController
içinde tanımlı olmadığıdır. Rails 4 ile kaldırılan page caching'i kullanıyoruz ve buna benzer diğer şeyler olan observers, protected model attributes ve ActiveResource kullanıyoruz. İyi haber, eğer bunları kullanmak istiyorsak, bir kaç gem eklemesi ile durumu kolayca kurtarabiliriz. Bütün bu versiyon yükseltme boyunca kullanmak için bu gem'leri eklemek iyi bir fikir olacaktır.
gem 'protected_attributes' gem 'rails-observers' gem 'actionpack-page_caching' gem 'actionpack-action_caching' gem 'activerecord-deprecated_finders'
Bunu yapmamızın nedeni Rails 4 ile ortaya çıkacak hatalardan kaçınmak. Bu şekilde önemli versiyon yükseltmeleri yapılırken, hızlı çalışabilmek adına, yoğun ve büyük kod değiştirmelerden, düzeltmelerden kaçınmak ve bize uygulamamızda yardım edecek bir kaç gem'i eklemek en iyi yoldur. Bütüm testlerimiz geçtiği zaman belki kodu tekrar düzeltebiliriz ve böylelikle kullandığınımız teknikleri değiştirir, gem'lere artık ihtiyacımız kalmadığından onları kaldırabiliriz. Şimdi bundle
kodunu çalıştırıyoruz ve gem'leri yüklüyoruz. Sonrasın da ise spec'leri çalıştırıp, onları geçirmeye çalışacağız. Bunları yaparken bir çok deprecation hatası alacağız ve bu hataların adreslerini göreceğiz.
$ spec . ... You should not use the `match` method in your router without specifying an HTTP method. If you want to expose your action to both GET and POST, add `via: [:get, :post]` option. If you want to expose your action to GET, use `get` in the router: Instead of: match "controller#action" Do: get "controller#action" ...
match
metodu artık desteklenmiyor. Normalde bunu get ile değiştirebiliriz fakat eğer bir çok metodu desteklenmesi istiyorsak, via:
ile bu metodları ekleyebiliriz.
# match 'new', to: 'episodes#new', via: [:get, :post] get 'new', to: 'episodes#new'
Spec'lerimizi çalıştırmayı denediğimiz zaman nedeni mass-assigning protected attributes olan bir çok hata ile karşılaşıyoruz. Bu hatalar Papertrail'ın Version
modelinden geliyor. Bu durum Rails 4'de strong paramaters ile çalıştırılmalı fakat biz hala protected attributes kullanıyoruz. Uygulamamızın config dosyasını modifiye ederek başlayabiliriz. active_record.whitelist_attributes
özelliğini false
olarak ayarlıyoruz. Bu özellik başlangıçta true
olarak geliyor ve bunu anlamı ise her model içinde attr_accessible
'ın beklenmesidir.
config.active_record.whitelist_attributes = false
Bütün spec'lerimiz artık başarı ile geçiyor. Ancak buna rağmen hala uyarı mesajları alıyoruz. Bir kaçından kurtulmayı deneyelim. Bunların bir kısmı whiny_nils
gibi artık desteklenmiyecek özelliklerin olduğu config dosyaları içinden geliyor. Development config dosyası içindeki whiny_nils
alanı kaldırıp, yerine eager_load
özelliğini ekliyoruz ve false
olarak ayarlıyoruz. Daha fazla desteklenmeyecek diğer özellikleri de dosyadan kaldırabiliriz.
Screencaster::Application.configure do # Settings specified here will take precedence over those in config/application.rb # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false config.eager_load = false # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false # Don't care if the mailer can't send config.action_mailer.raise_delivery_errors = false # Print deprecation notices to the Rails logger config.active_support.deprecation = :log # Expands the lines which load the assets config.assets.debug = true end
Production modunu düzenleyeceğiz. Öncelikle bunu config.assets.compress
ekliyoruz.
config.eager_load = true # Compress JavaScripts and CSS config.assets.js_compressor = :uglifier
Test ortamında ise whiny_nils
'i kaldırmalı ve yerine eager'ı ekleyip false
olarak ayarlamalıyız. mass_assignment_sanitizer
'ı da strong paramters kullandığımız için kaldırmalıyız.
# Log error messages when you accidentally call methods on nil # config.whiny_nils = true config.eager_load = false # Raise exception on mass assignment protection for Active Record models # config.active_record.mass_assignment_sanitizer = :strict
Asset pipeline hakkında hızlı bir not düşelim. Eğer uygulamamızdaki config dosyasına bakarsak, true olarak düzenlenmiş config.assets.version
'u görebiliriz. Eğer uygulamamız da asset pipeline kullanmıyorsak, Rails 4 ile varsayılan şekilde gelen bu duruma artık ihtiyacımız yok bu yüzden orayı false
olarak düzenleyeceğiz. Oradan kaldırmamızda da yeterli olacaktır.
Config dosyamızdaki secret token initializer'ı değiştirerek son bir değişim yapıyoruz. secret_key_base
, Rails 4 config dosyasında secret_token
olarak değiştirildi. Rails 3'den geçiş yaparken, bu iki opsiyonu da değiştirmeliyiz fakat uygulamamızı başarılı bir şekilde oluşturduk ve secret_token
opsiyonunu kaldırabiliriz. Farklı bir token kullanmak için en iyi yol secret_key_base
kullanmaktır.
Screencaster::Application.config.secret_token = '762a2f23950e306261908d4e5519ffe71ce626b119e9fc03a012ba86f46d82ef32d72f283633bacc2f59cf94ce5968552fe97d157e7f00560c1217d4592dda09' Screencaster::Application.config.secret_key_base = 'xx762a2f23950e306261908d4e5519ffe71ce626b119e9fc03a012ba86f46d82ef32d72f283633bacc2f59cf94ce5968552fe97d157e7f00560c1217d4592dda09'
Bu durum gerekli çünkü kullanıcı taraflı şifrenlenmiş cookie'lerde bulunun bir dizi saklanmış cookie'leri kaldırıyoruz. Bu kullanıcıların oturum cookie'lerinin içeriklerini görmelerini sağlıyor.
Bir çok değişiklik yaptık ancak henüz birşeyleri kapsamakdık. Yeni bir Rails 4 projesi yaratıp, orada oluşturulan config dosyası ile bizimkini karşılaştıracağız. Böylelikle neleri kopyalamamız gerektiği göreceğiz.
Bütün bu değişimler ile spec'lerimizi çalıştırıyoruz ve eğer uyarı mesajlarının sayısı azaldıysa, hiç bir sorunun olmadığına emin olmak istiyoruz. Bütün testler hala geçiyor ancak bir kaç uyarı mesajımız var. Bu yüzden, onları azaltmalıyız. Bu uyarılarıdan biri Episode
modelinden gelmekte. Bir named scope tanımladığımız zaman, ikinci bir obje olarak geri çağrılabilien bir obje tanımlamalıyız, öğrenğin bir lambda şu şekilde olabilir;
scope :published, -> { where('published_on <= ?', Time.now.to_date) }
Bu gerekli çünkü scope dinamik bir şekilde ayarlanıyor örneğin yerel zaman gibi. Lambda olmadan kullanım, , zamanın sınıf her yüklendikten sonra cağrılmasından ziyade, ancak o sınıfın yüklenmesi ile olabilir. Diğer uyarımız ise EpisodesController
içindeki index
action'ından geliyor.
def index @episodes = Episode.published.find_all_by_pro(false) end
Artık dinamik bulucular desteklenmiyecek. find
methodunun yerine alanı bir opsiyon olarak geçireceğiz.
def index @episodes = Episode.published.where(pro: false) end
Şimdilik bütün uyarı mesajlarından arındık. Artık strong parameters gibi diğer değişimlere odaklana biliriz. Bu konuyu Bölüm 371'de ele almıştık ve model'in mass assignment koruma kullanımlarında attr_accessible
yerine bunları controller'a koyuyoruz. Episode
modelinden attribute'ları kaldırıyoruz.
#attr_accessible :description, :name, :seconds, :published_on, :timecode
episode_params
adlı bir private metodu controller içinde tanımlıyoruz. Diğer yöntemleri yapmak yerine bu geleneksel yolu seçtik.
def episode_params params.require(:episode).permit(:description, :name, :seconds, :published_on, :timecode) end
Bu metod içinde permit
adlı üzerinden izin verilen parametleri geçirdiğimiz metodu kullanıyoruz. Parametrelerin bir hash içinde uygun durumda olduklarından ve nil durumundan kaçınmak için params[:episode]
yerine params.require(:episode)
kullanacağız. Bir formdan parametleri almak istediğimiz her zaman bu metodu kullanacağız.
def create @episode = Episode.new(episode_params) if @episode.save redirect_to @episode, notice: 'Episode was successfully created.' else render action: "new" end end
Bu düzeltmeyi her tarafta yaptıktan sonra artık protected_attributes
gem'ini GemFile'dan kaldırabiliriz. config.active_record.whitelist_attributes
gibi config dosyasındaki alakalı opsiyonlarını da kaldırabiliriz.
Uygulamamızdan geçiş ile akalaı gem'leri kaldırdık fakat diğerlerini kaldırmak biraz sıkıntılı olabilir. page_caching
işlemi için rails-observers
yerine geri bildirimleri kullanıyoruz. Bölüm 321'de bu durumun nasıl kullanıcağından bahsettik. action_caching
diğer bir iyi yöntem bu yüzden activerecord-deprecated_finders
'ı kaldırıyoruz. Daha doğrusu şimdilik Rails 4 ile bir bağımlılığı olan bu durum yakında Rails 4.1'den kaldırılacak.
Son olarak bir kaç küçük değişiklik daha yapacağız. Öncelikle controller'lar içindeki before_filter
'ı before_action
olarak değiştiriyoruz. Şimdilik bir uyarı durumu yok ancak küçük bir isim değişikliği yeterlidir. Route dosyalarında ise eğer "put" metodunu kullanıyorsak onu patch
olarak bizlere daha iyi günceleme özelliği sunan metod ile değiştiriyoruz.
Eğer /test
hedef dizini olan bir uygulamamız varsa Rails 4 ile değişen küçük bir değişiklik gerekiyor. Dahası /vendor/plugins
klasörü artık desteklenmiyor. Plugin'ler artık gem olacak ya da /lib
altına konacak.
Rails 4 ile gelen bir çok yeni özelliği burada anlatmadık fakat bir kaçına eski bölümlerimizde değindik. Buradaki listede özellikleri bulabilirsiniz.