#### {% title "Leniwiec z o.o." %}

# Pastie „Leniwiec z o.o.”

<blockquote>
{%= image_tag "/images/bradypus.jpg", 
              :alt => "[Bradypus tridactylus]", :title => "Bradypus tridactylus" %}
</blockquote>

To klon Pastie napisany w Rails 3 + ActiveRecord.

Czym jest „pastie”? Oto przykłady:

* [pastie](http://pastie.org/)
* [pastebin](http://pastebin.com/)

Jak stworzyć klona pastie w Sinatrze + Datamapper
opisał Nick Plante, [Clone Pastie with Sinatra & DataMapper 
0.9](http://blog.zerosum.org/2008/7/2/clone-pastie-with-sinatra-datamapper-redux).

Nasz „Leniwiec” ma umożliwiać wklejanie 
fragmentów kodu. Kod będziemy wklejać do formularza
z przyciskiem „Wklej”. 
Po kliknięciu tego przycisku, wklejony kod
zapisujemy w tabelce i przekierowujemy się na stronę
z wklejonym kodem, na przykład:

    http://leniwiec.local:3000/128

Od tej chwili, po wsze czasy (no, dopóty, dopóki nie padnie dysk na
*mancie*), wklejony kod będzie dostępny pod tym URL.

W następnej wersji dodamy do każdej strony formularz umożliwiający
wyszukiwanie wklejonych fragmentów kodu zawierających podaną frazę.

A tak wygląda strona główna *pastie.org*:

{%= image_tag "/images/pastie.png", :alt => "[http://pastie.org]" %}


**Zaczynamy** od wygenerowania rusztowanie aplikacji:

    rails leniwiec.local

Oraz nauczenia Railsów odmiany słowa *leniwiec*.
W pliku *inflections.rb* wpisujemy:

    :::ruby
    ActiveSupport::Inflector.inflections do |inflect|
      inflect.irregular 'leniwiec', 'leniwce'
    end

## Projektujemy routing

<blockquote>
{%= image_tag "/images/mvc.png", :alt => "[MVC]" %}
</blockquote>

Cytat: „The routing *ActionController::Routing* module provides URL rewriting
in native Ruby. It’s a way to redirect incoming requests to
controllers and actions. This replaces *mod_rewrite* rules. Best of all,
Rails' Routing works with any web server. Routes are defined in
*config/routes.rb*.”
\[[więcej](http://apidock.com/rails/ActionController/Routing)\]

Strona główna:

    http://leniwiec.local:3000/

Wklejone fragmenty kodu:

    http://leniwiec.local:3000/:number

Wyszukiwanie:

    http://leniwiec.local:3000/search?query=def

Wyniki:

    http://leniwiec.local:3000/search

Routing:

    :::ruby
    # root_path, root_url
    map.root :conditions => { :method => :get },
      :controller => 'leniwce',
      :action => 'index'
    
    # leniwce_url(:number)
    map.leniwce ':number',
      :conditions => { :method => :get },
      :controller => 'leniwce',
      :action => 'show',
      :number => /\d+/
    
    # create_path
    map.create '',
      :conditions => { :method => :post },
      :controller => 'leniwce',
      :action => 'create'
     
    # search_path
    map.search 'search',
      :conditions => { :method => :get },
      :controller => 'leniwce',
      :action => 'search'

Generujemy model i migrujemy:

<blockquote>
{%= image_tag "/images/leniwiec.png", :alt => "[leniwiec.rb]" %}
</blockquote>

    script/generate model Leniwiec lang:string body:text 
    rake db:migrate

Generujemy kontroller:

    script/generate controller Leniwce index show search

Dopiero teraz możemy obejrzeć routing:

    rake routes

I próbnie uruchomić aplikację.

Co działa? A co nie działa? Wpisujemy kilka URL.
Przyglądamy się temu co jest wypisywane na konsoli.


## Jazda obowiązkowa: ćwiczenia na konsoli

<blockquote>
{%= image_tag "/images/mvc.png", :alt => "[MVC]" %}
</blockquote>

Przykłady do wpisania na konsoli SQlite, `script/dbconsole`:

    :::sql
    insert into leniwce (lang, body) 
        values("ruby", "puts 1");
    insert into leniwce (lang, body) 
        values("html", "<html></html>");

I – na konsoli Rails, `script/console`:

    :::sql_rails
    Leniwiec.all
    Leniwiec.all(:conditions => ["lang = ?", "ruby"])
    Leniwiec.all(:conditions =>
      ["lang = ? and body like ?", "ruby", "%puts%"])

Więcej przykładowych poleceń jest do wklejenia
[stąd](http://apidock.com/rails/ActiveRecord/Base)

    :::sql_rails
    w = Leniwiec.new :lang => "css", 
        :body => "h1 { color: red; }"
    w.save
    
    Leniwiec.create :lang => "css", 
        :body => "h1 { background-color: blue; }"


## Widoki

<blockquote>
{%= image_tag "/images/mvc.png", :alt => "[MVC]" %}
</blockquote>

Zaczynamy od widoku *index.html.erb* z formularzem do wklejania kodu:

    :::html_rails
    <% form_for :leniwiec, :url => { 
          :controller => "leniwce", 
          :action => "create" } do |f| %>
      <%= f.error_messages %>
      <p>
        <%= f.label :lang, "Wybierz język" %><br /> 
        <%= f.select :lang, @languages %>
      </p>
      <p>
        <%= f.label :body, "Wklej kod:" %><br />
        <%= f.text_area :body, :cols => 80, :rows => 20 %>
      </p>
      <p>
        <%= f.submit 'Wklej' %>
      </p>
    <% end %>

Od razu też wrzucimy do katalogu *layouts* layout *application.html.erb*:

    :::html_rails
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
      <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
      <title>Leniwce z o.o.</title>
      <%= stylesheet_link_tag 'application', 'uv' %>
    </head>
    <body>
      <h1>Leniwce z o.o.</h1>
      
      <p style="color: green"><%= flash[:notice] %></p>
      
      <%= yield %>
      
    </body>
    </html>

Plik *uv.css* będzie używany przy kolorowaniu składni.
Skopiowałem go z katalogu *stylesheets* tego samouczka.

Wejście na stronę *http://localhost:3000/* daje błąd:

    NoMethodError in Leniwce#index 
  
    You have a nil object when you didn't expect it!
    You might have expected an instance of Array.
    …
    <%= f.select :lang, @languages %>

Zmienna `@languages` nie istnieje. Aby błąd się nie pojawiał
musimy ją zdefiniować.

<blockquote>
{%= image_tag "/images/leniwce_controller.png", :alt => "[leniwce_controller.rb]" %}
</blockquote>

Dopisujemy w pliku *leniwce_controller.rb* w metodzie *index*:

    :::ruby
    class LeniwceController < ApplicationController
      def index
        @languages = ["ruby", "html", "css"]
      end

Jeszcze raz wchodzimy na stronę *http://localhost:3000/*,
teraz już działa, wpisujemy kawałek kodu, klikamy przycisk
„Wklej” i dostajemy stronę z:

    Unknown action
    No action responded to create. Actions: index, search, and show

No to definiujemy akcję *create*. Ponownie zaglądamy do pliku
*leniwce_controller.rb*, gdzie definiujemy metodę *create*:

    :::ruby
    def create
      @leniwiec = Leniwiec.new(params[:leniwiec])
      if @leniwiec.save
        flash[:notice] = 'Umieszczono leniwca w bazie.'
        redirect_to leniwce_path(@leniwiec.id)
      else
        render :action => "index"
      end
    end

Teraz wyświetla się wygenerowana stronka *show.html.erb*
na której ma się pojawić przed chwilą wklejony i zapisany
w bazie kod. Zmieniamy ją na:

    :::html_rails
    <h3>Leniwiec: <%= @leniwiec.lang %></h3>
    <%= @leniwiec.body %>
    <%= link_to 'Nowy leniwiec', root_path %>
 
Teraz po przekierowaniu dostajemy błąd:

    NoMethodError in Leniwce#show 
    Showing app/views/leniwce/show.html.erb where line #1 raised: 
    You have a nil object when you didn't expect it!

Oznacza to, że w metodzie *show* musimy wyciągnąć leniwca z bazy.
Robimy to tak:

    :::ruby
    def show
      @leniwiec = Leniwiec.find(params[:number])
    end


## Dodajemy kolorowanie składni

Zmieniamy kod metody *show*:

    :::ruby
    class LeniwceController < ApplicationController
      def show
        @leniwiec = Leniwiec.find(params[:number])
        @leniwiec.body = ::Uv.parse(@leniwiec.body, 'xhtml', @leniwiec.lang, false, "dawn")  
      end

oraz dopisujemy w pliku *environment.rb*:

    :::ruby
    require 'uv'
    Rails::Initializer.run do |config|
      config.gem 'ultraviolet' 


## Następna wersja „Leniwca z o.o.”

Zaimplementujemy wyszukiwanie fragmentów kodu zawierających podaną
frazę. Jak takie rzeczy się robi można podejrzeć na screencaście
[Simple Search Form](http://railscasts.com/episodes/37-simple-search-form).

W pliku *application.html.erb* dodamy formularz.
Tym razem użyjemy `form_tag` a nie `form_for`, dlaczego?

    :::html_rails
    <% form_tag search_path, :method => 'get' do %>
      <p>
        <%= text_field_tag :search, params[:search] %>
        <%= submit_tag "Wyszukaj", :name => nil %>
      </p>
    <% end %>

Jaką funkcję spełnia `:name => nil`? Technicznie żadną.
To jaki sens ma ten kawałek kodu?

W pliku *leniwce_controller.rb* piszemy metodę *search*:

    :::ruby
    def search
      @search = params[:search]
      @leniwce = Leniwiec.search(@search)
      
      # kolorowanie składni
      @leniwce.each do |leniwiec|
        leniwiec.body = ::Uv.parse(leniwiec.body, 'xhtml', leniwiec.lang, false, "dawn")
      end 
    end

Implementujemy `Leniwiec.search`:

    :::ruby
    def self.search(search)
      if search
        all(:conditions => ['body LIKE ?', "%#{search}%"])
      else
        all
      end
    end

I tworzymy widok na wyszukane fragmenty kodu:

    :::html_rails
    <h3>Wyniki wyszukiwania: <%= @search %></h3>
    <% @leniwce.each do |leniwiec| %>
      <p><b><%= leniwiec.lang %></b></p>
      <%= leniwiec.body %>
    <% end %>


## Filter parameter logging

Pamiętamy też o skróceniu logów \(dlaczego?\):

    :::ruby
    class ApplicationController < ActionController::Base
      # Scrub sensitive parameters from your log
      filter_parameter_logging :body
    end

## Final touches

Pozostaje jeszcze osuszyć kod (jaki?) oraz odrobić zadania.