ActiveStorage Caching Setting - Rails + Google Cloud - ruby-on-rails

I am trying to set caching for the images stored in Active Storage with google cloud. I have the below configuration file
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
local:
service: Disk
root: <%= Rails.root.join("storage") %>
production:
service: GCS
credentials: <%= Rails.root.join("cert/gcs-production.json") %>
project: 'my-app-121212'
bucket: 'my-prod-bucket'
staging:
service: GCS
credentials: <%= Rails.root.join("cert/gcs-staging.json") %>
project: 'my-app-121212'
bucket: 'my-stage-bucket'
Can any one please suggests as to where i can specify the caching settings, I want the images to be cached.

You can set public: true on the service. This will instruct rails to use public url from GCS which by default will have caching header added. Please refer to official guide
Make sure your GCS bucket has public permission added (allUsers with viewer role)

If you are using App Engine Flexible and not Compute Engine, caching files that are publicly readable object is allowed by default when using Google Cloud Storage, indicated by the service: GCS flag you’re using, meaning that you do not have to specify any special configuration.
Keep in mind that the objects you can cache need to be static files, so images, stylesheets, JavaScript, etc.
If you wanna read more on serving static files from App Engine with Rails, you can read this article from Google Cloud.

Related

Accessing rails active storage no routes matches error

I am trying to host rails sever as a backend.
Nginx will redirect to localhost:3000 when the route start with /api.
In my case, 'etl.robust.best/api' will go to host's localhost:3000 where rails have been hosted.
The problem is I cannot access images from active storage.
Instead I get no routes matches error.
config/storage.yml
I can access images from active storage when testing on my computer.
How do I fix this.
This is my development.rb file.
The config of nginx
You should check what your Rails.root is. You could do that in rails console, launched inside your app. Then check config/storage.yml and see that the path defined there for local storage matches the actual path. For example this would point to /storage inside your app:
local:
service: Disk
root: <%= Rails.root.join("storage") %>
More info on Active Storage here.

Multiple Azure Storage Integration with Rails 6 application

I have used Azure Active Storage for all the user files that are uploaded on my application developed using Rails v6. Works perfectly fine.
Now I wanted to make a copy of the files that are getting uploaded on my application to Another Azure storage account. How can I go about this approach. Any help would be much appreciated.
There are a couple of options available. One is using mirrors in storage.yml file. There you can configure multiple storage accounts even with different cloud service providers like Amazon and Azure. This is done at configuration level
s3_mirror:
service: S3
access_key_id: ""
secret_access_key: ""
region: ""
bucket: ""
development:
service: AzureStorage
root: <%= Rails.root.join("storage") %>
container: development
storage_account_name: my_account_name
storage_access_key: my_access_key
mirror:
service: Mirror
primary: development
mirrors:
- s3_mirror
Another way which was more usable for me was this piece of code suggested by a famous AI app
# First, install the gem
gem 'azure-storage-ruby'
# Then, in your code, you can use the Azure::Storage::Client class to connect
to a storage account
# Replace ACCOUNT_NAME and ACCOUNT_KEY with your storage account name and key
client1 = Azure::Storage::Client.create(storage_account_name: 'ACCOUNT_NAME',
storage_access_key: 'ACCOUNT_KEY')
client2 = Azure::Storage::Client.create(storage_account_name: 'ACCOUNT_NAME',
storage_access_key: 'ACCOUNT_KEY')
# You can then use the client objects to perform operations on the storage
accounts
blob_client1 = client1.blob_client
blob_client2 = client2.blob_client
# For example, you can list the blobs in a container like this:
blob_client1.list_blobs('my-container').each do |blob|
puts blob.name
end
blob_client2.list_blobs('my-container').each do |blob|
puts blob.name
end

Production Server Uploading to Staging S3

