Tworzenie Prostej Platformy Blogerskiej - Budowanie Postów

Przez:, Z dnia:

Ten tutorial zakłada, że już ukończyłeś:

  1. Install Ruby on Rails
  2. Create Ruby on Rails application
  3. Create Static Pages - without this deploy will not work
  4. Install Git
  5. Create Remote Git Repository - optional but recommended
  6. Deploy application to Heroku
  7. Manage users with Devise
  8. How to add Twitter Bootstrap to Ruby on Rails application - Advised
  9. Creating Simple Blogging Platform - Creating Model
  10. Creating Simple Blogging Platform - Routes
  11. Creating Simple Blogging Platform - Displaying Posts

Teraz, kiedy mamy sposób na wyświetlanie postów, możemy iść dalej i zacząć używać formularzy do tworzenia ich.

Krok 1: Stwórz Akcję "new"

Zaczniemy od dodania akcji "new" do naszego kontrolera:

/app/controllers/posts_controller.rb

class PostsController < ApplicationController

    def index
        @posts = Post.all
    end

    def show
        @post = Post.find(params[:id])
    end

    def new
    end
end

Krok 1.2: Stwórz "instancję" Posta w Kontrolerze

Tym razem wewnątrz akcji stworzymy "instancję" nowego posta i sapiszemy go w zmiennej. Tak jak to robilismy wcześniej w wierszu polecenia:

/app/controllers/posts_controller.rb

def new
    @post = Post.new
end

Krok 1.3: Stwórz plik HTML

Możemy kontynuować, potrzebny jest nam szblon dla nowych postów. Wewnątrz folderu /app/views/posts/ stwórz nowy plik i nazwij go "new.html.erb", dodaj ten kod:

/app/views/posts/new.html.erb

<%= form_for @post do |f| %>
    <div class="form-group">
        <%= f.label :title, class: 'control-label' %>
        <%= f.text_field :title, class: 'form-control' %>
    </div>

    <div class="form-group">
        <%= f.label :body, class: 'control-label' %>
        <%= f.text_area :body, class: 'form-control', rows: 6 %>
    </div>

    <%= f.submit 'Save', class: 'btn btn-primary' %>
<% end %>

Krok 1.4: Dodaj link

Umieśćmy link do tej strony na stronie "index":.

/app/views/posts/index.html.erb

<h1>This is a list of posts</h1>
<%= link_to 'New Post', new_post_path %>
<ul>
    <% @posts.each do |p| %>
        <li>
            <h3><%= link_to p.title, post_path(p.id) %></h3>
            <p><%= p.body %></p>
        </li>
    <% end %>
</ul>

Możemy teraz przejść do tej strony. Jak spróbujesz złożyć formularz, pojawi się błąd ponieważ będzie on poszukiwał danych posta by go stworzyć (akcja "create", której jeszcze nie stworzylismy.)

Krok 2: Akcja "create"

Otwórz posts_controller.rb i skopiuj kod od linijki 15 do 29:

/app/controllers/posts_controller.rb

class PostsController < ApplicationController

    def index
        @posts = Post.all
    end

    def show
        @post = Post.find(params[:id])
    end

    def new
        @post = Post.new
    end

    def create
        @post = Post.new(allowed_params)

        if @post.save
            flash[:success] = "Created new post"
            redirect_to @post
        else
            render 'new'
        end
    end

    private
        def allowed_params
            params.require(:post).permit(:title, :body)
        end
end

Napisalismy kilka linijek kodu. Najpierw musimy spojrzeć na kod poniżej deklaracji private (wszystko poniżej "private" jest dostępne tylko wewnątrz kontrolera - cecha bezpieczeństwa). Określiliśmy tam allowed_params. To cecha, która przyszła wraz z Rails 4 jako ulepszenie standardów bezpieczeństwa. Nie będziemy wchodzić w szczegóły. Zapamiętaj, że do parametrów "peemitted" (dozwolonych) musisz dodać wszystkie parametry zawarte w formularzu. W przeciwnym razie, nie zostaną one zapisane podczas podsumowywania formularza.

Teraz, spójrzmy na rzeczywistą akcję. Pierwszy wiersz przedstawia:

