#### {% 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.