I have an app running on a ubuntu server. I have a production mode and a staging mode.
Problem is that actions being done on the production site relative to uploading and retrieving images from an S3 bucket are being done to the same bucket as my staging. When I have my configurations set up differently.
production.rb
config.s3_bucket = 'bucket-production'
config.s3_path = 'https://bucket-production.s3.us-east-2.amazonaws.com/'
staging.rb && development.rb
config.s3_bucket = 'bucket-staging'
config.s3_path = 'https://bucket-staging.s3.us-east-2.amazonaws.com/'
storage.yml
amazon:
service: S3
access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
region: us-east-2
bucket: bucket-staging
endpoint: http://bucket-staging.us-east-2.amazonaws.com
I'm thinking it could be something with storage.yml but I deleted this entire file and restarted the localhost server and it didn't change anything. Is storage.yml production only?
Also, my logs are logging to staging from production.
I would like to ask is prod server/staging server(Ubuntu) running in AWS.if yes, you must have IAM ROLE attached to the server which must be fine-grained to which env application should access which bucket of S3. Also storing access_key_id and secret access key id should not be used as best practice. IAM role can take care of that. Also, I would like to add if the server is in the private subnet you need to explore either NAT gateway or use VPC S3 Endpoint to access the bucket.
Also try printing logs of S3 connection in prod mode how it is acquiring cred to access bucket. You might be granting access using some ENV variables or IAM role. Best way to see is use
printenv
before and after of S3 connection to see the variables and which bucket access is provided.
Thanks
Ashish

Rails Active Storage push to DigitalOcean Spaces

