【问题标题】:Access a Ruby module's method within same module在同一模块中访问 Ruby 模块的方法
【发布时间】:2016-03-02 12:15:05
【问题描述】:

我是 Ruby 新手,可能不懂一些基本的东西:

我正在尝试这个:

# lib/common_stuff.rb
module CommonStuff
  def self.common_thing
    # code
    @x = second_thing # --> should access method in same module. Doesn't work.
  end
  def self.second_thing
    # code
  end
end

# app/controllers/my_controller.rb
require 'common_stuff'
class MyController < ApplicationController
  include CommonStuff
  y = self.common_thing # accesses the Module method -> works
end

错误:

NoMethodError(未定义的方法 `second_thing' MyController:0x000000088d8990): lib/common.rb:7:in 'common_thing'

我尝试了模块和实例方法。此外,仅将 second_thing 声明为实例方法或 Module 中的两种方法都声明为实例方法是行不通的。我有什么误解?

** 编辑更正**

我意识到我的错误是使方法成为类方法(带有 self. 前缀)。没有它,它实际上是有效的。以为我试过了,但我昨天一定是瞎了。所以工作代码是(只是一个构造的例子——通常我当然不会实例化控制器):

# lib/common_stuff.rb

module CommonStuff
  def common_thing
    @x = second_thing # -->  access method in same module.  Works now too. 
  end

  def second_thing
    10
  end
end

# app/controllers/my_controller.rb


require 'common_stuff.rb'

class MyController

  include CommonStuff

  def a_class
    y = common_thing # accesses the Module method -> works
    puts y
  end
end

ctrl = MyController.new
ctrl.a_class

【问题讨论】:

  • second thing 被定义为类方法,但在您的模块中被调用为实例方法。
  • @harishsr:ruby 中没有“类方法”。每个方法都是一个实例方法(这里的实例是当前self 是什么)
  • 好的;确实,现在它不再起作用了。我不知道我以前在做什么。在上面的片段中,我忘记在 MyController 类中编写 Method 定义——但这不是问题。所以让我问一下:如果你有两个 Rails 控制器,它们都共享两种方法(其中第二种方法由第一种方法使用)。你会把这两种方法放在哪里?进入一个模块,使用 7stud 的答案中所示的钩子方法,或者可能进入一个关注点?
  • 这进一步混淆(注入的钩子似乎没有必要):yehudakatz.com/2009/11/12/better-ruby-idioms

标签: ruby-on-rails ruby


【解决方案1】:

我误会了什么?

1) @variable 是私有的,因此您始终需要提供访问器方法来访问它(或使用 instance_variable_get() 侵犯隐私):

module CommonStuff
  def common_thing
    @x = second_thing # --> should access method in same module. Doesn't work.
  end

  def second_thing
    10
  end
end


class MyController 
  include CommonStuff

  attr_accessor :x
end

obj = MyController.new
obj.common_thing
puts obj.x

--output:--
10

2) 不能包含模块的类方法:

module CommonStuff
  def self.common_thing
    puts 'hello'
    @x = second_thing # --> should access method in same module. Doesn't work.
  end

  def self.second_thing
    10
  end
end

class MyController 
  include CommonStuff
end


CommonStuff.common_thing
MyController.common_thing

--output:--
hello

1.rb:21:in `<main>': undefined method `common_thing' for MyController:Class (NoMethodError)

#obj = MyController.new  
#obj.common_thing   #Same error here

如果你想在 MyController 中注入一些类方法,你需要重写你的 CommonStuff 模块:

module CommonStuff
  def self.included(includer)  #Advanced 'hook' method
    includer.extend ClassMethods
  end

  module ClassMethods
    def common_thing
      puts 'hello'
      @x = second_thing # --> should access method in same module. Doesn't work.
    end

    def second_thing
      10
    end
  end
end

class MyController 
  include CommonStuff
  y = common_thing
  puts y

  puts instance_variable_get(:@x)
end

--output:--
10
10

只要模块被另一个类/模块包含,就会调用钩子方法,并且该方法作为参数传递包含的类/模块。

对评论的回应:

只有控制器的实例变量在视图中可用,例如:

class MyController

   def do_stuff
     @x = 10  #instance variable
   end

end

但是在类方法中创建的@variables不是控制器的实例变量:

class MyController

   def self.do_stuff
     @x = 10  
   end

end

因此,在类方法中创建的@variables 在视图中将不可用。

【讨论】:

  • 实例化控制器没有意义。
  • 好的,私有变量将仅在 Rail 视图中使用。据我了解,是这样的。如我错了请纠正我。我将尝试类注入方式,这似乎是我的情况。谢谢
  • @PhilippeAddor,请在我的回答末尾查看我对您的评论的回复。
  • 啊哈!这是一个非常有价值的输入。我不知道那个小而重要的细节。谢谢7stud。
  • 我意识到我并没有尝试将类方法包含在内,而是将实例方法包含到控制器中。我现在通过将两个实例方法放入帮助模块而不是“标准”模块来实现我想要的代码可重用性。这对我来说更直接。现在,我可以在包含帮助程序的两个不同控制器中访问这两种外包方法。恐怕这不是最佳做法......
猜你喜欢
  • 1970-01-01
  • 2012-03-19
  • 1970-01-01
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 2016-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多