Archív pro rubriku “Ruby on Rails”

Pokud chcete automaticky mít zobrazená všechna data v českém formátu, tak ideální DRY postup je přidat do config/environment.rb řádky (první pro datum, druhý pro čas):

ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS[:default] = '%d.%m.%Y'
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS[:default] = '%d.%m.%Y %H:%M'

Jenže ouha, tohle vám rozbije zpětnou konverzi dat od uživatele – Rails ve verzi 2.1 totiž dají přednost formátu mm.dd.yyyy před dd.mm.yyyy (08.01.2008 tedy uloží jako 1. srpen 2008) a nenašel jsem žádnou možnost tohle chování změnit. Pokud chcete všechno provést bez použití pluginů, tak můžete předefinovat metody string_to_date a string_to_time v ActiveRecord, které se starají o konverzi textových řetězců na objekty Date resp. DateTime. Vytvořte soubor config/initializers/active_record.rb a vložte do něj:

module ActiveRecord
  module ConnectionAdapters
    class Column
      def self.string_to_date_with_european_format(string)
        begin
          Date.strptime(string, '%d.%m.%Y')
        rescue
          string_to_date_without_european_format(string)
        end
      end
      def self.string_to_time_with_european_format(string)
        begin
          DateTime.strptime(string, '%d.%m.%Y %H:%M')
        rescue
          string_to_time_without_european_format(string)
        end
      end
      class << self
        alias_method_chain :string_to_date, :european_format
        alias_method_chain :string_to_time, :european_format
      end
    end
  end
end

Restartujte webserver a hotovo. Předefinované metody se v případě neúspěchu s konverzí pokusí zavolat svojí původní verzi, takže se nemusíte bát, že by přestaly fungovat konverze z oblíbených formátů yyyy-mm-dd a jiných.

Comments Bez komentářů »

Možná jste narazili na požadavek nějakým způsobem stylovat jednotlivé položky (option) v helperech select nebo select_tag. Princip je jednoduchý – nejde to. Naštěstí v Rails není problém upravit přímo jejich nějakou část, pokud vám nevyhovuje (většinou pomocí vytvoření nové metody a nastavení aliasu pro původní název). Tenhle konkrétní příklad se dá vyřešit krátkým kusem kódu:

module ActionView
  module Helpers
    module FormOptionsHelper
      def options_for_select_with_styles(container, selected = nil)
        container = container.to_a if Hash === container
        options_for_select = container.inject([]) do |options, element|
          text, value = option_text_and_value(element)
          selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
          css_class = " class=\"#{element[1]}\"" if element[1] && element[1] != value
          options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{css_class}>#{html_escape(text.to_s)}</option>)
        end
        options_for_select.join("\n")
      end
      alias_method_chain :options_for_select, :styles
    end
  end
end

Kód uložte do souboru s názvem form_options_helper.rb do adresře config/initializers a teď už můžete jednoduše jako druhý parametr přidat požadovanou CSS třídu (value se potom přesouvá na třetí místo).

Comments Bez komentářů »

Jako vášnivý čtenář všeho možného na internetu včetně diskuzí narážím semtam na názory „Ruby on Rails jsou buzzword, proto je nebudu používat“ (buzzword = „je to IN, móda, prostě TOHLE TEĎ LETÍ!!!“). Nic víc, žádný důvod, který by měl něco společného s kvalitou/nekvalitou samotného frameworku nebo Ruby jako jazyka. A důvody by se samozřejmě najít daly, Rails nejsou dokonalé a ani Ruby není dokonalé. Důvodem navíc může být i „umím skvěle PHP/Python/Javu a efektivnější je pro mě u toho zůstat“.

Způsob uvažování „je to buzzword, to nechci“ mi uniká a naopak považuji popularitu u open-source projektů za extrémně důležitý faktor. Přitahuje vývojáře a komerční firmy, které často vrací výsledek své práce komunitě. Skvěle je to vidět na jakémkoliv projektu, který je dál rozšiřitelný, například pomocí pluginů: velká komunita = víc rozšíření = méně práce pro další uživatele. Firefox, WordPress, Drupal nebo třeba Apache jsou příklady projektů, které tímto způsobem těží z široké komunity. Další výhodou je dokumentace a podpora. Víc hlav víc ví a hlavně víc hlav má víc času poradit.

