How can I get my CarrierWave model to return the full URL to me in a test? - carrierwave

Trying to test a carrierwave model is really difficult. I configured my test environment like this:
if Rails.env.test?
CarrierWave.configure do |config|
config.storage = :file
config.enable_processing = false
config.fog_directory = BUCKET # required
config.fog_public = false # optional, defaults to true
config.fog_credentials = {
:provider => 'Local', # required
:local_root => LOCAL_ROOT, # required
:endpoint => "http://localhost:3000" # required
}
end
else
CarrierWave.configure do |config|
config.storage = :fog
config.max_file_size = 1.gigabytes # defaults to 5.megabytes
config.fog_directory = BUCKET # required
config.fog_public = false # optional, defaults to true
config.fog_credentials = {
:provider => PROVIDER, # required
:aws_access_key_id => access_key_id, # required
:aws_secret_access_key => secret_access_key # required
}
end
end
and it works great for testing uploads. Makes it difficult for testing downloads though.
Here is a simple test:
require "test_helper"
class UploadTests < ActiveSupport::TestCase
let(:user) { User.me }
let(:repo) { Repository.first }
let(:sub) { user.subscriptions.where(repository_id: repo).first}
it "uploads a CSV file and lets me read it" do
filename = Rails.root.join("test/testfiles/product_upload_test.csv").to_s
upload = sub.uploads.new
File.open(filename) do |f|
upload.text_file_name = f
end
upload.save!
end
end
All very simple. But what I want to do is read the file from the model. In other words, call some CarrierWave API that lets me grab the file and read it.
In production, I store everything on S3. In test, everything is in a local file. And I set local_root to be my app's public directory.
CarrierWave only reports the url as the path, but doesn't include the local_root. I don't feel that it is my job to manually construct the path to a file that I want to read from CarrierWave. How/Where the file is stored should be hidden from my test... I should have to construct that path.
But I don't know what else to do. All I want to do is read that file.

I changed my test configuration to the following:
CarrierWave.configure do |config|
config.storage = :file
config.enable_processing = false
config.fog_directory = BUCKET # required
config.fog_public = true # optional, defaults to true
config.fog_credentials = {
:provider => 'Local', # required
:local_root => LOCAL_ROOT, # required
:endpoint => LOCAL_ROOT # required
}
end
and now the full url is returned.

Related

Fog/Carrierwave config for Rails app on AWS Elastic Beanstalk

I'm trying to set up Carrierwave and Fog to handle image and file uploads on a rails app that I have hosted on AWS' Elastic Beanstalk.
I'm a little confused on how to properly set up the Fog config.
I tried using my AWS Access and Secret keys (commented out in the example below). That through an error on my EB CLI (ERROR: NotAuthorizedError - Operation Denied. The security token included in the request is invalid.)
I'm tyring to use IAM instead of having my Access/Secret codes in my ruby code. Can anyone tell me how to set this up properly?
Here's my config file:
CarrierWave.configure do |config|
# Use local storage if in development or test
if Rails.env.development? || Rails.env.test?
CarrierWave.configure do |config|
config.storage = :file
end
end
# Use AWS storage if in production
if Rails.env.production?
CarrierWave.configure do |config|
config.storage = :fog
end
end
config.fog_credentials = {
:provider => 'AWS', # required
# :aws_access_key_id => 'My Access', # required
# :aws_secret_access_key => 'My Secret', # required
:use_iam_profile => true,
:region => 'eu-west-2' # optional, defaults to 'us-east-1'
}
config.fog_directory = 'elasticbeanstalk-us-west-2-XXXXXXXXXX' # required
#config.fog_host = 'https://assets.example.com' # optional, defaults to nil
config.fog_public = false # optional, defaults to true
config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
end
This is a setup that works for me:
config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.fog_provider = 'fog/aws' # required
config.fog_credentials = {
provider: 'AWS', # required
aws_access_key_id: ENV['aws_access_key_id'], # required
aws_secret_access_key: ENV['aws_secret_access_key'], # required
#region: 'Singapore', # optional, defaults to 'us-east-1'
#host: 's3.example.com', # optional, defaults to nil
#endpoint: 'olucube-images.s3-website-ap-southeast-1.amazonaws.com', # optional, defaults to nil
}
config.fog_directory = ENV['fog_directory'] # required
#config.fog_public = false # optional, defaults to true
# config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" }, # optional, defaults to {}
end
and I used figaro gem to hold my credentials as follow:
config/application.yml
aws_access_key_id: 'XXXXXXXXXXXXXXXXXXXX'
aws_secret_access_key: 'XXXXXXXXXXXXXXXXXX'
fog_directory: 'myAppName'
This was a bit a of a wild ride. I had a hard time figuring out that Figaro gem. It's probably simple but I didn't really understand it. So for a test, I put my keys directly in the code. It still didn't work.
I pushed my code to github (publicly) and didn't think too much of it. I was going to change the keys just in case. Before I was able to do that someone found my code on github and gained access to my AWS account. They started a bunch of EC2 instances and racked up $3000 worth of usage in a few hours!
My AWS account got suspended and I'm still dealing with having the charges reversed.
Anyway. I found out that you can actually set environment variables on the Elastic Beanstalk web interface. Its under Configuration → Software Configuration. So I did that instead of using Fiagro (much safer IMO). Now it works great. I simplified my Carrierwave config file to only use AWS calling the environment variables from EB. Here's the file:
# config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.fog_provider = 'fog/aws'
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: ENV['S3_KEY'],
aws_secret_access_key: ENV['S3_SECRET'],
region: ENV['S3_REGION']
}
config.fog_directory = ENV['S3_BUCKET']
config.fog_public = false
config.storage = :fog
end
I changed my uploader files to use fog too. Here's an example:
# app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_white_list
%w(jpg jpeg gif png)
end
end
Everything works great now. I hope this helps someone else.

