我正在尝试在Rails中引用User类的实例进行地理编码
class User < ActiveRecord::Base
geocoded_by :address
after_validation GeocodeJob.perform_later(self), if: :address_changed?
end
我要传递的是用户的当前实例。然而,很明显,我最终传递的是类而不是实例,无法启动我的作业队列。
如何在模型回调中引用和传递用户实例?我知道我可以使用控制器来使用实例变量,想知道我是否可以直接排队作为模型回调。
答案 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值。