Önceki bölümü okumadan buraya geldiyseniz hiç kasmayın geri dönün
- ORTA SEVİYE BİR RAİLS TUTORIAL - 1 (Kurulum, ilk stiller)
- ORTA SEVİYE BİR RAİLS TUTORIAL - 2 (Kullanıcı girişi - Bootstrap CSS)
- ORTA SEVİYE BİR RAİLS TUTORIAL - 3 (Blog altyapısı)
- ORTA SEVİYE BİR RAİLS TUTORIAL - 4 (JavaScript stiller)
- ORTA SEVİYE BİR RAİLS TUTORIAL - 5 (Kolleksiyon sayfaları)
Ana sayfa güncellemesi
Hali hazırda ana sayfada birkaç rastgele gönderi görebiliyoruz. Tüm kolleksiyonlardan birkaç gönderi gösterebilmek için ana sayfayı değiştirelim.
_main_content.html.erb
dosyasının içeriğini şöyle değiştirelim:
app/views/pages/index/_main_content.html.erb
<div id="main-content" class="col-sm-9"> <h3 class="page-name"><%= link_to "Hobi Arkadaşı", hobby_posts_path %></h3> <div class="row"> <%= render @hobby_posts %> <%= render no_posts_partial_path(@hobby_posts) %> </div><!-- row --> <h3 class="page-name"><%= link_to "Çalışma Arkadaşı", study_posts_path %></h3> <div class="row"> <%= render @study_posts %> <%= render no_posts_partial_path(@study_posts) %> </div><!-- row --> <h3 class="page-name"><%= link_to "Takım Arkadaşı", team_posts_path %></h3> <div class="row"> <%= render @team_posts %> <%= render no_posts_partial_path(@team_posts) %> </div><!-- row --> </div><!-- ana içerik -->
Her kolleksiyondan gönderilerin olduğu bölümler oluşturduk.
Oluşum değişkenlerini
PagesController
in index
aksiyonunda tanımlayalım. Aksiyonu şöyle yapalım:
app/controllers/pages_controller.rb
def index @hobby_posts = Post.by_branch("hobby").limit( 8 ) @study_posts = Post.by_branch("study").limit( 8 ) @team_posts = Post.by_branch("team").limit( 8 ) end
Daha önce
no_posts_partial_path
yardımcı metodunu tanımlamıştık. Fakat üzerinde biraz değişiklik yapmamız gerekiyor. Şu anda sadece kolleksiyon sayfalarına göre çalışıyor. Metoda bir posts
parametresi ekleyelim:
app/helpers/posts_helper.rb
def no_posts_partial_path(posts) posts.empty? ? "posts/shared/no_posts" : "shared/empty_partial" end
Burada
posts
parametresini tanımladık, oluşum değişkenini basit değişken ile değiştirdik. Parça dosyayı daha mantıklı bir yere taşıyoruz çünkü şu anda sadece kolleksiyonlarda kullanılmıyor.
posts/branch/_no_posts.html.erb
dosyasını
posts/shared/_no_posts.html.erb
adresine taşıyalım.
Daha önce
no_posts_partial_path
metodunu kullandığımız _branch.html.erb
dosyasında metoda parametre olarak @posts
oluşum değişkenini verelim.
Bazı stil değişiklikleri için
default.scss
dosyasına şunları ekleyelim:
app/assets/stylesheets/base/default.scss
.container { padding: 0; } .row { margin: 0; }
Ayrıca
home_page.scss
içine şunları ekleyelim:
app/assets/stylesheets/partials/home_page.scss
.page-name { margin: 15px 0 15px 0; text-align: center; background-color: white !important; font-weight: bold; a { color: black; } a:hover { text-decoration: underline; } }
Servis nesneleri
Daha önce belirttiğimiz gibi eğer kontrolör içine lojik koyarsanız kolayca ortalık karışabilir ve testler çok sıkıntılı olabilir. Bu yüzden lojiği kontrolör dışında bir yerlere almak faydalı olacaktır. Bu amaçla servis nesneleri (servisler) kullanabiliriz.
PostsController
içinde şöyle bir get_posts
metodumuz vardı:def get_posts branch = params[:action] search = params[:search] category = params[:category] if category.blank? && search.blank? posts = Post.by_branch(branch).all elsif category.blank? && search.present? posts = Post.by_branch(branch).search(search) elsif category.present? && search.blank? posts = Post.by_category(branch, category) elsif category.present? && search.present? posts = Post.by_category(branch, category).search(search) else end end
Bu metodda çok fazla servislere aktarılacak lojik var. Servisler Ruby sınıfları gibidir. Tanımlanmış bir metodu çağırırız ve dönen değeri kullanırız. Ruby’de sınıfın üreteci olan
initialize
metodu parametreler ile çağırarak sınıf üretiriz. Daha sonra tüm lojiği işleyecek bir metod tanımlarız. Uygulamalı yaparak kod içinde nasıl göründüğüne bakalım.
app
klasörü altında services
adında bir alt klasör oluşturalım.
app/services
Klasör içinde yeni bir posts_for_branch_service.rb
dosyası tanımlayarak içine şu kodu yazalım:
app/services/posts_for_branch_service.rb
class PostsForBranchService def initialize(params) @search = params[:search] @category = params[:category] @branch = params[:branch] end # isteğe uygun gönderileri getir def call if @category.blank? && @search.blank? posts = Post.by_branch(@branch).all elsif @category.blank? && @search.present? posts = Post.by_branch(@branch).search(@search) elsif @category.present? && @search.blank? posts = Post.by_category(@branch, @category) elsif @category.present? && @search.present? posts = Post.by_category(@branch, @category).search(@search) else end end end
Görüldüğü üzere
initialize
metodunda parametreleri alıyor ve başka metodda kullanılacağı için oluşum değişkeni olarak kaydediyoruz. Sonra call
metodu içinde daha öncesinde kontrolörde yazdığımız get_posts
metodunun lojiğini aynen işliyoruz. Şimdi get_posts
metoduna geri dönelim ve içeriğini şöyle değiştirelim:
app/controllers/posts_controller.rb
... def get_posts PostsForBranchService.new({ search: params[:search], category: params[:category], branch: params[:action] }).call end ...
Peki Rails nereden bilecek bu sınıfı? Default olarak Rails
app
klasörü altındaki tüm sınıf tanımlarını başlangıçta yükler. Server’ı tekrar başlatmamız yeterli olacaktır.
Yeni gönderi oluşturmak
Şimdiye kadarki gönderiler seed ile üretilmiş yapay gönderilerdi. Kullanıcının yeni gönderiler girmesi için gereken arabirimi hazırlayalım artık.
posts_controller.rb
dosyasında new
ve create
aksiyonlarına ihtiyacımız var. Bunları tanımlayalım (tabi ki private bölümü dışında):
app/controllers/posts_controller.rb
... def new @branch = params[:branch] @categories = Category.where(branch: @branch) @post = Post.new end def create @post = Post.new(post_params) if @post.save redirect_to post_path(@post) else redirect_to root_path end end ...
new
aksiyonu içinde formda kullanılmak üzere yeni gönderi oluşturmak amaçlı oluşum değişkenlerini belirliyoruz. @categories
oluşum değişkeninde o kolleksiyona ait kategorilerin listesi bulunuyor. @post
oluşum değişkeni ise formda yeni bir gönderi oluşturmak için bir yeni Post nesnesi bulunuyor.
create
aksiyonu ise form doldurulup gönderilince yeni gönderiyi post_params
metodu ile oluşturarak kaydını yapıyor. Şimdi post_params
metodunu private bölümüne ekleyelim:
app/controllers/posts_controller.rb
... private ... def post_params params.require(:post). permit(:content, :title, :category_id). merge(user_id: current_user.id) end ...
permit
metodu sayesinde sadece belirtilen parametreler form gönderiminden alınır, gerisine izin verilmez.
PostsController
en üst satıra şunu ekleyelim:
app/controllers/posts_controller.rb
class PostsController < ApplicationController before_action :redirect_if_not_signed_in, only: [:new] ...
before_action
Rails filtrelerinden biridir. Burada kullanıcı girişi yapmamış ziyaretçilerin yeni gönderi oluşturmasına engel oluyoruz. Buradaki satırın anlamı new
aksiyonuna gitmeden önce redirect_if_not_signed_in
metodu çağırılacak. Tahmin edersiniz ki bu metod uygulamada başka yerlerde de gerekecektir mutlaka. O yüzden metodu application_controller.rb
içine ekleyelim:
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base protect_from_forgery with: :exception def redirect_if_not_signed_in redirect_to root_path if !user_signed_in? end def redirect_if_signed_in redirect_to root_path if user_signed_in? end end
Giriş yapmamış kullanıcılar ana sayfaya yönlendirilecek. Ayrıca nasıl olsa lazım olur diyerek giriş yapmış kullanıcıları ana sayfaya yönlendiren bir metod daha ekledik.
Sıra geldi görsel kalıp dosyamıza.
app/views/posts
klasöründe new.html.erb
kalıp dosyasını tanımlayıp içine şunları yazalım:
app/views/posts/new.html.erb
<div class="container new-post"> <div class="row"> <div class="col-sm-6 col-sm-offset-3"> <h1>Yeni gönderi oluşturun</h1> <%= render "posts/new/post_form" %> </div> </div> </div>
Parça görsel için
new
klasörünü ve içine _post_form.html.erb
dosyasını tanımlayarak içine şunları yazalım:
app/views/posts/new/_post_form.html.erb
<%= bootstrap_form_for(@post) do |f| %> <%= f.text_field :title, label: "Başlık", maxlength: 100, placeholder: "Başlık", class: "form-control", required: true, minlength: 5 %> <%= f.hidden_field :branch, :value => @branch %> <%= f.text_area :content, label: "İçerik", rows: 6, required: true, minlength: 20, maxlength: 1000, placeholder: "Neler aradığınızı yazın. Örn. özel ilgiler, uzmanlık seviyesi vs.", class: "form-control" %> <%= f.collection_select :category_id, @categories, :id, :name, class: "form-control", label: "Kategori" %> <%= f.submit "Gönderi oluşturun", class: "form-control" %> <% end %>
Bu kodda yeni olan tek şey
collection_select
bize bir dropdown list tanımlıyor. Kısaca şöyle, category_id parametresine @categories oluşum değişkenine koyduğumuz kolleksiyona ait kategorilerden birini id sini kullanıcı seçimime göre koyuyor.
Şimdi
new
görsel kalıbı için biraz stil tanımlayalım. app/assets/stylesheets/partials/posts
klasöründe new.scss
dosyası tanımlayalım ve içine şunları yazalım:
app/assets/stylesheets/partials/posts/new.scss
.new-post { height: calc(100vh - 50px); background-color: white; h1 { text-align: center; margin: 25px 0; } input, text-area, select { width: 100%; } }
Yeni gönderi oluşturma formu şuna benzedi:
Son olarak tüm alanların doğru doldurulduğundan emin olmak için bazı doğrulamalar yapalım.
Post
modeli içine şunları ekleyelim:
app/models/post.rb
... validates :title, presence: true, length: { minimum: 5, maximum: 255 } validates :content, presence: true, length: { minimum: 20, maximum: 1000 } validates :category, presence: true ...
Bu bölümde anlatılacaklar da bu kadar. Gelecek bölümde yeni bir özellik ile uygulamamızı genişleteceğiz. Kullanıcılara anında mesajlaşma özelliği sağlayacağız. Şimdilik kalın sağlıcakla..
Sırada şunlar var:
- ORTA SEVİYE BİR RAİLS TUTORIAL - 7 (Anlık mesajlaşma ilavesi)
Hiç yorum yok:
Yorum Gönder