@post = Post.new(allowed_params)

Stworzyliśmy zmienną @post i używamy metody new w klasie Post. Przekazujemy allowed_params jako parametry dozwolone, które zdefiniowaliśmy pod deklaracją "private".

Metoda new nie zapisuje naszych postów do bazy danych. Zamiast tego, przechowuje on posta w pamięci zanim zdecydujemy się go zapisać. Będziemy tego próbować w następnym kroku. Jeżeli próba zapisania nie powiedzie się, @post.save zwróci false i akcja ponownie odda stronę "new", jeżeli się powiedzie, otrzymamy komunikat, że się udało i akcja przekieruje nas na stronę posta (@post).

Dlaczego zapis może się nie powieść? Być może dlatego, że pole tytułu lub treści jest puste kiedy my chcemy żeby miały one zawartość.

W tem momencie nic takiego się nie wydarzy, ponieważ nie dodaliśmy sposobu na odrzucanie takich formularzy. Możesz spróbować; teraz nasza aplikacja zapisze każdy post. Bez tytułu ani treści. To nie dobrze, dlatego musimy to naprawić.

Krok 2.2: Dodaj walidacje w Modelu

W tym momencie, wróćmy do naszego modelu i dodajmy trochę walidacji.

/app/models/post.rb

class Post < ActiveRecord::Base
    validates :title, presence: true, length: { minimum: 3 }
    validates :body, presence: true, length: { minimum: 30 }
end

Dzięki temu będziemy mieć pewność, że tytuł i treść nie będą puste i będą miały odpowiednio przynajmniej 3 lub 30 znaków

Krok 2.3: Dodaj nowe pliki

Teraz potrzebujemy się upewnić, że użytkownicy zostają powiadamiani o błędach. By tego dokonać, musimy zbudować mechanizm do wyświetlania wiadomości błędów formularzy. Wewnątrz /app/views stworz folder i nazwij go "shared". W środku tego foldera stwórz nowy plik o nazwie "_error_messages.html.erb". Upewnij się, że dodałeś "_" na początku nazwy. Do tego pliku skopiuj-wklej poniższy kod:

/app/views/shared/_error_messages.html.erb

<% if object.errors.any? %>
    <div id="error_explanation">
        <div class="alert alert-danger alert-dismissable">
            <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
            <p><strong>This form contains <%= pluralize(object.errors.count, 'errors') %>.</strong></p>
            <ul>
                <% object.errors.full_messages.each do |msg| %>
                <li><%= msg %></li>
                <% end %>
            </ul>
        </div>
    </div>
<% end %>

Teraz możemy wrócić spowrotem do naszego formularza i dodać tam ten "partial". Kod jest zbudowany w taki sposób, że pojawi się tylko wtedy gdy wystąpi jakiś błąd.

/app/views/posts/new.html.erb

<%= form_for @post do |f| %>
    <%= render 'shared/error_messages', object: f.object %>
    <div class="form-group">
        <%= f.label :title, class: 'control-label' %>
        <%= f.text_field :title, class: 'form-control' %>
    </div>

    <div class="form-group>
        <%= f.label :body, class: 'control-label' %>
        <%= f.text_area :body, class: 'form-control', rows: 6 %>
    </div>

    <%= f.submit 'Save', class: 'btn btn-primary' %>
<% end %>

Spróbuj.

Krok 3: Własność Posta

Jedynym problem pozostaje rozpoznanie kto jest twórcą posta. Teraz każdy może wejść na naszą stronę i stworzyć post, nawet jeśli nie jest zalogowany. To nie jest zachowanie, jakiego oczekujemy od aplikacji. Chcemy żeby użytkownik najpierw stworzył konto by mógł dodawać posty. Ponadto, każdemu postowi chcemy przypisać autora.

Aby odwołać się do użytkownika posta musimy dodać nową kolumnę do tabeli "posts" w bazie danych. Łatwo możemy tego dokonać przez generator migracji. W terminalu:

bash

$ rails generate migration add_user_id_to_posts user_id:integer

Notice how we pass arguments to the generator - user_id:integer. Rails will also pick up the name of the table to alter: posts.

