Tymon Tobolski

Merb: flash

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


comments powered by Disqus

Read more