【问题标题】:Ruby on Rails instance vs class methodsRuby on Rails 实例与类方法
【发布时间】:2015-10-20 13:38:15
【问题描述】:

我研究了 Ruby 类、实例方法之间的主要区别,我发现的主要区别是我们不需要创建该类的实例,我们可以直接在类名上直接调用该方法。

class Notifier 

def reminder_to_unconfirmed_user(user)
    headers['X-SMTPAPI'] = '{"category": "confirmation_reminder"}'
    @user = user
    mail(:to => @user["email"], :subject => "confirmation instructions reminder")
  end

end

因此,我在 Notifier 类中定义了实例方法 reminder_to_unconfirmed_user 以向未经确认的用户发送电子邮件,当我运行 Notifier.reminder_to_unconfirmed_user(User.last) 时,它会被调用,前提是它是实例方法而不是类方法。

【问题讨论】:

  • 问题是什么?
  • 他的问题是为什么可以在类上调用实例方法,就好像它是类方法一样。在下面发布了答案。

标签: ruby-on-rails ruby


【解决方案1】:

要定义类方法,请在方法定义(或类名)中使用self 关键字:

class Notifier
  def self.this_is_a_class_method
  end

  def Notifier.this_a_class_method_too
  end

  def this_is_an_instance_method
  end
end

在您的情况下,reminder_to_unconfirmed_user 应定义为类方法:

class Notifier 

  def self.reminder_to_unconfirmed_user(user)
    # ...
  end

end

那么你可以这样使用它:

Notifier.reminder_to_unconfirmed_user(User.last)

【讨论】:

    【解决方案2】:

    我也有同样的问题,OP 提出了同样的问题,在四处挖掘之后,我终于弄明白了!其他答案只是解决了何时在 Ruby 中使用实例与类方法,但是 Rails 在幕后做了一些偷偷摸摸的事情。问题不在于何时使用类与实例方法,而是 Rails 如何允许您调用实例方法,就好像它是上面他的邮件示例所示的类方法一样。这是由于:AbstractController::Base,可以在这里看到:AbstractController::Base

    基本上,在所有控制器中(无论是您的邮件程序还是标准控制器),所有定义的方法都会被“method_missing”拦截,然后返回该类的实例!然后定义的方法也被转换为公共实例方法。因此,因为您从不实例化这些类(例如,您从不执行 Mailer.new.some_method),Rails 会自动调用 method_missing 并返回该 Mailer 的实例,然后该实例利用该类中定义的所有方法。

    【讨论】:

      【解决方案3】:

      在你的情况下它必须是:

      class Notifier 
      
        def self.reminder_to_unconfirmed_user(user)
          headers['X-SMTPAPI'] = '{"category": "confirmation_reminder"}'
          @user = user
          mail(:to => @user["email"], :subject => "confirmation instructions reminder")
        end
      
      end
      

      顾名思义:

      模型上的实例方法应该用于与模型的特定实例(调用该方法的实例)相关的逻辑/操作。

      类方法适用于不对模型的单个实例进行操作的事物,或者适用于您没有可用实例的情况。就像在某些情况下,您确实想对几组对象应用更改。 如果您想在特定条件下更新所有用户,那么您应该使用类方法。

      他们确实有不同的调用方式:

      class Test
        def self.hi
          puts 'class method'
        end
      
        def hello
          puts 'instance method'
        end
      end
      
      Foo.hi # => "class method"
      Foo.hello # => NoMethodError: undefined method ‘hello’ for Test:Class
      
      Foo.new.hello # => instance method
      Foo.new.hi # => NoMethodError: undefined method ‘hi’ for #<Test:0x1e871>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多