ruby-on-railsrubygoogle-cloud-platformrails-activestoragerake-task

How to save images in Google storage bucket with a rake task


I have a Rails application using Active Storage, with some tasks that should run every day to attach images to a model and store them in a bucket in Google Cloud.

When I run the task "rake attach_image:attach_image_to_cloud" to attach the image, it shows:

Google::Cloud::PermissionDeniedError: forbidden: attach-images-app@attach-images.iam.gserviceaccount.com does not have storage.buckets.get access to the Google Cloud Storage bucket.

Caused by:
Google::Apis::ClientError: forbidden: attach-images-app@attach-images.iam.gserviceaccount.com does not have storage.buckets.get access to the Google Cloud Storage bucket.

I followed "Setting up Rails 5.2 Active Storage, using Google Cloud Storage and Heroku" and think I did everything right.

My Ruby version is 2.5.3 and Rails is 5.2.2.

My task is:

def download_data(download_url, datetime, json_data)
  puts "Downloading fields"
  @field = Field.new(datetime: datetime, json_data: json)
  puts "Saving field, datetime: #{datetime}"
  attach_image(download_url, datetime, @field)
  @field.save
  puts "Finished downloading #{datetime} field"
end

def attach_image(download_url, datetime, field)
  link = download_url
  field.image.attach(io: open(link), filename: "global_#{datetime}.png")
end

download_data(download_url, some_datetime, json_data)

This is my model field.rb:

class Field < ApplicationRecord
  has_one_attached :image
end

This is my config.yml:

google:
  service: GCS
  project: attach-images
  credentials: <%= ENV['GOOGLE_APPLICATION_CREDENTIALS'].as_json %>
  bucket: fields
google_dev:
  service: GCS
  project: attach-images
  credentials: <%= Rails.root.join("config/secrets/attach_images.json") %>
  bucket: fields

These are on my development.rb and production.rb environment files:

config.active_storage.service = :google_dev

config.active_storage.service = :google

I ran bundle install with:

gem "google-cloud-storage", "~> 1.8", require: false

My bucket and my service account key were both created correctly and the credential has owner rule. The credential is a hash downloaded when it was created in Google Cloud's console and set correctly in my development and Heroku production environments.


Solution

  • I've found a solution for this issue. The problem was solved by using the gsutil cors command to configure CORS on a bucket.

    gsutil cors set [JSON_FILE_NAME].json gs://[BUCKET_NAME]
    

    And the content of the json file was:

    [
      {
        "origin": ["*"],
        "responseHeader": ["Content-Type", "Content-Md5", "Origin", "X-Requested-With", "Accept", "Authorization"],
        "method": ["PUT", "GET", "HEAD", "DELETE", "OPTIONS"],
        "maxAgeSeconds": 3600
      }
    ]