Can carrierwave direct upload to local storage?

Sometimes I am away from internet and still need to work on upload pages. Carrierwave Direct seems to force storage :fog; with no way of overriding in dev.
Is it possible to tell Carrierwave Direct to use local storage (:file) and simply fallback to Carrierwave's development config settings?
Setting storage :file in carrierwave initializer under development config settings doesnt work...carrierwave_direct errors with "is not a recognized provider" from "<%= direct_upload_form_for #uploader do |f| %>".
I have attempted to work around carrierwave direct, but between forcing :fog, expecting a redirect url and expecting the direct_upload_form_for form method...carrierwave_direct is pretty much in charge.
Using storage :file in development would be a welcome feature for the carrierwave_direct gem. Does anyone know how to cleanly do this?
I think it can be done as follows:
CarrierWave.configure do |config|
if Rails.env.development? || Rails.env.test?
config.storage = :file
config.asset_host = ENV["dev_url"]
else
config.fog_provider = 'fog/aws' # required
config.fog_credentials = {
provider: 'AWS', # required
aws_access_key_id: ENV["aws_id"], # required
aws_secret_access_key: ENV["aws_key"], # required
region: ENV["aws_zone"] # optional, defaults to 'us-east-1'
}
config.fog_directory = ENV["aws_bucket"] # required
config.max_file_size = 600.megabytes # defaults to 5.megabytes
config.use_action_status = true
config.fog_public = false # optional, defaults to true
config.fog_attributes = { cache_control: "public, max-age=#{365.day.to_i}" } # optional, defaults to {}
end
end
And in your Uploader add in:
class SomeUploader < CarrierWave::Uploader::Base
if Rails.env.development? || Rails.env.test?
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
end

CarrierWave With Cloudfront Generating wrong URL

Hello I am using Cloudfront with CarrierWave and S3. For some reason in my app I am getting very strange URLs for my cloudfront path when using image_tag and I don't know where I am going wrong. Here is my carrierwave config file
CarrierWave.configure do |config|
config.fog_provider = 'fog/aws' # required
config.fog_credentials = {
provider: 'AWS', # required
aws_access_key_id: 'accesskey', # required
aws_secret_access_key: 'secretaccess key', # required
region: 'us-east-1', # optional, defaults to 'us-east-1'
}
config.fog_directory = 'bwautosales' # required
# config.asset_host = 'randomletters.cloudfront.net'
config.asset_host = 'randomletters.cloudfront.net'
config.fog_public = true
config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" } # optional, defaults to {}
end
and my production.rb file I have
config.action_controller.asset_host = 'randomletters.cloudfront.net'
but in my view when I do something like
<%= link_to image_tag(car.images[0], class: "img-responsive right-block", id: index), car %>
I get this -
src = https://randomletters.cloudfront.net/images/randomletters.cloudfront.net/uploads/car/images/28/car.png"
I'm sure this is an easy fix but don't know where I'm going wrong. Any help would be appreciated!
Image Uploader `
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_whitelist
%w(jpg jpeg gif png)
end
end
`
In your Carrierwave initializer change the line,
config.asset_host = 'randomletters.cloudfront.net' to config.asset_host = 'http://randomletters.cloudfront.net' to get the required cloudfront URL you needed.
You can also remove the line, config.action_controller.asset_host = 'randomletters.cloudfront.net' from Production.rb as the carrierwave itself fetches from the cloud-front url.
CarrierWave.configure do |config|
config.fog_provider = 'fog/aws'
config.fog_credentials = {
--------------
--------------
}
config.fog_directory = 'bwautosales'
config.asset_host = 'http://randomletters.cloudfront.net' # please check the change in this line.
config.fog_public = true
config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" } # optional, defaults to {}
end
Just for the sake of adding credibility to Sravan's answer, I had the same problem and when I followed his instructions it started working properly. If you leave out the http:// from
config.asset_host = <>
It gets confused and tries to use a different path with your site's domain name. I had the same issue, but adding http:// to the beginning of the url fixed it.