Hi I'm trying to get active storage to push to a DigitalOcean space. However, I'm finding that the push url is being changed to amazonaws.com even though I've defined the endpoint to digital ocean.
here is what I have in storage.yml
amazon:
service: S3
access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
region: sfo2
bucket: redacted_bucket_name
endpoint: https://sfo2.digitaloceanspaces.com
When I try to upload a file, I get the following error:
Aws::Errors::NoSuchEndpointError (Encountered a `SocketError` while attempting to connect to:
https://redacted_bucket_name.s3.sfo2.amazonaws.com/a8278561714955c23ee99
in my gemfile I have: gem 'aws-sdk-s3
I've followed the directions found here, and I'm still getting the error. Is it possible that there's a new way to do this?
I just set something like this up myself a few days ago. When you check the URL https://redacted_bucket_name.s3.sfo2.amazonaws.com/a8278561714955c23ee99 it's different from the actual endpoint you set up https://redacted_bucket_name.sfo2.amazonaws.com/a8278561714955c23ee99
the error is being caused by an invalid endpoint your hitting, the s3 right before the .sfo2 is offsetting the endpoint. Did you happen to add s3 to your spaces config? check your spaces dashboard and try to get the endpoint setup properly.
I had this same challenge when working on a Rails 6 application in Ubuntu 20.04.
Here's how I fixed mine:
Firstly, create a Spaces access keys in your digital ocean console. This link should help - DigitalOcean Spaces API
Secondly, add a new configuration for DigitalOcean Spaces in your config/storage.yml file. Just after the local storage definition:
# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
digital_ocean:
service: S3
access_key_id: <%= SPACES_ACCESS_KEY_ID %>
secret_access_key: <%= SPACES_SECRET_ACCESS_KEY %>
region: <%= SPACES_REGION %>
bucket: <%= SPACES_BUCKET_NAME %>
endpoint: <%= SPACES_ENDPOINT %>
Note: You can give your entry any name, say digital_ocean_spaces or something else. For me I named it digital_ocean.
Thirdly, modify the config.active_storage.service configuration in the config/environments/production.rb file from:
config.active_storage.service = :local
to
config.active_storage.service = :digital_ocean
Finally, specify these environment variables file in your config/application.yml file (if you're using the Figaro gem) or your .env file. (if you're using the dotenv gem). In my case I was using the dotenv gem, so my .env file looked looked like this:
SPACES_ACCESS_KEY_ID=E4TFWVPDBLRTLUNZEIFMR
SPACES_SECRET_ACCESS_KEY=BBefjTJTFHYVNThun7GUPCeT2rNDJ4UxGLiSTM70Ac3NR
SPACES_REGION=nyc3
SPACES_BUCKET_NAME=my-spaces
SPACES_ENDPOINT=https://nyc3.digitaloceanspaces.com
That's all.
I hope this helps

keystonejs cloudinary invalid signature error

I have implemented a Cloudinary type in one of my models, but get this error back when I try and save it to Cloudinary:
Image upload failed - Invalid Signature
ea4401c2ebf292208d28f9dc88c5ff1c4e73761d.
String to sign - 'tags=trial-images_image,trial-
images_image_55ba9896c6d05b8704802f0a,dev&timestamp=1438292137'.
I'm not sure what to do about it, anyone experience this?
You should make sure to calculate the signature correctly. Specifically, you should sign both the tags and the timestamp (including your api_secret of course).
I had the exact same issue.
Please double check that you have the configuration parameters(cloud name, api key, api secret) correctly set up. They can be found by going to the management console on your cloudinary account. (Dashboard > Account Details).
As per their documentation:
(http://cloudinary.com/documentation/rails_additional_topics#configuration_options)
Configuration parameters can be globally set using a cloudinary.yml configuration file, located under the config directory of your Rails project. etc...
Here's an example of a cloudinary.yml file:
production:
cloud_name: "sample"
api_key: "874837483274837"
api_secret: "a676b67565c6767a6767d6767f676fe1"
etc...
... Another configuration option is to use a Rails initializer file. You can place a file named cloudinary.rb in the /config/initializers folder of your Rails project. Here's a sample initializer code:
Cloudinary.config do |config|
config.cloud_name = 'sample'
config.api_key = '874837483274837'
config.api_secret = 'a676b67565c6767a6767d6767f676fe1'
config.cdn_subdomain = true
end
One last configuration option allows you to dynamically configure the Cloudinary library by defining the CLOUDINARY_URL environment variable. The configuration URL is available in the Management Console's dashboard of your account. When using Cloudinary through a PaaS add-on (e.g., Heroku), this environment variable is automatically defined in your deployment environment. Here's a sample value:
CLOUDINARY_URL=cloudinary://874837483274837:a676b67565c6767a6767d6767f676fe1#sample
How I actually solved the issue
I solved the issue by adopting (and slightly modifying) the first option, which is to create cloudinary.yml file in config directory and write the following code:
(config/cloudinary.yml)
development:
cloud_name: <%= ENV["CLOUD_NAME"] %>
api_key: <%= ENV["API_KEY"] %>
api_secret: <%= ENV["API_SECRET"] %>
test:
cloud_name: <%= ENV["CLOUD_NAME"] %>
api_key: <%= ENV["API_KEY"] %>
api_secret: <%= ENV["API_SECRET"] %>
production:
cloud_name: <%= ENV["CLOUD_NAME"] %>
api_key: <%= ENV["API_KEY"] %>
api_secret: <%= ENV["API_SECRET"] %>
Please note that the configuration parameters (cloud name, api key, api secret) are set as environmental variables(CLOUD_NAME, API_KEY, API_SECRET) to prevent them from being exposed when the code is shared publicly. (You don't want to hard code the sensitive information)
You can set environmental variables in bash by editing .bash_profile file, which is located (and hidden) in the home directory:
(.bash_profile)
.....
export CLOUD_NAME="your cloud name"
export API_KEY="your api key"
export API_SECRET="your api secret"
.....
You can check that these environmental variables are correctly set by typing echo $CLOUD_NAME, for example, in your terminal.(You may need to quit and restart the terminal). If it's successful, the output will look something like:
echo $CLOUD_NAME
> your cloud name
Finally, if you are planning to deploy your app to heroku, you may also want to add cloudinary as an addon, which is free for a starter option, by typing the following command in the terminal:
heroku addons:create cloudinary:starter
Putting this all together might solve your issue.
Last but not least, I found the following blog post quite useful:
http://www.uberobert.com/rails_cloudinary_carrierwave/
It explains how you can use cloudinary and carrierwave to upload and manipulate the images on your application.
Hope it helps!

Resources