Když jsem tohle napsal někomu na diskuzi v Rootu, tak jsem dostal odpověď „víc lidí, větší popularita, víc idiotů na jedné kopě, kteří ti dokáží věc znechutit“. Přiznám se, že jsem to nepochopil. Mezi větším množstvím lidí bude samozřejmě absolutní počet idiotů větší, to dává smysl. Ale nikdo mě přece nenutí komunikovat s lidmi, se kterými komunikovat nechci (ti idioti), tak jak by mi mohli něco znechutit? Prostě je vypustím, nebo je začnu brát jako komický doplněk (skvělý příklad je Astor na Živě.cz, modří určitě vědí). Navíc kdybych se tím chtěl řídit, tak musím přestat používat Windows, Firefox, MySQL a servery přeinstalovat na nějaký neznámý klon Unixu. Co ale budu dělat, když i moje nové alternativy začnou být taky populární?

Pokud se podíváme kousek do minulosti, tak podobným buzzwordem bylo XHTML. Spousta lidí v tom vidělo spásu webu, další spousta začalo hrdě ověšovat své weby ikonkami „XHTML 1.0 Strict Valid“ a někteří přestali používat tabulky i pro tabulky. Přiznám se, že mě to nechalo úplně klidným, ne protože jsem byl nějaký vizionář, ale jednoduše protože jsem byl líný a XHTML mi nic nepřinášelo. Pozdější vývoj udělal tvrdou selekci, XHTML pomalu umírá a přichází HTML5. Dalším příkladem, tentokrát úspěšného buzzwordu byl i Linux. Obrovské úspěchy se sice nekonaly, ale Linux se pomalu rozšiřuje a je to už dlouho seriózní projekt.

Pointa z toho je jednoduchá – nezáleží na tom, jestli je něco buzzword, ve výsledku stejně rozhodne kvalita a buď bublina splaskne, nebo se změní v životaschopný projekt. Takže proč se tím řídit?

Comments Bez komentářů »

Prozatím píšu opravdu krátce – vyšla nová hlavní (major) verze frameworku Ruby on Rails. Přináší spoustu změn, o kterých se pokusím v budoucnosti rozepsat. Pro zájemce prozatím dávám odkaz na oficiální informace o vydání.

Comments Bez komentářů »

Nejdřív jsem byl trochu udivený, že na tuhle typickou činnost neexistuje v Rails žádný plugin, ale pak mi to došlo – není moc potřeba. Google odhalil jeden užitečný kus kódu, který jsem pro větší přehlednost trochu přepsal a celé použil jako metodu třídy Password. V této podobě generuje náhodná hesla obsahující znaky a-z a 0-9, výchozí délka hesla, pokud generátor zavoláte bez parametru, je 8. Pro použití v Rails celý kód zkopírujte do souboru lib/password.rb a potom budete moci z kteréhokoliv místa kódu volat Password.generate.

class Password
 
   ALLOWED_CHARS = ('a'..'z').to_a + ('0'..'9').to_a
 
   def Password.generate(length = 8)
      password = ''
      while password.length < length
         password << ALLOWED_CHARS[Kernel.rand(ALLOWED_CHARS.length)]
      end
      password
   end
 
end

Comments Bez komentářů »

Sitepoint nabízí zdarma ke stažení knihu „Build Your Own Ruby on Rails Web Applications“ na adrese http://rails.sitepoint.com. Nabídka platí po dobu 60 dnů (z nichž 18 už uplynulo, než mě napadlo o tom napsat), pouze zadáte svůj mail a obratem vám přijde odkaz ke stažení. Knížka mi přišla kvalitní, ne tak rozsáhlá jako Agile Web Development with Rails 2nd edition, ale pro začátečníky v Ruby on Rails rozhodně použitelná (trochu více se o tom rozepsal Jamis Buck na svém blogu).

Comments Bez komentářů »

