Connect with us

Cześć, czego szukasz?

Internet Maker

Ruby on Rails dla zaawansowanych – tworzymy system newsów

Uznaliśmy, że warto dalej drążyć temat Ruby on Rails. Aby przybliżyć faktyczne możliwości platformy, postanowiliśmy stworzyć przykładową aplikację. Będzie to jeden z tych programów, który niemal zawsze stanowi centralną część każdej strony WWW. System newsów to przykład aplikacji, na którą składa się wiele standardowych zagadnień z budowy stron internetowych. Zobaczmy czy w Rails można faktycznie szybko dojść do satysfakcjonujących rezultatów.

Aby rozpocząć pracę nad systemem newsów,
konieczne jest przyjęcie niezbędnych
założeń co do funkcjonalności aplikacji.
Zakładamy na początku, że przyjmie ona kształt
prostego systemu CMS. Niezbędne będzie zatem
rozdzielenie funkcjonalności aplikacji na dwie
części:

  • Stronę WWW, której będą używali internauci,
    pragnący skorzystać z oferowanych im treści. Do
    dyspozycji użytkowników będzie kanał RSS generowany
    automatycznie (w momencie żądania)
    przez system.
  • Panel administracyjny, służący do zarządzania
    zawartością publikowaną na stronie WWW. Ponieważ
    konieczne jest zapewnienie limitowanego
    dostępu do panelu administracyjnego, nasza
    aplikacja musi zostać wyposażona w mechanizm
    logowania oraz dostarczyć interfejs pozwalający
    na rejestrację nowych użytkowników uprzywilejowanych
    i na zarządzanie nimi.

Definiujemy składowe systemu poprzez określenie funkcjonalności panelu administracyjnego.

Panel narzuca sposób organizacji treści bez
określania warstwy prezentacji:

  • Możliwość dodawania, edycji i usuwania aktualności.
  • Możliwość dodawania, edycji i usuwania kategorii, do których przynależą newsy.
    • Zastrzegamy, że aby wiadomość została
      dodana, musi przynależeć do kategorii. Jest
      to relacja wiele do jednego, czyli wiele newsów
      należy do jednej kategorii. Nie będzie
      możliwe przypisanie aktualności do więcej niż
      jednej kategorii.
  • Możliwość dodawania, edycji i zarządzania
    kontami użytkowników.

    • Dodanie użytkownika polega na zalogowaniu
      się na istniejące konto administratora i wypełnieniu
      formularza. Składowymi formularza
      są login i hasło służące do autentykacji oraz
      takie pola jak imię, nazwisko, adres e-mail,
      czy notatka \”o autorze\”.
    • System nie ma praw dostępu, stąd nowe
      konto ma możliwości analogiczne do administratorskich.

Możliwe jest jednak rozszerzenie
systemu, tak by stworzyć konta typu redaktor
(tylko dodawanie) czy korektor (dodawanie i edycja).

Struktura panelu administracyjnego:

  • Formularz logowania.
  • Nowy news.
  • Zarządzanie aktualnościami, lista aktualności z możliwością ich usunięcia i edycji.
    • Formularz edycji aktualności.
  • Nowy użytkownik, formularz.
  • Zarządzanie użytkownikami, lista użytkowników z możliwością ich usunięcia.
  • Mechanizm wylogowania.

Struktura strony WWW:

  • Strona główna prezentująca ograniczoną odgórnie liczbę ostatnio dodanych aktualności bez podziału na kategorie, z zaznaczeniem przynależności do kategorii.
    • Lista dostępnych kategorii z możliwością przejścia do listy aktualności w kategorii.
    • Dostęp do kanału RSS przygotowanego wg standardu RSS 2.0.
  • Strona kategorii, zawierająca listę skrótów aktualności przynależących do kategorii.
    • Lista aktualności zostanie wygenerowana w oparciu o tytuł aktualności, wstęp (tzw. zajawkę). Po kliknięciu na aktualność otworzy się strona z jej pełną treścią.
    • Lista zostanie ograniczona limitem aktualności na stronę. Będzie udostępniony mechanizm dzielenia na strony, dzięki któremu długość strony ulegnie skróceniu do rozsądnych rozmiarów oraz przyczyni się do uzyskania większej ilości odsłon.
  • Strona aktualności, zawierająca pełną jej treść.
    • News składa się z informacji o przynależności do kategorii z możliwością przejścia do listy newsów do niej przynależących
    • News to tytuł, wstęp, treść oraz informacja o autorze.
    • Pod newsem znajdzie się podpis, stanowiący część formularza do dodawania aktualności.