Carrierwave + Fog+ caching

Scenario: We have a few users on the site who have previously uploaded a logo for their site. Recently, we changed the dimensions of this logo and would like all accounts to reflect this change (we've also removed retina_rails from our app). So we plan on making a migration to remove retina rails while at the same time looping through each account and re uploading the logos to normalize across all logos.
Currently, this is what the migration looks like:
class RemoveRetinaDimensionsFromAccounts < ActiveRecord::Migration
def change
remove_column :accounts, :retina_dimensions, :text
end
ActsAsTenant.configure.require_tenant = false
Account.all.each do |account|
if account.logo?
account.logo.cache_stored_file!
account.logo.retrieve_from_cache!(account.logo.cache_name)
account.logo.recreate_versions!(:small, :small)
account.save!
end
end
ActsAsTenant.configure.require_tenant = true
end
This is what our carrierwave.rb file looks like:
CarrierWave.configure do |config|
if Rails.env.test?
config.storage = :file
config.enable_processing = false
elsif Rails.env.development?
config.storage = :file
config.cache_dir = "#{Rails.root}/tmp/uploads"
elsif Rails.env.staging?
config.storage = :fog
config.cache_dir = "#{Rails.root}/tmp/uploads"
config.fog_credentials = {
:provider => 'AWS', # required
:aws_access_key_id => Rails.application.secrets.aws_access_key_id, # required
:aws_secret_access_key => Rails.application.secrets.aws_secret_access_key, # required
:region => 'us-west-2' # optional, defaults to 'us-east-1'
}
config.fog_directory = 'blvd-staging' # required
config.fog_public = false
end
end
I've tried to follow the advice mentioned in this link https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Recreate-and-reprocess-your-files-stored-on-fog but it is not working. I've tested to make sure the cache is saving files, and it is. However, when I try and retrieve_from_cache! I'm unable to do so (as the cached file does not have a name).
This is what my cached files look like:
tmp
uploads
##########-#####-####
Thank you.
Turns out I did not run the desired code block within the change block inside the migration so the code was never being executed.

Rails Engine not uploading to s3 with Carrierwave

I am creating a rails plugin with rails new plugin my_plugin --mountable
This was quite some work to figure out but it is supposed to upload files to S3 with carrierwave, but it says ok but nothing is uploaded
Carrierwave is used to generate an uploader with rails g uploader photo
the file looks like this
# my_engine/app/uploaders/my_engine/photo_uploader.rb
# encoding: utf-8
module my_engine
class PhotoUploader < CarrierWave::Uploader::Base
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
end
the model had an mount :photo, PhotoUploader
module PdfGeneratorEngine
class Assemble < ActiveRecord::Base
attr_accessible :color, :photo, :qr_code_url, :text
mount_uploader :photo, PhotoUploader
end
end
my CarrierWave config file is this
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => 'MY_ACCES_KEY',
:aws_secret_access_key => 'MY_SECRET_KEY',
:provider => 'AWS',
:region => 'eu-west-1'
}
config.fog_directory = 'my.bucket.com'
config.fog_host = 'https://s3-eu-west-1.amazonaws.com/my.bucket.com'
config.storage = :fog
config.s3_use_ssl = true
config.fog_public = true
end
So first of all it starts screaming at fog_host, it is okay if it is asset_host
Next it's problem lies within s3_use_ssl, while it is an merged issue on CarrierWave's github. But the host is already defined as https:// so I don't see why that line is necessary.
After that it says 'Okay it's done' and when I try to check (with a deamon) for the file, there's nothing there.
What did I miss? Or is there something of an issue with CarrierWave and Rails mountable engines?
In your photo_uploader.rb
comment storage:file and uncomment storage:fog
# storage :file
storage :fog
--
Look at your fog.rb, Its inconsistent with what is given here
carrierwave#using-amazon-s3
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS', # required
:aws_access_key_id => 'xxx', # required
:aws_secret_access_key => 'yyy', # required
:region => 'eu-west-1' # optional, defaults to 'us-east-1'
:hosts => 's3.example.com' # optional, defaults to nil
:endpoint => 'https://s3.example.com:8080' # optional, defaults to nil
}
config.fog_directory = 'name_of_directory' # required
config.fog_public = false # optional, defaults to true
config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
end
Okay So there is a bit of a problem with CarrierWave.
I have quickly setup RightAws and now it uploads to S3 and I can find it from my deamon.
in my uploader I added
#s3 = RightAws::S3Interface.new('MY KEY', 'MY SECRET KEY')
#s3.put('my.bucket.com', assemble.photo.identifier ,params[:assemble][:photo])
Thanks for your help Nishant, CarrierWave would be a lot slicker and nicer but it currently does not work. There has been an issue for this in their github regarding use in Rails engines.

Resources