Forum: Rails Germany [plugin dev.] Klassenmethode analog zu before_filter

40f541f2a6a003ffbbad24ed9b1f748f?d=identicon&s=25 Kjell S. (metafoo)
on 2009-06-27 13:53
Hallo zusammen,

gibt es eine Möglichkeit, via Plugin eine Klassenmethode im
ApplicationController zu platzieren, welche auf die folgende Art und
Weise aufgerufen werden kann:

ApplicationController < ActionController::Base

  load_widget :sidebar, :quicksearch

end

Das Problem hierbei ist, dass der ApplicationController bereits vor dem
Laden der Plugins eingebunden zu werden zu scheint.

Gibt es generell best practices zur Implementierung solcher Methoden
über Plugins? Genauer geht es darum, wo ich in diesem Falle
Informationen ablegen kann, da beim Aufruf der Methode aus diesem
Kontext heraus ja noch kein Objekt der Klasse existiert.
Derzeit lege ich herfür eine Klassenvariable an, bin mir aber nicht
sicher, ob das so eine gute Lösung ist.

Grüße
Bce1d1b7c3ec7b577dcb42e254899e6b?d=identicon&s=25 Michael Schuerig (Guest)
on 2009-06-27 15:56
(Received via mailing list)
On Saturday 27 June 2009, Wer Sie wrote:
> end
Muss es ein Plugin sein? Du könntest die Methode doch einfach *im*
ApplicationController definieren:

ApplicationController < ActionController::Base
  def self.load_widget
    ...
  end
  load_widget :sidebar, :quicksearch
end

Falls du wirklich ein Plugin brauchst, dann solltest du die gewünschte
Methode in einer Erweiterung für ActionController::Base definieren:

# vendor/plugins/wer_sie_widgets/lib/wer_sie/controller_extensions.rb
module WerSie
  module ControllerExtensions
    def self.included(base)
      base.extend(SingletonMethods)
    end
    module SingletonMethods
      def load_widget
        ...
      end
    end
  end
end

# vendor/plugins/wer_sie_widgets/rails/init.rb
ActionController::Base.class_eval do
  include WerSie::ControllerExtensions
end


> Gibt es generell best practices zur Implementierung solcher Methoden
> über Plugins? Genauer geht es darum, wo ich in diesem Falle
> Informationen ablegen kann, da beim Aufruf der Methode aus diesem
> Kontext heraus ja noch kein Objekt der Klasse existiert.
> Derzeit lege ich herfür eine Klassenvariable an, bin mir aber nicht
> sicher, ob das so eine gute Lösung ist.

Geht es um Konfigurationsinformationen? Dann sind
class_inheritable_attribute und Konsorten wahrscheinlich besser. Siehe

gems/1.8/gems/activesupport-2.3.2/lib/active_support/core_ext/class/inheritable_attributes.rb

Wahrscheinlich ist es auch sehr hilf- und lehrreich, wenn du dir den
Code von ein paar Plugins/Gems ansiehst, die etwas ähnliches machen, wie
das, was du erreichen willst.

Michael

--
Michael Schuerig
mailto:michael@schuerig.de
http://www.schuerig.de/michael/
40f541f2a6a003ffbbad24ed9b1f748f?d=identicon&s=25 Kjell S. (metafoo)
on 2009-06-27 18:31
Hi,

das Ganze soll als Plugin eingebunden werden, hinter der Methode
verbirgt sich noch etwas mehr...
Sorry, ich hätte mich klarer ausdrücken sollen, das entwprechende Modul,
welches in den ApplicationController gemixt werden soll, habe ich
bereits geschrieben.

Wenn ich meine Methode nun in einem konkreten Controller aufrufe,
funktioniert das Ganze auch wunderbar. Sobald ich die Methode jedoch im
ApplicationController aufrufe, bricht Rails beim Starten des Servers ab,
da die Methode nicht bekannt sei.

Füge ich den Methodenaufruf jedoch erst nach dem Starten des Servers im
ApplicationController hinzu, funktioniert es.

Kann mir das irgendwie nicht erklären :-/.

Hier mal meine Code dazu in Ausschnitten:

init.rb:
module WidgetPool
  class << self
    def enable
      ActionView::Base.send :include, ViewHelpers
      ActionController::Base.send :include, Loader
    end
  end
end

WidgetPool.enable

widget_pool.rb:
module WidgetPool
  module Loader
    def self.included base
      base.extend ClassMethods
    end

    module ClassMethods
      def load_widget pool, *options
        [...]
      end
      [...]
    end
  end
