2016-05-19 8 views
0

In einer aktuellen Rails-App, die wir erstellen, kann ein Benutzer firmenweite Voreinstellungen, benutzerspezifische Voreinstellungen oder projektspezifische Voreinstellungen haben. Wenn ein Benutzer eine Bestellung erstellt, muss ich alle diese Einstellungen zusammenfassen und die entsprechenden Attribute für die Bestellung festlegen. Ich beginne mit den Projekteinstellungen und gehe weiter in die Hierarchie, bis ich alle Attribute wie unten beschrieben gesammelt habe.Ruby - Scoping-Methode ruft aktuelle Klasse auf

class Preferences 

    def initialize(project, user) 
     @preferences = Preferences.new 
     @project = project 
     @user = user 
    end 

    def stage 
    end 

    def set_preferences 
     set_department 
    end 

    End 


    class UserPreferences < Preferences 

    def initialize(project, user) 
    super(project, user) 
    @user_preferences = nil 
    end 

    def stage 
    @user_preferences = @user.preferences 
    set_preferences if @user_preferences.present? 
    super unless @preferences.valid? 
    end 


    def set_department 
    @preferences ||= @user_preferences.dept 
    end 

    end 

    class ProjectPreferences < UserPreferences 

    def initialize(project, user) 
    super(project, user) 
    @project_preferences = nil 
    end 

    def stage 
    @project_preferences = @project.preferences 
    set_preferences if @project_preferences.present? 
    super unless @preferences.valid? 
    end 

    def set_department 
     @preferences.dept ||= @project_preferences.dept 
    end 

    end 

    def StagePreferences < ProjectPreferences 

    def initialize(project, user) 
    super(project, user) 
    end 

    def stage 
    super 
    @preferences 
    end 

    end 

und das Verfahren, wie ich in ein Problem leite unter

StagePreferences.new(project, current_user).stage 

aufgerufen, wo, wenn ich die set_preferences Methode aus der Benutzereinstellungen Klasse aufrufen (weil es keine für dieses Projekt eingestellt Präferenzen waren), Die set_department von UserPreferences wird aufgerufen, die einen Fehler wie folgt zurückgibt?

NoMethodError: undefined method `dept' for nil:NilClass 
from /home/rails/tools/ss/lib/preferences/project_preferences.rb:27:in `set_department' 
from /home/rails/tools/ss/lib/preferences/preferences.rb:26:in `set_preferences' 
from /home/rails/tools/ss/lib/preferences/user_preferences.rb:17:in `stage' 
from /home/rails/tools/ss/lib/preferences/stage_preferences.rb:23:in `stage' 
from /home/rails/tools/ss/lib/preferences/project_preferences.rb:17:in `stage' 
from /home/rails/tools/ss/lib/preferences/stage_preferences.rb:8:in `stage' 
from (irb):8 
from /home/rails/.rvm/gems/ruby-2.2.1/gems/railties-4.0.13/lib/rails/commands/console.rb:90:in `start' 
from /home/rails/.rvm/gems/ruby-2.2.1/gems/railties-4.0.13/lib/rails/commands/console.rb:9:in `start' 
from /home/rails/.rvm/gems/ruby-2.2.1/gems/railties-4.0.13/lib/rails/commands.rb:62:in `<top (required)>' 
from bin/rails:4:in `require' 
from bin/rails:4:in `<main>' 
+1

Sie weisen 'nil' eine' @ user_preferences'-Variable zu und versuchen, 'dept'-Methode für' nil' aufzurufen. Überprüfen Sie die aktuelle Logik Ihrer Klassen. –

+0

Danke, aber @user_preferences wird nur während der Initialisierung auf Null gesetzt. Der Fehler wird von der ProjectPreferences-Klasse ausgelöst, die die set_department für die UserPreferences-Klasse aufruft. Ich muss es nur auf die Methode in der ProjectPreferences-Klasse beschränken. –

+0

Sieht so aus, als gäbe es mehr Code, den du nicht zeigst. Was ist auf stage_preferences.rb: 23? –

Antwort

2

Rubys Dynamische Dispatch eine ‚Tiefe zuerst‘ Suche nach den Methoden, die auf dem Empfänger verwendet, die Ihre ProjectPreferences#set_department Methode bedeutet immer aufgerufen, und Ihre ‚Benutzereinstellungen # set_department‘ Methode wird nie (FYI aufgerufen, es sieht aus wie du einen Tippfehler in dieser Methode hast?).

Es ist möglich, diese Methode in der aktuellen Hierarchie instance_method Methode des mit Ruby anrufen über:

UserPreferences.instance_method(:set_department).bind(self).call 

Welche Sie diese ‚nicht erreichbar‘ Methode auf sich selbst aufrufen können, als ob ProjectPreferences es nicht außer Kraft gesetzt hatte.

Allerdings würde ich die Anforderung, so viele Präferenzunterklassen zu haben, in Frage stellen, wie diese Frage hervorhebt, Debugging-Probleme in der Klassenhierarchie werden zunehmend komplexer.

+0

Ich wollte vermeiden, einzelne Klassenmethoden aufzurufen, und ich kann die einzelnen Instanzmethoden lieber umbenennen und sie direkt aus der UserPreferences-Klasse aufrufen. Der einzige Vorteil, den ich mit instance_method erreichen kann, ist die Verwendung derselben Methodennamen, die keinen Zweck mehr erfüllen. Habe ich das richtig verstanden? –

+0

Die Sache ist, dass, wenn es #set_department in Preferences # set_preferences aufruft, aber StagePreferences oder ProjectPreferences-Instanz verwendet, um es im Interpreter aufzurufen, nach #set_department von 'bottom' der Hierarchie (StagePreferences-Klasse) sucht und nach oben geht, bis das erste Vorkommen gefunden wird (ProjectPreferences # set_department). Sie können also nicht auf UserPreferences # set_department zugreifen, es sei denn, Sie verwenden die UserPreferences-Instanz direkt und nicht das untergeordnete Element. Hoffe das ist klar – Leaf