我想知道是否有办法在ActiveRecord :: Relation中访问关联的belongs_to对象
例如在这种关系中:
class Customer < ActiveRecord::Base
has_many :invoices
end
class Invoice < ActiveRecord::Base
belongs_to :customer
def self.check_new
# do something
rescue => e
MyLogger.log_error_for(customer, __method__)
end
end
所以,如果我打电话
Customer.first.invoices.check_new
并发生错误。我想为此特定客户记录此错误。
我知道我可以在类方法中使用scoped
获取发票并调用scoped.first.customer
。
但这看起来有点脏。此外,如果还没有任何发票,这将不是一个解决方案。
如果有办法可以做到这一点,我不是一般的,但是对scoped进行检查会给你带来类似的东西:
SELECT * FROM SOME JOIN WHERE customer_id = 1
所以有一种对Customer对象的引用。 有人可以帮忙吗?
更新: 这只是一个例子。其实我不做记录或其他什么。当然,他们是更好的记录方式。 我想要的只是在模型类中放置更新集合的代码。像普通的Customer.first.invoices.create一样。并且可以访问此关系的父级。
答案 0 :(得分:0)
可能是这样的:
customer = Customer.first
customer.invoices.each {|invoice| invoice.check_new}
其他一些想法:
更新:
我认为Customer.first.invoices.check_new
会抛出错误,因为你试图在集合上调用类方法。
^^^
这是不正确的。请参阅oh-my-zsh。
你可以做你想要的。我不知道。这看起来真的很复杂。我相信你有一个有效的用例。但是,目前尚不清楚它是什么。我仍然可能会这样做:
customer = Customer.first
customer.invoices.check_new
不回答您的问题,如果不符合您的使用案例,请道歉。
END UPDATE。
因此,.check_new
应该是一个实例方法。有点像:
class Invoice < ActiveRecord::Base
def check_new
if errors = check_for_errors
MyLogger.log_error_for(customer, __method__, errors)
end
end
private
def check_for_errors
... error checking logic
end
end
为了让你的模型变得模糊,你可以创建一个普通的旧Ruby对象,如:
#app/managers/invoice_manager.rb
class InvoiceManager
class << self
def check_new(invoices)
invoices.each do |invoice|
@invoice = invoice
if @errors = invoice_errors
log_errors
end
end
end
private
def invoice_errors
... invoice error checking logic
end
def log_errors
MyLogger.log_error_for(invoice.customer, caller[0][/`.*'/][1..-2], @errors)
end
end
end
在这种情况下,您可以执行以下操作:
InvoiceManager.check_new(Customer.first.invoices)
这样,您的Invoice
模型又回归到处理数据库交互,并且您的业务逻辑完全分离。
此外,使用此方法,您的控制器根本不需要访问Invoice
类或其实例。或者,对Invoice
课程一无所知。这样可以改善Controller
和Model
图层之间的分隔。并使潜在的下游变更Invoice
更具破坏性。
最后,我发现测试PORO比测试控制器容易得多。
答案 1 :(得分:0)
这是一个工作示例,为简单起见,使用控制器
WhateverController
def show #(no matter which one, could be index or anything with GET request)
@user = Customer.first
@invoice = @user.invoices.first #works with the properly set up belongs_to and has_many associations which you did well
@invoice.check_new #it is called on an instance (object) of invoice class, not on the class it self as you do
end
班级发票
def check_new #if you put self before the method name then it is a class method and self is equal to Invoice (class name), if you don't then it's an instance method
self.do_something #now self means the instance itself which is the single @invoice at the moment. If you use self within the class method then this self would mean Invoice class just like in the name of the method
end
基本上,当您使用类本身时,您使用类方法,并且您不会尝试对单个实例执行任何操作。例如
@invoices = Invoice.limit(10).order(create_at: :desc)
在这里,您尝试查找该类的一些实例,因此您无法在单个实例上使用方法。但是,让我们说你想修改一些实例的属性。所以你必须转到那个实例并改变它:
@invoices.each do |invoice|
invoice.check_new
invoice.amount = 10
end
这里一次更改一个实例,因此需要实例方法。
我建议点击谷歌并查看差异。这在rails
中非常重要