Docelowa aplikacja będzie zatem bardzo
prosta. Taki szablon systemu CMS to bardzo dobry
punkt wyjścia do dalszych eksperymentów. Proponowane
rozszerzenia systemu to:

  • Obsługa zdjęć z generowaniem miniatur.
  • Kodowanie hasła w bazie danych.
  • Przydzielanie określonego dostępu dla użytkowników panelu, np. tylko do działu artykuły, akcji dodaj.
  • Zastosowanie zaawansowanego wystroju graficznego strony.

Tworzymy projekt

Ponieważ większość naszych czytelników
korzysta z oprogramowania InstantRails, wszystkie
operacje będą bazowały na tym założeniu. Jeżeli
jednak ktoś wykorzystuje samodzielnie zainstalowaną
platformę Rails czy korzysta z niej na serwerze
zdalnym, także nie powinien mieć problemów
z wykonaniem tych samych operacji.
Uruchamiamy InstantRails i klikamy na \”Create
New Rails App…\”. Jako nazwę podajemy “news\”,
choć może to być dowolna nazwa:

rails news
cd news

Przechodzimy do katalogu z projektem, np.
{stala}C:/InstantRails/rails_apps/news{/stala} i dokonujemy
edycji pliku konfiguracji bazy danych: {stala}config/database.yml{/stala}.

development:
adapter: mysql
database: newsy_dev
username: root
password: root
host: localhost

Określamy parametry dostępu do bazy danych.
Dla tego projektu warto utworzyć osobną bazę
danych. Dobrą praktyką w Rails jest tworzenie
trzech środowisk pracy bazodanowej. Naturalnie,
na lokalnym komputerze stworzymy wyłącznie środowisko
developerskie, podczas gdy na serwerze
produkcyjnym moglibyśmy postawić bazy danych:
testową oraz produkcyjną.

Struktura naszej aplikacji będzie następująca:

• Ścieżka główna oraz katalog news/ to dostęp
publiczny do odczytywania newsów. Będzie
to zatem interfejs użytkownika. Przykładowe
adresy:

{stala}http://localhost:3000/{/stala} – spis ostatnich artykułów
{stala}http://localhost:3000/news/category/1{/stala} – artykuły w kategorii o identyfikatorze 1
{stala}http://localhost:3000/news/pokaz/1{/stala} – artykuł numer 1

• Panel administracyjny jest strefą chronioną, co
oznacza, że aby móc się do niej zalogować,
konieczne jest podanie loginu i hasła. Strefa
chroniona składa się z formularza logowania,
który pojawia się, ilekroć próbujemy uzyskać
dostęp do strony chronionych. Do panelu administracyjnego
wchodzimy, wprowadzając adres:

{stala}http://localhost:3000/admin/{/stala}
{stala}http://localhost:3000/admin{/stala} – zarządzanie użytkownikami
{stala}http://localhost:3000/article{/stala} – zarządzenia artykułami
{stala}http://localhost:3000/category{/stala} – zarządzanie kategoriami

Baza danych

Każdy projekt rozpoczynamy od utworzenia
potrzebnych modeli, które powstają w oparciu
o przemyślaną wcześniej strukturę bazy danych.

Potrzebujemy następujących tabeli w bazie:

  • articles – artykuły
  • categories – kategorie newsów
  • users – użytkownicy

Ponieważ nasz system oddziela część administracyjną
od tej dla użytkownika, z tabeli articles będą korzystały
odpowiednio dwa modele – articles oraz news.

Utwórzmy zatem odpowiednie modele:

ruby scripts/generate model Article
ruby scripts/generate model Category
ruby scripts/generate model User
ruby scripts/generate model News

Wywołanie każdego z tych poleceń powoduje
utworzenie odpowiednich modeli. Przechodzimy
zatem do katalogu {stala}db/migrate{/stala}, by określić strukturę
naszej bazy danych.

