Ruby - 作用域方法调用当前类

时间:2016-05-19 15:27:59

标签: ruby-on-rails ruby

在我们正在构建的当前Rails应用程序上,用户可以拥有公司范围的首选项,用户特定首选项或项目特定首选项。当用户创建采购订单时,我需要聚合所有这些首选项并在订单上设置相应的属性。我从项目首选项开始,继续上层,直到我收集所有属性,如下所示。

  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

并调用该方法,如下所示

StagePreferences.new(project, current_user).stage

我遇到一个问题,当我从UserPreferences类调用set_preferences方法时(因为没有为此项目设置首选项),来自UserPreferences的set_department被调用,返回如下错误?

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 个答案:

答案 0 :(得分:2)

Ruby的动态调度使用接收器上方法的“深度优先”搜索,这意味着您的ProjectPreferences#set_department方法将始终被调用,并且您的'UserPreferences#set_department'方法永远不会被调用(仅供参考,FYI,它看起来你在这个方法中有一个错字?)。

可以使用Ruby的instance_method方法在当前层次结构中调用此方法:

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

允许您在自己上调用此“无法访问”方法,就像ProjectPreferences没有覆盖它一样。

但是,我要问有这么多Preference子类的要求,正如这个问题所强调的那样,类层次结构中的调试问题变得越来越复杂。