在我的rails 4应用程序中,我有一个名为Property
的模型,它具有以下类方法:
def under_contract?
self.contracts.last && self.contracts.last.accepted? ? true : false
end
这样做是检查财产是否有与之相关的合同,然后检查该合同是否已被接受。
我想为租用的属性创建一个范围(如果你在它们上使用类方法under_contract?它将返回true)。以下是我尝试做到的事情:
scope :rented, -> {where(under_contract?: true)}
问题是under_contract不是数据库中的一个列,它只是一个类方法,所以我得到一个错误说"没有这样的列"。
我接近这个完全错误还是我只是错过了一些小事?
答案 0 :(得分:1)
类方法
这是一个instance method - 如果它是类,它将是def self.under_contract?
-
我接近这个完全错误的
是
首先,scope与类方法相同;它初始化类的新实例以返回您的数据。实例方法对已经调用的类执行操作:
#app/models/property.rb
class Property < ActiveRecord::Base
def under_contract? #-> instance method
...
end
def self.under_contract #-> class method
where under_contract: true
end
end
以上可以使用如下:
@property = Property.find x
@property.under_contract? #-> instance method
@properties = Property.under_contract #-> class method
@properties.each do |property|
property.under_contract?
end
差异很微妙但很重要。它是你问题的根源。
-
其次,您不能混合使用类和实例方法。它们的范围完全不同;你不能在类方法上调用实例方法。
您不能将scope
与已调用的对象一起使用。你必须要么调用对象&amp;使用实例方法,或使用范围最初调用所需的对象。
这样做:
#app/models/property.rb
class Property < ActiveRecord::Base
has_many :contracts
scope :rented, -> { joins(:contracts).where(accepted: true) }
def under_contract?
self.contracts.any? && self.contracts.exists(accepted: true) #-> returns true / false
end
end
这为您提供了范围,用于从db中提取rented
属性:
@properties = Property.rented
...以及确定是否已租用特定属性的实例方法:
@property = Property.find x
@property.under_contract?
答案 1 :(得分:1)
感谢所有帮助。我用下面的代码解决了我的具体问题。
def under_contract
self.contracts.any? && self.contracts.last.accepted?
end
scope :rented, -> {select { |p| p.under_contract == true}}
答案 2 :(得分:0)
我不知道您对合同的接受?方法看起来像是假设您在合同中有接受:布尔列,那么您可以使用像这样的包含来构建您的范围...
scope :rented, -> { includes(:contracts).where.not(contracts: { property_id: nil }).where(contracts: {accepted: true}) }