Migracje to znakomity mechanizm oferowany
przez framework RoR. Pozwala on na sprecyzowanie
struktury bazy danych, lecz w taki sposób,
by możliwe było jej utworzenie na dowolnej
bazie, np. MySQL czy PostgreSQL. Migracje są
więc niezależne od bazy danych. Wraz z rozwojem
każdego oprogramowania struktura bazy danych
się zmienia. Dodanie nowej kolumny przestaje
być łatwe w momencie, gdy pracujemy na trzech
bazach danych. System migracji ułatwia to zadanie,
wprowadzając wersjonowanie struktury bazy
danych, z możliwością tworzenia zmian i przywracania
poprzednich wersji.

RoR utworzył w katalogu db/migrate 4 pliki:

001_create_articles.rb
002_create_categories.rb
003_create_users.rb
004_create_news.rb

Możemy usunąć plik 004, gdyż nie będzie nam
potrzebny. W końcu model news i articles korzystają
z tej samej tabeli w bazie danych.
Tradycyjny kod SQL tworzonej bazy danych
wyglądałby następująco (w MySQL):

CREATE TABLE \'articles\' (
\'id\' int(11) NOT NULL auto_increment,
\'title\' varchar(150) NOT NULL,
\'intro\' text NOT NULL,
\'content\' text NOT NULL,
\'user_id\' int(11) NOT NULL default \'1\',
\'category_id\' smallint(6) NOT NULL default \'1\',
\'date\' datetime NOT NULL,
PRIMARY KEY (\'id\')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE \'categories\' (
\'id\' int(6) unsigned NOT NULL auto_increment,
\'name\' varchar(50) default NULL,
PRIMARY KEY (\'id\')
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE \'users\' (
\'id\' int(11) NOT NULL auto_increment,
\'login\' varchar(50) NOT NULL,
\'password\' varchar(50) NOT NULL,
\'firstname\' varchar(100) NOT NULL,
\'surname\' varchar(100) NOT NULL,
\'email\' varchar(100) NOT NULL,
\'note\' text NOT NULL,
PRIMARY KEY (\'id\')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

W RoR korzystamy z migracji. Otwórzmy do
edycji plik {stala}001_create_articles.rb{/stala}, by utworzyć
strukturę tabeli:

class CreateArticles < ActiveRecord:: Migration
      def self.up
 	     create_table :articles do |t|
	      t.column :title, :string, :limit=> 150
	      t.column :intro, :text
	      t.column :content, :text
	      t.column :user_id, :integer
	      t.column :category_id, :integer
	      t.column :date, :datetime
	end
end
   def self.down
	   drop_table :articles
	end
end

Wyróżniamy dwie metody, self.up – tworzenie
tabeli oraz self.down, powrót do sytuacji
sprzed jej powstania. W RoR domyślną kolumną
{stala}auto_increment{/stala} jest kolumna id, której tutaj
nie ma, gdyż RoR utworzy ją automatycznie. Tę
zasadę określaliśmy mianem \”konwencja ponad
konfigurację\”. Dodanie kolumn odbywa się
poprzez określenie ich nazwy ({stala}:title{/stala}) oraz typu
danych, które reprezentuje (tu {stala}:string{/stala}). Można
dodatkowo określić limit znaków, które mogą na
daną kolumnę przypadać (:limit).

Dostępne typy danych to: {stala}:string{/stala}, {stala}:text{/stala}, {stala}:integer{/stala},
{stala}:float{/stala}, {stala}:decimal{/stala}, {stala}:datetime{/stala}, {stala}:timestamp{/stala}, {stala}:time{/stala}, {stala}:date{/stala}, {stala}:binary{/stala}, {stala}:boolean{/stala}

Create_table to tak zwana transformacja. Jej
zadaniem jest utworzenie nowej tabeli. Istnieją
jednak i inne transformacje, np. {stala}add_column{/stala}, która
służy do dodawania nowej kolumny:

add_column :haslo, :string, :default => \"masło\", :limit => \"150\"

Definicja tabeli user będzie prezentowała się
następująco:

create_table :users do |t|
             t.column :login, :string, :limit => 50
             t.column :password, :string, :limit => 32
             t.column :firstname, :string, :limit => 50
             t.column :surname, :string, :limit => 50
             t.column :email, :string, :limit => 50
             t.column :note, :text
end

Tabela categories będzie tą najmniej skomplikowaną:

create_table :categories do |t|
	t.column :name, :string, :limit => 50
end

Jeżeli poprawnie ustanowiliśmy połączenie
z bazą danych, możemy dokonać migracji. RoR automatycznie
utworzy nasze tabele w bazie danych.
Koniec martwienia się o poprawny kod SQL czy
korzystania z phpMyAdmin:

rake db:migrate

Relacje między tabelami

ActiveRecord to mechanizm RoR, który pozwala
na dynamiczne określanie zależności między tabelami
w bazie danych. Ponieważ liczba możliwych
kombinacji jest określona, mechanizm ten działa
bardzo dobrze. Dostępne typy zależności to:

  • {stala}belongs_to{/stala} – każdy artykuł należy do kategorii
  • {stala}has_one{/stala} – jedna fotografia ma jeden opis
  • {stala}has_many{/stala} – jeden artykuł ma wiele zdjęć, jedna kategoria ma wiele artykułów
  • {stala}has_and_belongs_to_many{/stala} – jeden artykuł może znajdować się w wielu kategoriach

Jak widać, modele tworzą pomiędzy sobą
relacje. Musimy je zastosować do naszego projektu.
Wykorzystamy dwie relacje z powyższej listy,
gdyż nasz projekt korzysta tylko z {stala}belongs_to{/stala} oraz
has_many. Otwórzmy plik {stala}articles.rb{/stala} z katalogu
{stala}app/models{/stala}:

class Articles < ActiveRecord::Base
	belongs_to :category
	belongs_to :user
end

Jeden artykuł należy zawsze do kategorii. Jeden
artykuł zawsze należy do jakiegoś użytkownika.
Z kolei do kategorii należy zawsze wiele artykułów
({stala}category.rb{/stala}):

class Category < ActiveRecord::Base
	has_many :articles
end

Uwaga. Do newsów ({stala}news.rb{/stala}) należy wiele
kategorii i wielu użytkowników, choć model News
nie odpowiada w bazie danych tabeli news, lecz
articles:

class News < ActiveRecord::Base
	belongs_to :category
	belongs_to :user
end

Model użytkownika możemy pozostawić w nienaruszonym
stanie.

Tworzymy kontrolery

Zanim nasza aplikacja zacznie działać, musimy
utworzyć szereg kontrolerów akcji. By przyspieszyć
tempo tworzenia aplikacji, wykorzystamy
mechanizm scaffold, który wygeneruje wszystkie
potrzebne formularze. Dzięki temu zabiegowi panel
administracyjny stworzymy dosłownie w ciągu
kilku minut. Będzie on zawierał wszystkie opcje
potrzebne do zarządzania zawartością: dodawanie,
edycję, usuwanie użytkowników, kategorii oraz
artykułów.

By utworzyć kontroler po stronie klienckiej,
wywołujemy następujące polecenia generatora:

ruby scripts/generate controller news
ruby scripts/generate controller rss

Kontroler rss będzie odpowiadał za generowanie
kanału RSS. Postanowiliśmy go oddzielić
od kontrolera news, by zachować przejrzystość,
w przypadku, gdy zdecydujesz się na rozszerzenie
aplikacji. Po stronie administracyjnej tworzymy
szereg kontrolerów:

ruby scripts/generate controller article
ruby scripts/generate controller user
ruby scripts/generate controller category

System logowania

By korzystać z panelu administracyjnego, musimy
utworzyć pierwszego użytkownika. To dlatego
warto najpierw stworzyć interfejs administracyjny
pozbawiony logowania. Poddajmy edycji plik {stala}user_controller.rb{/stala}:

class UserController < ApplicationController
	scaffold :user
end

Możemy teraz uruchomić nasz program: {stala}http://localhost:3000/user/{/stala}. Lecz przecież założyliśmy, że
do panelu administracyjnego będziemy wchodzić
poprzez adres {stala}http://localhost:3000/admin/{/stala}.

Dlatego modyfikujemy ścieżki {stala}config/routes.rb{/stala}.
Dodajmy linie:

map.connect \'admin\', :controller => \"user\"
map.connect \'\', :controller => \"news\"

Dzięki temu zabiegowi wprowadzenie adresu
admin powoduje uruchomienie kontrolera user.
Przy okazji sprawimy, by przy wpisaniu http://localhost:
3000/ pojawił się kontroler news, dzięki czemu
możliwe będzie wyświetlenie listy aktualnych
wiadomości.

Załóżmy nowe konto. Teraz możemy przystąpić
do programowania. Utworzymy system autoryzacyjny,
pozwalający na logowanie się na stronę.
Edytujemy kontroler {stala}application.rb{/stala}, stanowiący
klasę, po której dziedziczymy we wszystkich kontrolerach.
Dodajemy deklarację metody {stala}check_authentication{/stala}
odpowiedzialnej za sprawdzenie
autoryzacji użytkownika:

def check_authentication
unless @session[:user]
session[:intended_action] = action_name
session[:intended_controller] = controller_name
redirect_to :controller => \"user\", :
action => \"signin\"
end
end

W momencie, gdy sesja użytkownika nie
istnieje, zostaje on przekierowany do kontrolera
user i akcji signin odpowiedzialnej za logowanie.
Dwie zmienne {stala}intended_action{/stala} i {stala}intended_controller{/stala}
pozwalają na zapamiętanie miejsca, z którego
logował się użytkownik. W ten sposób możliwe
będzie jego przekierowanie po udanym zalogowaniu
we właściwe miejsce.

Stwórzmy teraz odpowiednią klasę {stala}UserController{/stala},
nadpisując tę, którą przed chwilą tworzyliśmy:

class UserController < ApplicationController
	before_filter :check_authentication, :except => [:signin]
	scaffold :user

	layout \'admin\'
	def signin
	  if request.post?
	  user = User.find(:first, :conditions=> [\'login = ? AND password = ?\', params[:login], params[:password]])
	  if user.blank?
	  raise \"Błąd nazwa użytkownika lub hasło!\"
	end
	session[:user] = user.id
	redirect_to :action => session[:intended_action],
	  :controller => session[:intended_controller]
	end
end
	def logout
	  session[:user] = nil
	  redirect_to :controller => \"user\"
	end
end

Właściwość klasy {stala}before_filter{/stala} powoduje,
że każdorazowe odwołanie się do dowolnej
z metod danej klasy powoduje sprawdzenie, czy
użytkownik jest zalogowany. Jeżeli nie, zostaje on
odesłany do metody {stala}check_authentication{/stala} klasy
bazowej. Wyjątkiem jest sytuacja, gdy wybrano
akcję signin, odpowiedzialną za logowanie
użytkownika.

Zdefiniowana metoda signin sprawdza, czy
użytkownik przesłał dane metodą POST. Tworzymy
nowy obiekt klasy User, wywołując metodę
find (cecha frameworka), znajdującą i zwracającą
pierwszy rekord spełniający warunek loginu i hasła
podanego przez użytkownika. Tu params jest tablicą
superglobalną, zawierającą dane wprowadzane
metodą POST i GET przez klienta przeglądarki.

W przypadku nie znalezienia użytkownika, zwracany
jest błąd. Jeżeli użytkownik został odnaleziony,
następuje zapisanie do tablicy sesyjnej jego
identyfikatora oraz przekierowanie do żądanej
akcji. Wylogowanie, za które odpowiada metoda
logout, jest realizowane poprzez wyzerowanie
tablicy sesyjnej i przekierowanie użytkownika do
kontrolera user.

Przystąpmy do utworzenia formularza logowania.
Utwórzmy plik {stala}signin.rhtml{/stala} w katalogu
{stala}app/views/user{/stala}. Zawartość będzie następująca:

<%= form_tag(:action => \"signin\") %>
Login:
Hasło:
<%= end_form_tag %>

Do poprawnego zrozumienia powyższej
zawartości konieczna jest znajomość systemu
szablonowego RoR. Większość tagów HTML
w RoR generujemy za pośrednictwem specjalnie
do tego stworzonych funkcji. Funkcja form_tag
odpowiada tu za wygenerowanie tagu {html}

{/html}
z odpowiednimi parametrami. Reszta kodu nie
wymaga omówienia, gdyż jest to prosta składnia
HTML.

W ten oto sposób utworzyliśmy prosty system
logowania. Błędem jest umieszczanie w bazie
hasła w postaci niezakodowanej. Ze względu na
charakter szkoleniowy tego tekstu, to zadanie
pozostawiamy tobie.

Layouty

Każda strona ma pewien zestaw elementów
wspólnych. Layouty w RoR odpowiadają za
wyświetlenie metod kontrolera w odpowiednim
wystroju graficznym. Aby kontroler wyświetlił
stronę w oparciu o określony layout, korzystamy
ze składni:

layout \'nazwa\'

Żeby layout działał poprawnie, konieczne jest
utworzenie odpowiedniego szablonu. Dla panelu
administracyjnego szablon taki przyjmie postać:


panel administracyjny

Panel administracyjny

<%= link_to_unless_current(\"Użytkownicy\",{ :controller => \"user\", :action => \"index\"}) %> <%= link_to_unless_current(\"Artykuły\", { :controller => \"article\", :action => \"index\"}) %> <%= link_to_unless_current(\"Kategorie\",{ :controller => \"category\", :action =>\"index\" }) %> <%= @content_for_layout %> <%= link_to_if(@session[:user], \"Wyloguj\",{ :controller => \"user\", :action => \"logout\"}) %>

Jak łatwo zauważyć, większą jego zawartość
stanowią specjalne konstrukcje szablonowe RoR.
Funkcja {stala}link_to_unless_current{/stala} zaciekawi
szczególnie tych, którzy nie przepadali za tworzeniem
odnośników, które przestają być aktywne po
przejściu na wskazywaną przez nie stronę. RoR
realizuje takie zadanie automatycznie. Wystarczy
jako parametr podać nazwę odnośnika oraz kontroler
i akcję, do której ma się odwoływać.

Reszta jest robiona automatycznie. Przycisk \"wyloguj\"
ma sens tylko wówczas, gdy użytkownik jest
zalogowany. Taką sytuację sprawdzamy, korzystając
z instrukcji warunkowej {stala}link_to_if{/stala}. Jako
parametr podajemy tablicę sesyjną użytkownika
oraz kontroler i akcję odpowiedzialną za realizację
tego zadania.

Zawartość właściwa strony zostanie zawsze
umieszczona w miejscu, gdzie znajduje się tag:

<%= @content_for_layout %>

Aby użytkownik miał dostęp do kanału RSS, konieczne
jest wskazanie kanału w nagłówku HTML.

Dokonujemy tego za pomocą następującego taga:

<%= auto_discovery_link_tag(:rss, {:controller => \'rss\', :action => \"news\"},{:title => \"Moj kanal RSS\"}) %>

W przypadku wprowadzenia standardowego
taga, problemem nie do rozwiązania będzie przygotowanie
odpowiedniej ścieżki do pliku, chyba,
że podamy kompletny adres URL do kanału.
W systemie udostępniono również listę
kategorii. Umieszczamy ją w layoucie {stala}news.rhtml{/stala},
pamiętając o wygenerowaniu odpowiednich
danych na potrzeby wyświetlenia listy kategorii.
To dlatego we właściwych metodach kontrolerów
znajdujemy linijkę:

@categories = Category.find_all

Dzięki niej możemy wygenerować następujący
kod odpowiedzialny za wyświetlenie listy kategorii:

  • <%= link_to_unless_current(\"Wszystkie\",{ :controller => \'news\' }) %> <% for category in @categories %>
  • <%= link_to_unless_current(category.name, { :action => \'category\', :id =>category }) %> <% end %>

Nie jest to niestety rozwiązanie eleganckie
i wymaga poprawy. Generowanie menu należałoby
przenieść na klasę {stala}ApplicationHelper{/stala}, co będzie
kolejnym zadaniem dla ciebie.

Podsumowanie

W zaprezentowanym artykule udało nam się
stworzyć prosty system newsów. Warto go jednak
rozszerzyć o opcje przedstawione w specyfikacji
początkowej systemu. Ruby on Rails to framework
pełen dodatkowych wtyczek, które łatwo
zainstalować.

Aby wykonać taką operację jak dodanie pliku
czy poddanie obrazu miniaturyzacji, nie trzeba
się zatem zbytnio wysilać. Wystarczy do tego celu
wykorzystać np. wtyczkę FileColumn (http://www.kanthak.net/opensource/file_column/index.html).

By działała ona poprawnie, nasze środowisko musi
mieć dostęp do biblioteki RMagick (http://rmagick.rubyforge.org/), odpowiedzialnej za współpracę
z zewnętrznym programem do obróbki grafiki.
W ROR taką funkcję pełni ImageMagick (http://www.imagemagick.org/) lub GraphicsMagick.
Żeby zatem korzystać z miniaturyzowania zdjęć,
konieczne jest zainstalowanie jednego rozszerzenia,
jednego gema i jednego programu.

Podczas tworzenia nawet najprostszego
oprogramowania w Ruby on Rails zaczynamy
podświadomie przenosić naszą wiedzę z innych
języków na to środowisko. Myślenie w RoR wymaga
jednak bardzo dobrego poznania samego
frameworka. Bez tego wiele operacji wykonujemy
nie w stylu RoR, co przysparza niepotrzebnych
problemów. By dobrze poznać RoR, warto
aktywnie korzystać z dokumentacji środowiska
dostępnej pod adresem http://api.rubyonrails.org.

Także sama składania Ruby jako języka, na którym
oparto RoR, potrafi sprawić problem. Ponieważ
różni się ona zasadniczo od choćby popularnego
C++, niekiedy sporo czasu trzeba poświęcić na
ponowne odkrywanie koła.

Czy zatem dla wielu oczywistych zalet warto
korzystać z RoR? Na to pytanie każdy musi sobie
odpowiedzieć sam.

Pozostałe kontrolery

Aby klasa była objęta autoryzacją, konieczne
było dodanie linijki:

before_filter :check_authentication, :except => [:signin]

Wiedząc to, definiujemy pozostałe kontrolery.
Kontroler Article przyjmie następujący kształt:

class ArticleController < ApplicationController
	before_filter :check_authentication, :except => [:signin]
	scaffold :article
	layout \'admin\'
end

Do tematyki layoutu powrócimy w dalszej
części artykułu. Analogiczny kształt przyjmuje
kontroler Category.

Przejdźmy zatem do strony klienckiej i kontrolera
news. Tutaj konieczne będzie określenie
akcji lista, pokaz i category. Odpowiednio, metody
te będą odpowiadały za pokazanie listy ostatnich
newsów, pokazanie newsa o konkretnym
identyfikatorze oraz pokazanie artykułów w danej
kategorii.

class NewsController < ApplicationController
 def index
    @categories = Category.find_all
    lista
    render :action => \'lista\'
 end
 def lista
     @categories = Category.find_all
     @article_pages, @articles = paginate :articles, :per_page => 10, :order => \'id DESC\'
 end
     def category
    @categories = Category.find_all
    @category = Category.find(params[:id])
    @article_pages, @articles = paginate :articles, :per_page => 10, :order => \'id DESC\', :conditions => [\'category_id = ?\', params[:id]]
 end
    def pokaz
    @categories = Category.find_all
    @article = Article.find(params[:id])
    @user = User.find(@article.user_id)
 end
end

Każdej powyższej metodzie odpowiada jeden
szablon. Przykładem niech będzie szablon pokaz.
rhtml:

<%= @article.title %>

<%= @article.date %>

<%= @article.intro %>

<%= @article.content %>

Autor: \"><%= @user.firstname %> <%= @user.surname%>

O autorze: <%= @user.note %>

Obiekt {stala}@article{/stala} to record z bazy danych odnaleziony
na podstawie dostarczonego identyfikatora
za pośrednictwem tablicy params. Do tego zadania
wykorzystano obiekt klasy {stala}Article{/stala} (który odpowiada
nazwie tabeli articles) oraz metodę find.

Ponieważ w tabeli {stala}articles{/stala} przechowujemy wyłącznie
identyfikator autora, konieczne jest pobranie
dodatkowych danych. Służy do tego analogiczna
metoda, tym razem klasy {stala}User{/stala}. Jako parametr podajemy
wartość kolumny {stala}user_id{/stala} z tabeli articles.

RoR oferuje możliwość dynamicznego podziału
na strony. Jest to realizowane za pośrednictwem
konstrukcji paginate, przy czym należy określić
limit rekordów na stronę. W metodzie category
konieczne było przyjęcie dodatkowego założenia,
które wynika z faktu, że konieczne jest wyświetlenie
artykułów tylko z wybranej kategorii. Wykorzystuje
się w tym celu parametr {stala}:conditions{/stala}, który odpowiada składni SQL WHERE. Parametr :order to
naturalnie rzecz biorąc sposób, w jaki dane mają
być sortowane.

Klasa {stala}NewsController{/stala} oraz wszystkie jej szablony
zostały stworzone w oparciu o wygenerowany
uprzednio {stala}scaffold{/stala}. RoR pozwala na definiowanie
rusztowania statycznego oraz dynamicznego.
Statyczne rusztowanie tworzy się następującym
poleceniem:

ruby scripts/generate scaffold NAZWA

Warto zwrócić uwagę na zawartość szablonu
{stala}_form.rhtml{/stala}, gdyż zawiera on zawsze statyczną
wersję formularza dodania/aktualizacji danych
aktualnego wa chwili generowania rusztowania.

Tworzenie kanału RSS

Kolejnym kontrolerem wymagającym obsługi
jest nasz kanał RSS:

class RssController < ApplicationController
	def news
		@news = Article.find(:all, :order =>\"id DESC\", :limit => 15)
		@headers[\"Content-Type\"] = \"application/rss+xml\"
	end
end

W analogiczny do poprzedniego przykładu
sposób definiujemy metodę news, która wygeneruje
kanał RSS. By pobrać dane, wykorzystujemy
metodę find, pobierając ostatnich 15 rekordów.
Dodatkowo konieczne jest zadeklarowanie typu
dokumentu. Jest to RSS/XML. Cała akcja rozgrywa
się w szablonie {stala}news.rhtml{/stala} (views/rss). Tam
umieszczamy kod:

xml.instruct!
xml.rss \"version\" => \"2.0\", \"xmlns:dc\" =>\"http://purl.org/dc/elements/1.1/\" do
	xml.channel do
	xml.title \'Aktualne newsy serwisu XYZ.pl\'
	xml.link url_for(:only_path => false,
		:controller =>\'news\',
		:action => \'\')
	xml.pubDate CGI.rfc1123_date(@news.first.date)
	xml.description h(\"Ten kanał ...opis\")
	@news.each do |news|
		xml.item do
		xml.title news.title
		xml.link url_for(:only_path =>false,
			:controller =>\'news\',
			:action => \'pokaz\',
			:id => news)
		xml.description h(news.intro.to_s)
		xml.pubDate CGI.rfc1123_date(news.date)
		xml.guid url_for(:only_path =>false,
			:controller =>\'news\',
			:action => \'pokaz\',
			:id => news)
		end
	end
end
end

Ten dość rozbudowany przykład jest odpowiedzialny
za prawidłowe wygenerowanie arkusza
XML. Utworzenie dokumentu polega na wywoływaniu
kolejnych metod, gdzie ich nazwa odpowiada
nazwie węzła XML. Funkcja {stala}url_for{/stala} jest często
wykorzystywana w szablonach i służy do wygenerowania
odnośnika do zasobu, określając przy tym
wyłącznie kontroler oraz akcję. Tajemnicza metoda
klasy CGI o nazwie {stala}rfc1123_date{/stala} odpowiada za
przerobienie standardowej daty bazy MySQL na
postać określoną przez standard RSS 2.0.

Może cię też zainteresować

Internet Maker

Czy któryś programista webowy interesujący się najnowszymi trendami nie słyszał o Ruby on Rails? Jeśli tak, to spieszę z wyjaśnieniami. RoR to framework napisany w języku Ruby. Jak każdy framework, ma...

Internet Maker

Obiektowy język programowania o nazwie Ruby został stworzony w 1995 roku przez Japończyka Yukihiro Matsumoto. Jego zadaniem było zapewnienie programistom jak największej wygody i ułatwienie im czerpania satysfakcji...

Internet Maker

Ruby on Rails to framework, który cieszy się niesłabnącym zainteresowaniem w kręgach projektantów aplikacji internetowych. Jego główną zaletą ma być szybkość tworzenia i wdrażania nowych rozwiązań. Postanowiliśmy sprawdzić,...

Internet Maker

Ruby on Rails rzutem na taśmę wywołało burzę skrajnie różnych emocji. Owszem, jest to nowy, rewolucyjny sposób szybkiego budowania aplikacji internetowych. Lecz także i tej technologii trzeba się nauczyć...