0

I have an Animal model:

class Animal < ApplicationRecord
  has_one_attached :avatar
  ...
end

Here's the animals_controller.rb:

def create
  @animal = Animal.new(animal_params)
  @animal.save
  @animal.avatar.attach(io: File.open("/Users/jasontemp/Downloads/dogpic.jpg"), filename: 'dogpic.jpg', content_type: 'image/jpeg')
  ...
end

This is my controller spec:

it "creates a new Animal" do
  au = AdminUser.create!(:email => 'admin@example.com', :password => 'password', :password_confirmation => 'password')

  expect {
    post :create, params: {animal: valid_attributes.merge("admin_user_id"=>au.id)}, session: valid_session
  }.to change(Animal, :count).by(1)
  expect(Animal.last.avatar.attached?).to be(true)
  expect(Animal.last.avatar.blob.filename.to_s).to eql("dogpic.jpg")
end

Here's my storage.yml:

test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

My development.rb:

...
  # Store uploaded files on the local file system (see config/storage.yml for options).
  config.active_storage.service = :local
...

When I run the spec, it's green. When I actually run the code in development mode using puma through my browser, it makes the animal object but doesn't attach the file. I'm not sure why the behavior is different. I must be overlooking something but I can't see it.

EDIT: Decided to try it in the rails console. I loaded the object:

irb(main):012:0> @animal = Animal.last
   (1.9ms)  SELECT sqlite_version(*)
  Animal Load (0.9ms)  SELECT "animals".* FROM "animals" ORDER BY "animals"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> #<Animal id: 6, name: "Demo Sjorn", type: "dog", tracking_start: nil, tracking_end: nil, rescue_org_id: nil, pickup_shelter_name: "", pickup_addr1: "", pickup_city: "", pickup_state: "", pickup_zip: "", dropoff_name: "", dropoff_addr1: "", dropoff_city: "", dropoff_state: "", dropoff_zip: "", created_at: "2020-07-25 00:59:53", updated_at: "2020-07-25 00:59:53", shelter_identifier: "", hours_left: 32, hero_pic: "", hero_vid: "", admin_user_id: 1>

Then I added the attachment using the same code from the controller:

irb(main):013:0>         @animal.avatar.attach(io: File.open("/Users/jasontemp/Downloads/dogpic.jpg"), filename: 'dogpic.jpg')
   (0.1ms)  begin transaction
  AdminUser Load (0.6ms)  SELECT "admin_users".* FROM "admin_users" WHERE "admin_users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  ActiveStorage::Blob Load (0.6ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" INNER JOIN "active_storage_attachments" ON "active_storage_blobs"."id" = "active_storage_attachments"."blob_id" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ?  [["record_id", 6], ["record_type", "Animal"], ["name", "avatar"], ["LIMIT", 1]]
  ActiveStorage::Attachment Load (0.1ms)  SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ?  [["record_id", 6], ["record_type", "Animal"], ["name", "avatar"], ["LIMIT", 1]]
  ActiveStorage::Blob Create (1.5ms)  INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "metadata", "byte_size", "checksum", "created_at") VALUES (?, ?, ?, ?, ?, ?, ?)  [["key", "bqi8aqdvd3m67c8m6od5azwd8joh"], ["filename", "dogpic.jpg"], ["content_type", "image/jpeg"], ["metadata", "{\"identified\":true}"], ["byte_size", 40164], ["checksum", "d1QbnR5/D4cBx7gWw6FIFg=="], ["created_at", "2020-07-26 19:21:37.773142"]]
  ActiveStorage::Attachment Create (0.6ms)  INSERT INTO "active_storage_attachments" ("name", "record_type", "record_id", "blob_id", "created_at") VALUES (?, ?, ?, ?, ?)  [["name", "avatar"], ["record_type", "Animal"], ["record_id", 6], ["blob_id", 15], ["created_at", "2020-07-26 19:21:37.781476"]]
  Animal Update (0.2ms)  UPDATE "animals" SET "updated_at" = ? WHERE "animals"."id" = ?  [["updated_at", "2020-07-26 19:21:37.784817"], ["id", 6]]
   (0.7ms)  commit transaction
  Disk Storage (11.5ms) Uploaded file to key: bqi8aqdvd3m67c8m6od5azwd8joh (checksum: d1QbnR5/D4cBx7gWw6FIFg==)
Enqueued ActiveStorage::AnalyzeJob (Job ID: 6914b937-f9a5-4766-af4f-cda7b14e841c) to Async(active_storage_analysis) with arguments: #<GlobalID:0x00007fde7aa2e260 @uri=#<URI::GID gid://rescue-bot/ActiveStorage::Blob/15>>
=> true
irb(main):014:0>    (0.1ms)  SELECT sqlite_version(*)
   (0.1ms)  SELECT sqlite_version(*)
  ActiveStorage::Blob Load (0.1ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
Performing ActiveStorage::AnalyzeJob (Job ID: 6914b937-f9a5-4766-af4f-cda7b14e841c) from Async(active_storage_analysis) enqueued at 2020-07-26T19:21:37Z with arguments: #<GlobalID:0x00007fde773e1e50 @uri=#<URI::GID gid://rescue-bot/ActiveStorage::Blob/15>>
  Disk Storage (0.3ms) Downloaded file from key: bqi8aqdvd3m67c8m6od5azwd8joh
Skipping image analysis because ImageMagick doesn't support the file
   (0.1ms)  begin transaction
  ActiveStorage::Blob Update (0.4ms)  UPDATE "active_storage_blobs" SET "metadata" = ? WHERE "active_storage_blobs"."id" = ?  [["metadata", "{\"identified\":true,\"analyzed\":true}"], ["id", 15]]
   (0.8ms)  commit transaction
Performed ActiveStorage::AnalyzeJob (Job ID: 6914b937-f9a5-4766-af4f-cda7b14e841c) from Async(active_storage_analysis) in 11.87ms

...and it worked!

irb(main):014:0> @animal.avatar.attached?
=> true

Still doesn't work via my my web browser with puma running locally! I'm stumped at the moment.

1 Answers1

0

Make sure to test whether the save succeeded:

def create
  @animal = Animal.new(animal_params)
  if @animal.save
    @animal.avatar.attach(io: File.open("/Users/jasontemp/Downloads /dogpic.jpg"), filename: 'dogpic.jpg', content_type: 'image/jpeg')
    ...
  else
    raise @animal.errors.inspect
  end
end

In the test you merge admin_user_id in the params but in the controller this does not seem to be the case.

Sjors Branderhorst
  • 2,138
  • 17
  • 25
  • You're right, it is different. I explicitly merge it in the spec because I'm simulating a login session. In the puma server, I'm actually logged in so the admin_user_id is available to the create method from the params: `Animal Create (5.3ms) INSERT INTO "animals" ("name", "type", ... "admin_user_id") VALUES (?, ?, ... ?) [["name", "Demo Sjorn"], ["type", "dog"], ... ["admin_user_id", 1]]` – HashtagONUD Jul 25 '20 at 01:05
  • I thought of something: How does the source of the html form look like? Does it have an ```enctype=``` attribute? I got bitten (in the past) by omitting the enctype attribute. Maybe check this out: https://stackoverflow.com/a/4526286/790737 Also keep uour netwerk tab from developer tools open while posting the form, and check whether data is actually sent to the controller. – Sjors Branderhorst Jul 28 '20 at 14:12