如何在Ruby on Rails中引用模型类中的模型实例?

时间:2016-01-07 23:57:56

标签: ruby-on-rails ruby ruby-on-rails-4 sidekiq resque

我正在尝试在Rails中引用User类的实例进行地理编码

class User < ActiveRecord::Base
  geocoded_by :address

  after_validation GeocodeJob.perform_later(self), if: :address_changed?
end

我要传递的是用户的当前实例。然而,很明显,我最终传递的是类而不是实例,无法启动我的作业队列。

如何在模型回调中引用和传递用户实例?我知道我可以使用控制器来使用实例变量,想知道我是否可以直接排队作为模型回调。

2 个答案:

答案 0 :(得分:2)

使用您当前编写的内容,将在加载类时调用GeocodeJob.perform_later(self),并且它的返回值将用作传递给after_validation调用的参数。如你所说,那不是你想要的。

相反,您可以传递方法的符号,如下所示:

class User < ActiveRecord::Base
  geocoded_by :address

  after_validation :setup_geocode_job, if: :address_changed?

  def setup_gecode_job
    GeocodeJob.perform_later(self)
  end
end

这将通过调用模型的实例方法来执行您想要的操作,self将是模型实例。

请参阅:http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

答案 1 :(得分:1)

将ActiveRecord实例直接用作作业参数绝对是个坏主意。这里的主要问题是将Ruby对象序列化为某种可写格式(JSON,YAML等)。链接阅读更多:

要在作业工作者上下文中访问ActiveRecord实例,最好按给定的id值查找记录:

class GeocodeJob < ActiveJob::Base
  def perform(user_id)
    user = User.find user_id
    # do hard geocode work here
  end
end

从回调开始工作,如:

class User < ActiveRecord::Base
  geocoded_by :address

  after_validation if: :address_changed? do |user|
    GeocodeJob.perform_later(user.id)
  end
end

<强> PS 即可。我强烈建议使用after_commit回调而不是after_validation,因为某些时间记录保存过程可能会在其他回调中被取消,或者如果引发数据库的某些问题。还有一件事 - 如果之前没有保存用户(如User.create(...)),则其实例没有id值。