关于多态关系的ActiveRecord范围

时间:2015-12-04 17:17:44

标签: ruby-on-rails activerecord

我有三个具有多态关系的模型如下:

class DataSource < ActiveRecord::Base
  belongs_to :sourceable, polymorphic: true
end

class Foo < ActiveRecord::Base
  has_many :data_sources, as: :sourceable

  # For the sake of this example, I have place the scope here.
  # But I am going to put it in a Concern since Baz needs this scope as well.
  scope :bar_source_id, -> (id) do 
    joins(:data_sources)
    .where(data_sources: { source: 'bar', source_id: id })
    .first
  end
end


class Baz < ActiveRecord::Base
  has_many :data_sources, as: :sourceable
end

我希望能够根据相关Foo的{​​{1}}找到source_id条记录。换句话说,DataSource应该返回Foo.bar_source_id(1)条记录Foo包含data_sources的记录。但是source: 'bar', source_id: 1模型的范围不能像我预期的那样工作。

Foo会返回正确的Foo.bar_source_id(1)记录,但如果没有Foo DataSource source_id 1则会返回。

另一方面,如果没有记录,Foo.all将始终返回正确的记录或Foo.joins(:data_sources).where(data_sources: { source: 'bar', source_id: 1 }).first。这是我期望的行为。

为什么当我从模型本身调用它时,这个查询是否有效,但是当我将它作为范围包含在模型中时却不行?

编辑:

我对我的问题有部分答案。范围中的nil导致第二个查询加载所有.first条记录。如果我删除Foo,我将返回.first

为什么ActiveRecord_Relation在这两种情境中表现不同?

1 个答案:

答案 0 :(得分:0)

在挖掘之后我发现了这个:ActiveRecord - "first" method in "scope" returns more than one record

我认为这里的基本原理是scope并不意味着返回单个记录,而是返回记录集合。

我可以通过添加方法bar_source_id而不是使用范围来获得我需要的结果。

def self.bar_source_id(id)
  joins(:data_sources)
  .where(data_sources: { source: 'bar', source_id: id })
  .first
end