rails: Cannot Serialize Object with no ActiveStorage Attachment to JSON

Steps to reproduce

class Foo
  has_one_attached :image
end

Foo.new.as_json

Expected behavior

The serialized Foo.new should have an image field that is specified as nil, signifying that it has no attached image.

Actual behavior

Module::DelegationError: to_model delegated to attachment, but attachment is nil

System configuration

Rails version: 5.2.0

Ruby version: 2.5.1

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 5
  • Comments: 18 (7 by maintainers)

Most upvoted comments

I’m aware that we can get some workarounds by manipulating the as_json output, but I don’t think basic serialization should require that.

i use as_json with inclusion of methods from model

class Foo
  has_one_attached :image

  def image_filename
    self.image.filename.to_s if self.image.attached?
  end

  def image_attached?
    self.image.attached?
  end
end

Foo.new.as_json(methods: [:image_attached?,:image_filename])
# result
{"id"=>nil, "created_at"=>nil, "updated_at"=>nil, "image_attached?"=>false, "image_filename"=>nil}
# you can use the method "image_attached?"

i use as_json with inclusion of methods from model

class Foo
  has_one_attached :image

  def image_filename
    self.image.filename.to_s if self.image.attached?
  end

  def image_attached?
    self.image.attached?
  end
end

Foo.new.as_json(methods: [:image_attached?,:image_filename])
# result
{"id"=>nil, "created_at"=>nil, "updated_at"=>nil, "image_attached?"=>false, "image_filename"=>nil}
# you can use the method "image_attached?"

Man, I’m learning ruby… I did not know about the def method for defining properties. Thank you!

It’s going to be fixed eventually.

try to change with this on serializer :

      has_one :attachment do |object|
        object.attachment.attached? ? object.attachment : nil
      end

Note that this is a problem only with has_one_attached relationships not with has_many_attached ones. Here is the workaround I came up with (I use jsonapi-rb for serialisation). A bit tedious but does the job.

model:

class User < ApplicationRecord
  has_one_attached :curriculum_vitae
  has_one_attached :cover_letter
end

controller:

  # GET /users/1
  def show
    render status: 200, jsonapi: @user,
      include: %i[curriculum_vitae cover_letter] and return if @user.curriculum_vitae.attached? && @user.cover_letter.attached?
    render status: 200, jsonapi: @user,
      include: %i[curriculum_vitae] and return if @user.curriculum_vitae.attached?
    render status: 200, jsonapi: @user,
      include: %i[cover_letter] and return if @user.cover_letter.attached?
    render status: 200, jsonapi: @user
  end