teamon.eu

blah blah blah

Merb - flash

31 października 2008

Kategorie:

Tagi:

  • Flash
  • Merb
  • Ruby

UPDATE: Zamiast calej zabawy - plugin merb-flash :)

Kontynuując serię o sztuczkach w Merbie tym razem przedstawię coś, czego najbardziej mi zabrakło - railsowego flasha.

Twórcy Merba zrezygnowali z takiego rozwiązania, i postawili na dodatkowy parametr _message przekazywany w url jako zakodowany ciąg znaków.

redirect resource(@product), :message => "Product was successfully created"

Jednak według mnie to rozwiązanie jest po prostu brzydkie. Podpatrując nieco z pluginu merb_has_flash zamieniłem ów :message na wersję wykorzystującą sesje bez zmieniania API.

 
# lib/flash.rb
 
class Flash
  def initialize(*args)
    @attrs = Mash.new(*args)
    @keepers = []
  end
 
  def []=(key, value)
    @attrs[key] = value
    keep key
  end
 
  def update(hash)
    @attrs.update(hash)
    hash.keys.each {|key| keep key}
  end
 
  def method_missing(method_name, *args, &block)
    @attrs.send(method_name, *args, &block)
  end
 
  def keep(key)
    key = key.to_s
    @keepers << key unless @keepers.include?(key)
  end
 
  def sweep
    @attrs.keys.each {|key| @attrs.delete(key) unless @keepers.include?(key)}
    @keepers = []
  end
end
 
class Merb::Request
  def message
    session['flash'] || {}
  end
end
 
class Merb::Controller
  after :sweep_flash
  def sweep_flash
    session["flash"].sweep if session["flash"]
  end
 
  def redirect(url, opts = {})
    default_redirect_options = { :message => nil, :permanent => false }
    opts = default_redirect_options.merge(opts)
    if opts[:message]
      opts[:message] = {:notice => opts[:message]} unless opts[:message].is_a?(Hash)
      session['flash'] = Flash.new unless session['flash'].is_a?(Flash)
      session['flash'].update(opts[:message])
    end
    self.status = opts[:permanent] ? 301 : 302
    Merb.logger.info("Redirecting to: #{url} (#{self.status})")
    headers['Location'] = url
    "<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
  end
end
 

Jak już wspomniałem, sposób użycia się w zasadzie nie zmienia. Jedyną zmianą jest to, że gdy podamy jako parametr :message ciąg znaków to zamieni się on na {:notice => "nasza wiadomosc"}. Dzięki temu nie musimy pisać:

redirect resource(@product), :message => {:notice => "Product was successfully created"}
aby odróżnić potem typ wiadomości. Jeśli chcemy wyświetlić error to nic nie stoi na przeszkodzie aby zapisać:
redirect url(:default), :message => {:error => "Product not found"}

Wyświetlanie wiadomości podobnie jak w Rails: (wersja haml)

 
- message.each_pair do |type, msg|
  = tag :div, msg, :class => type.to_s, :id => "flash"
 

W celu załadowania tej "poprawki" dopisujemy do pliku conifg/init.rb

require "lib/flash.rb"
lub
Merb.push_path(:lib, Merb.root / "lib")
Przy drugim sposobie zostaną automatycznie załadowane wszystkie pliki z katalogu lib

Warto jeszcze wspomnieć, że patch działa razem z merb-auth.

Do zobaczenia w następnym odcinku :P

5 komentarzy

  • gość 26 listopada 2008 10:02:33

    wielkie dzieki!

  • test 28 listopada 2008 18:50:11

    test

  • Drogomir 22 grudnia 2008 22:26:22

    Wrzuć to jako plugin :)

  • Drogomir 22 grudnia 2008 22:30:07

    Jak teraz przyjrzałem się bliżej temu snippetowi, to widzę, że nadpisałeś metodę redirect. Filozofia merba jest taka, że jeżeli musisz użyć monkey patchingu, żeby coś zmienić w merbie, to jest to bug.

    Spytaj się na google groups, albo na ircu o coś takiego - może udałoby się zrobić bez monkey patchingu.

  • Teamon 22 grudnia 2008 22:37:22

    Raczej nie ma innej opcji - to jest zupełny zamiennik message.

Zostaw komentarz

code