在Rails 4

时间:2015-07-16 18:37:45

标签: ruby-on-rails ruby ruby-on-rails-4 class-method

我有以下型号:

class ActivityLog < ActiveRecord::Base
  validates :user_id, :instance_id, :action, presence: true
  validates :user_id, :instance_id, :action, numericality: true

  def log
    ActivityLog.create(
      user_id: current_user ? current_user.id : -1,
      instance_id: instance_id,
      action: actions.index(action)
      )
  end

  private 

  def actions
    ['start','stop','create','destroy']
  end

end

当我从rails控制台调用以下行时,出现错误:

ActivityLog.log(user_id: 1, instance_id:1, action: 'create')

# Error returned from console
NoMethodError: undefined method `log' for #<Class:0x007fb4755a26a8>

为什么我的方法调用不起作用?我在课堂上定义了它,但它说它是未定义的。我错过了什么或误解了什么?谢谢。

3 个答案:

答案 0 :(得分:9)

创建方法log

假设您有一个班级User,并在班级中定义方法has_cell_phone。 (该方法的内容无关紧要。)当您将类中的方法定义为def has_cell_phone时,可以在任何User对象上调用该方法。虽然class User本身是对象,但您可以在其直接类为User的对象上调用它。正确地说,您将为User类的实例编写实例方法

您收到该错误,因为您定义的方法log仅适用于ActivityLog类的_instance。如果您执行以下操作,则可以根据当前代码正确调用log

activity_log = ActivityLog.create  # with required params
activity_log.log

其次,您使用参数调用log,而您的方法定义不需要任何参数。 (这看起来像def log(params)。)

现在,您可以在此处修改现有代码。如果要在整个类(意味着类本身)上调用方法,则将关键字self添加到类方法定义中。例如,对于User类,它将是def self.create_user_with_cell_phone。您还可以向该方法添加参数。您在“方法调用”行中提供的参数,我会将它们添加到您的类方法中,如下所示:

def self.log(instance_id, action)
  # ...
end

ActivityLog.log(1, 'create')

您不需要包含user_id,因为根据您的逻辑,它会检查current_user对象是否为true,并从那里开始。

创建类常量

再看一下你的问题,我发现你正在定义一个方法actions。还记得我对实例方法的看法吗?由于actions似乎始终保持不变,我建议您将其设为一个!为此,建议您在任何方法定义之前在类中放置以下行。

ACTIONS = ['start','stop','create','destroy']

然后,只要您想在ACTIONS课程内召唤ActivityLog,就可以执行以下操作:ACTIONS.index(action)。如果你想在它的类中调用 之外的常量,你可以这样做:ActivityLog::ACTION。它是类似方法调用的类似语法,而是使用::将类与常量分开。重新检查您的代码,它现在应该是这样的:

class ActivityLog < ActiveRecord::Base
  ACTIONS = ['start','stop','create','destroy']

  validates :user_id, :instance_id, :action, presence: true
  validates :user_id, :instance_id, :action, numericality: true

  def self.log(instance_id, action)
    ActivityLog.create(
      user_id: (current_user ? current_user.id : -1),
      instance_id: instance_id,
      action: ACTIONS.index(action)
    )
  end
end

答案 1 :(得分:2)

log是定义的实例方法;它只有在你拥有ActivityLog的具体实例时才有效。

如果你想把它作为一个类方法,你应该通过self关键字将它附加到课堂上。

def self.log
    # code here
end

答案 2 :(得分:0)

您正在编写实例方法并将其称为类方法。

要编写类方法,您需要在方法名称(selfself.log)之前添加self.actions。这将让你像预期的那样调用方法,并且可能是编写这样的替代构造函数的最佳方法。如果你的方法不依赖于类的特定实例,这似乎是你在这里做的,那么最好使它们成为类方法。

或者,您可以创建类的实例并调用已定义的实例方法。使用ActivityLog.log创建一个新的记录器而不是Activity.new,并在其上调用log方法。在一行中,这看起来像Activity.new.log,但您应该将新对象存储在变量中以跟踪它。

最后一种选择是使用initialize方法。通过撰写def initialize,您可以更改班级的构造函数,这样您就可以调用ActivityLog.log而不是调用ActivityLog.new。这使得您更清楚的是构建一个新对象并且在ruby中是惯用的。但是,它确实删除了描述性方法名称。如果你不打算用任何其他方法构建你的类,我会推荐这条路线,但是如果你想要几个,那就去使用类方法。