Zauważ jak przekazujemy argumenty do generatora - user_id:integer. Rais wychwyci także nazwę tabeli by zmienić: posts.

invoke  active_record
create    db/migrate/20140512101508_add_user_id_to_posts.rb

Spójrzmy na nowo stworzony plik migracyjny.

db/migrate/20140512101508_add_user_id_to_posts.rb

class AddUserIdToPosts < ActiveRecord::Migration
  def change
    add_column :posts, :user_id, :integer
  end
end

Krok 3.2: Uruchom Migracje

Możemy teraz zmigrować bazę danych z poleceniem rake:

bash

$ rake db:migrate

== 20140512101508 AddUserIdToPosts: migrating =================================
-- add_column(:posts, :user_id, :integer)
   -> 0.0047s
== 20140512101508 AddUserIdToPosts: migrated (0.0048s) ========================

Krok 3.3: Zmodyfikuj pliki Post i User

Teraz musimy powiedzieć aplikacji o istniejącym powiązaniu pomiędzy postami i użytkownikami. Dodaj 3. linijkę po class User < ActiveRecord::Base.

app/models/user.rb

class User < ActiveRecord::Base

  has_many :posts, dependent: :destroy

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

Dodaj 3. linijkę w post.rb:

app/models/post.rb

class Post < ActiveRecord::Base

  belongs_to :user

  validates :title, presence: true, length: { minimum: 3 }
  validates :body, presence: true, length: { minimum: 30 }
end

Te dwie linijki has_many i belongs_to dają nam możliwość tworzenia postów "przez" ("through") użytkownika, który zostanie automatycznie zostanie wszczepiony do posta przez user_id. Aby zobaczyć jak to działa, zmieńmy kontroler postów by z tego korzystał:

app/controllers/posts_controller.rb

def create

  @user = current_user
  @post = @user.posts.build(allowed_params)

  if @post.save
    flash[:success] = "Created new post"
    redirect_to @post
  else
    render 'new'
  end
end

Dodajmy też autora do widoku:

app/views/posts/index.html

<ul>
    <% @posts.each do |p| %>
        <li>
            <h3><%= link_to p.title, post_path(p.id) %></h3>
            <p><small><strong>By: </strong><%= p.user.email %></small></p>
            <p><%= p.body %></p>
        </li>
    <% end %>
</ul>

app/views/posts/show.html

<h1><%= @post.title %></h1>
<p><small><strong>By: </strong><%= @post.user.email %></small></p>
<p><%= @post.body %></p>

Krok 4: Odpal Konsolę Rails

Jeżeli spróbujesz odświeżyć stronę, jest zepsuta. Dzieje się tak, ponieważ stworzylismy wcześniej posty, które nie posiadają user_id. Musimy wyczyścić bazę danych. Otwórz konsolę w terminalu:

bash

$ rails console

2.1.1 :001 > Post.destroy_all

Krok 5: Użyj Devise

Zanim zaczniemy tworzyć posty, musimy dokonać jednej regulacji. Teraz, do tworzenia postów, używamy current_user. Jak już wiemy, current_user jest obecny tylko wtedy, gy użytkownik jest zalogowany. Co jeśli niezalogowany użytkownik próbuje stworzyć nowy post? Aplikacja się popsuje. Na szczęście, łatwo to naprawić z Devise.

app/controllers/posts_controller.rb

class PostsController < ApplicationController

    before_filter :authenticate_user!, except: [:show, :index]

    # existing code
end

Metoda :authenticate_user! jest zapewniona przez Devise. Pozwala zalogowanym użytkownikom na dostęp do wszystkich akcji oprócz tych wymienionych w except. Ale na tym się nie kończy. Jeżeli użytkownik próbuje wejść na stronę zabronioną, Devise przekieruje go na stronę logowania. Po tym jak się zaloguje lub zarejestruje, zostanie przeniesiony do miejsca gdzie próbował wejść wcześniej. Śmiało, wypróbuj to.

Edycja Postów

Musisz się zalogować by móc oznaczyć tutorial jako ukończony żeby śledzić swój postęp



Dodaj komentarz

Możesz się zalogować by skomentować