将布尔实例方法作为范围调用'

时间:2017-02-16 16:19:56

标签: ruby-on-rails rails-activerecord

我有一个模特

Email

和实例方法

def sent_to_user?(user)
  self.who_to == user
end

其中who_to是另一个执行某些复杂内容的实例方法。

在后台还有更多的东西在那里,所以我不能轻易将它变成一个活跃的记录查询。

我想做类似的事情:

scope :sent_to_user, -> (user) { sent_to_user?(user)} 

@user.emails.sent_to_user

并仅返回那些为" sent_to_user返回true的电子邮件?'

尝试了

scope :sent_to_user, -> (user) { if sent_to_user?(user)} 

....等。

不太确定如何构建范围/类方法

4 个答案:

答案 0 :(得分:7)

你不能(至少不应该)以这种方式使用范围。范围用于返回ActiveRecord关系,其他范围可以链接到该关系。如果要使用作用域,则应生成必要的SQL以在数据库中执行过滤。

如果要在Ruby中过滤结果并返回数组,则应使用类级方法,范围:

class Email < ActiveRecord::Base
  def self.sent_to_user(user)
    select { |record| record.sent_to_user?(user) }
  end
end

答案 1 :(得分:0)

你应该在ActiveRecord逻辑中编写who_to,比如

  

范围:sent_to_user, - &gt; (用户){joins(:recipient)where(recipient_id:user.id)}

答案 2 :(得分:0)

假设用户has_many :emails可以执行以下操作:

class User < ActiveRecord::Base
  has_many :emails

  # ...

  def emails_sent_to_user
    emails.select { |e| e.sent_to_user?(self) }
  end
end

答案 3 :(得分:0)

有趣的是,我制定了一个方法来进行检查,这有点像黑客,但在这种情况下工作,可能对某人有用。 接受的解决方案的问题,虽然它是基于我所描述的限制来实现它的唯一方法,但性能可能会非常缓慢。

我现在正在使用:

scope :sent_to_user, -> (user) {"json_email -> 'to' ILIKE ?", "%#{user.email)}%"}

其中“json_email”是解析为json的电子邮件对象(这是我们将它们存储在数据库中的方式)。这减少了使用Mail gem的需要,并大大提高了性能。