end
Bce1d1b7c3ec7b577dcb42e254899e6b?d=identicon&s=25 Michael Schuerig (Guest)
on 2009-06-27 19:06
(Received via mailing list)
On Saturday 27 June 2009, Kjell S. wrote:
> Wenn ich meine Methode nun in einem konkreten Controller aufrufe,
> funktioniert das Ganze auch wunderbar. Sobald ich die Methode jedoch
> im ApplicationController aufrufe, bricht Rails beim Starten des
> Servers ab, da die Methode nicht bekannt sei.

Das klingt so, als ob die ApplicationController-Klasse aus irgendeinem
Grund geladen wird, bevor dein Plugin ActionController::Base um die
benötigte Methode erweitert.

> Füge ich den Methodenaufruf jedoch erst nach dem Starten des Servers
> im ApplicationController hinzu, funktioniert es.

Daraus kann ich nicht entnehmen, was du machst. Das gilt auch für den
Rest deiner Beschreibung. Im Nebel stochern kann man damit, dir
ernsthaft helfen nicht.

Michael

--
Michael Schuerig
mailto:michael@schuerig.de
http://www.schuerig.de/michael/
056c32203f8017f075ac060069823b66?d=identicon&s=25 peter schröder (Guest)
on 2009-06-27 19:58
(Received via mailing list)
vielleicht hilft dir das hier weiter:

http://railsguts.com/initialization.html


Am 27.06.2009 um 18:31 schrieb Kjell S.:
40f541f2a6a003ffbbad24ed9b1f748f?d=identicon&s=25 Kjell S. (metafoo)
on 2009-06-28 15:50
Ah, nach stundenlangem Suchen, HowTos und Quellcode lesen habe ich die
Ursache endlich gefunden.
Mein Plugin enthält eine Klasse, welche von ApplicationController erbt,
was wohl erklärt, dass dieser zu früh geladen wird.

Jetzt könnte ich diese Datei natürlich einfach laden, nachdem ich
ActionController::Base erweitert habe, was aber sich zu eventuellen
Problemen mit anderen Plugins führen könnte :-/.

Ich brauche in dieser Klasse Zugriff auf die Methoden und Attribute des
ApplicationController. Welche Möglichkeiten bleiben noch, um das zu
erreichen?
40f541f2a6a003ffbbad24ed9b1f748f?d=identicon&s=25 Kjell S. (metafoo)
on 2009-06-28 22:21
> Geht es um Konfigurationsinformationen? Dann sind
> class_inheritable_attribute und Konsorten wahrscheinlich besser. Siehe

Hi Michael,

ich möchte nocheinmal kurz auf das ablegen von Information innerhalb der
Klassenmethode zurückkommen.
Hierzu habe ich ein Objekt, in welchem ich diverse Informationen
speichere. Diese gelten aber nur für den aktuellen Request. Wenn ich
dieses nun aber in einer Klassenvariable im Controller ablege, sind (in
production) alle Daten aus dem vorheriegen Request noch vorhanden.
Also wohin damit, so dass ich bei jedem Request wieder ein
jungfräuliches Objekt habe? ;-)


Danke & Grüße
Kjell
4d9dd9bd8d3d4d0ba8af2acc41d14006?d=identicon&s=25 Mathias Meyer (mattmatt)
on 2009-06-28 22:43
(Received via mailing list)
2009/6/28 Kjell S. <lists@ruby-forum.com>:

> ich möchte nocheinmal kurz auf das ablegen von Information innerhalb der
> Klassenmethode zurückkommen.
> Hierzu habe ich ein Objekt, in welchem ich diverse Informationen
> speichere. Diese gelten aber nur für den aktuellen Request. Wenn ich
> dieses nun aber in einer Klassenvariable im Controller ablege, sind (in
> production) alle Daten aus dem vorheriegen Request noch vorhanden.
> Also wohin damit, so dass ich bei jedem Request wieder ein
> jungfräuliches Objekt habe? ;-)
>
Innerhalb einer Singleton-Methode an der Klasse ActionController::Base
koenntest du z.B. einen Filter erstellen a la:

attr_accessor :widgets

def self.load_widget(*widgets)
  before_filter do |controller|
    controller.widgets = widgets
  end
end

Die Magie von Closures erledigt hier den rest.

Cheers, Mathias
40f541f2a6a003ffbbad24ed9b1f748f?d=identicon&s=25 Kjell S. (metafoo)
on 2009-06-30 10:39
Besten Dank! :)
This topic is locked and can not be replied to.