chell
chell

Reputation: 7866

Rails scope on ActiveStorage blob filename gives erroneous results

I have the following model that uses ActiveStorage:

class ProofreadDocument < ApplicationRecord

  has_one_attached :file
  has_many   :paragraphs, dependent: :destroy

      scope :with_file_named, -> (filename) { 
includes(:paragraphs).joins(file_attachment: 
:blob).where("active_storage_blobs.filename = ?", filename).first}

It works very well when there is a record with a matching filename. However, when I do a search for a record with a filename that does not exists it returns all of the records.

    pry(main)> ProofreadDocument.with_file_named("M6").count
      ProofreadDocument Load (6.9ms)  SELECT  "proofread_documents".* FROM 
"proofread_documents" INNER JOIN "active_storage_attachments" ON 
"active_storage_attachments"."record_id" = "proofread_documents"."id" AND 
"active_storage_attachments"."record_type" = $1 AND 
"active_storage_attachments"."name" = $2 INNER JOIN "active_storage_blobs" 
ON "active_storage_blobs"."id" = "active_storage_attachments"."blob_id" 
WHERE (active_storage_blobs.filename = 'M6') ORDER BY 
"proofread_documents"."id" ASC LIMIT $3  [["record_type", 
"ProofreadDocument"], ["name", "file"], ["LIMIT", 1]]
(0.5ms)  SELECT COUNT(*) FROM "proofread_documents"

=> 576

How can I fix this so that it returns 0 records if there is no record for the given filename?

Upvotes: 2

Views: 827

Answers (1)

George Claghorn
George Claghorn

Reputation: 26545

Your scope returns a record object or nil. Per the docs for the scope macro, a scope should return an ActiveRecord::Relation; when it returns nil, as yours does when no blob has the given filename, it’s equivalent to all (emphasis added):

Adds a class method for retrieving and querying objects. The method is intended to return an ActiveRecord::Relation object, which is composable with other scopes. If it returns nil or false, an all scope is returned instead.

Modify your scope to return a relation by removing the call to first:

scope :with_file_named, -> (filename) do
  includes(:paragraphs).joins(file_attachment: :blob).where("active_storage_blobs.filename = ?", filename)
end

Upvotes: 1

Related Questions