Pokud používáte Ruby on Rails, tak téměř určitě je máte nainstalované z RubyGems – balíčkovacího systému pro Ruby, který umožňuje jednoduchou a pohodlnou instalaci aplikací nebo knihoven. Při postupných updatech gemů se vám může stát, že za chvilku máte od některých hromadu verzí (u Rails se mi to stává běžně). Pokud starší verze nepotřebujete, například kvůli zpětné kompatibilitě, tak se jich můžete rychle zbavit příkazem cleanup:

gem cleanup

Comments Bez komentářů »

Rails obsahují už delší dobu podporu pro stránkování pomocí klasického

@foo_pages, @foo = paginate(:foo, :order => 'bar' )

Problém je, že jde o trochu podivný zápis, vestavěné stránkování je nedoporučované kvůli mizernému výkonu a navíc ve verzi 2.0 bude kompletně odstraněno. Jedna možnost jak ho nahradit je napsat si vlastní, druhá využít skvěle fungujícího ekosystému pluginů. Já jako typický Rails programátor (tedy líný a nesnášející psaní rutinních věcí) jsem sáhl po druhé možnosti. Google po chvilce hledání odhalil skvělý plugin will_paginate. Proč je tak skvělý? Je jednoduchý na používání a dělá přesně co je potřeba.

Instalace klasicky v adresáři vaší aplikace:

ruby script/plugin install svn://errtheblog.com/svn/plugins/will_paginate

Samotné použití je jednoduché – prostě nahradíte volání find() objektu ActiveRecord za volání paginate a předáte mu parametr :page => params[:page], například takhle:

@foos = Foo.paginate(:all, :page => params[:page])

Výchozí počet záznamů na stránku je 15, změnit to můžete buď při volání paginate pomocí parametru :per_page nebo globálně pro určitý model přidáním metody per_page:

class Foo < ActiveRecord::Base
    def self.per_page
        50
    end
    ...
end

Kromě toho samozřejmě můžete používat všechny ostatní parametry známé z find. will_paginate vám poskytne i užitečný helper pro přepínání stránek, který přidáte do view takto:

<%= will_paginate @foos %>

Vzhled helperu můžete kompletně změnit pomocí CSS a autoři pamatovali i na možnost změnit anglické Previous a Next bez potřeby předefinování helperu. Do config/environment.rb jenom přidejte:

WillPaginate::ViewHelpers.pagination_options[:prev_label] = '&laquo; Předchozí'
WillPaginate::ViewHelpers.pagination_options[:next_label] = 'Další &raquo;'

To je vše a můžete vesele stránkovat.

Comments Bez komentářů »

Pokud generujete URL v odesílaných e-mailech, tak logicky potřebujete, aby byly absolutní. Na druhou stranu psát absolutní URL do kódu je nepohodlné kvůli testování. Samozřejmě je možný výsledný URL zkopírovat do prohlížeče a tam ručně změnit adresu, ale to zkrátka není ono. Řešením je nastavit výchozí parametry pro volání url_for.

V ActionMaileru nejsou potřebné proměnné k dispozici, takže je musíte předat při vytváření e-mailu:

class FooController < ApplicationController
	def send_email
		url_options = {:host => request.host, :protocol => request.protocol.gsub('://', '')}
		url_options[:port] = request.port unless [80, 443].include?(request.port)
		mail = FooMailer.create_bar(url_options)
		...
	end
end

Tělo ActionMaileru potom vypadá takto:

class FooMailer < ActionMailer::Base
	include ActionController::UrlWriter
	def bar(url_options)
		...
		default_url_options.merge!(url_options)
	end
end

V šabloně e-mailu potom můžete normálně používat url_for s parametrem :o nly_path => false. Stejně tak musíte vždy explicitně definovat kontroler, neplatí že by byl použitý kontroler, ze kterého bylo voláno vytvoření e-mailu:

<%= link_to('click here',  url_for(:only_path => false, :controller => 'foo', :action => 'index')) %>

Comments Bez komentářů »

Tohle je další věc, která nefunguje out-of-box. Pokud zkusíte url_for nebo cokoliv podobného v šablonách ActionMaileru, nikam se nedostanete. V dokumentaci je navíc poměrně depresivní upozornění, že to zkrátka nejde. Naštěstí to jde, stačí includovat UrlWriter:

class EshopOrderMailer < ActionMailer::Base
	include ActionController::UrlWriter
	....
end

Comments Bez komentářů »