2
votes

I'm trying to switch from AWS to Cloudinary to manage images on my website. I'm using Cloudinary with CarrierWave on a Rails app and followed Cloudinary's guide to setting up image uploading and storage (http://cloudinary.com/documentation/rails_carrierwave). When I try to uploaded I get this error:

Cloudinary::CarrierWave::UploadError in UsersController#update

Invalid Signature (value removed). String to sign - 'public_id=(value removed)sf&timestamp=1433525724'.

Here is my update method in my users controller:

def update
   @user = User.find(params[:id])
   if @user.update_attributes(user_params)
      flash[:notice] = "User information updated!"
      redirect_to edit_user_registration_path
   else
      flash[:error] = "Error updating user information!"
      redirect_to :back
   end
end

def user_params
  params.require(:user).permit(:name, :picture, :picture_cache)
end

Here is my uploader file:

class PictureUploader < CarrierWave::Uploader::Base

   include Cloudinary::CarrierWave

   version :main do
       process :resize_to_fill => [300, 350]
   end
   # def scale(width, height)
   #   # do something
   # end

   # Create different versions of your uploaded files:
   version :icon do
      process :resize_to_fit => [18, 21]
   end
   version :small do
     process :resize_to_fit => [54, 63]
   end
   version :profile do
     process :resize_to_fit => [180, 210]
   end

   def extension_white_list
     %w(jpg jpeg gif png)
   end
 end

Any ideas are greatly appreciated. Thanks!

2
Hi, if you (or anyone else) are still experiencing similar issues, the best way to resolve it is probably to contact Cloudinary via a support ticket. The tech-support team will be happy to inspect that issue and help resolving it.Nadav Ofir

2 Answers

4
votes

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 on 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"] %>

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

You also need to configure an environmental variable named CLOUDINARY_URL(available on the management console of the cloudinary account. (Dashboard > Account Details)) on heroku with the following command:

heroku config:set CLOUDINARY_URL="your cloudinary url"

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!

0
votes

Thanks for getting back to me. I was actually going to post back today that I was unable to fix the issue so I went back to AWS using Carrierwave, Fog and Minimagick. There I had an issue with an invalid signature so I had to create a new bucket in the US region - the Frankfurt region requires the new v4 signature which was causing the issue that led me to try Cloudinary. By using the new bucket, I was able to upload pictures successfully. Here is the form code I was using with Cloudinary:

<h2>Update Profile</h2>
<div class="row">
  <div class="col-md-8">
    <%= form_for current_user, multipart: true do |f| %>

      <div class="form-group">
        <%= f.label :name %><br />
        <%= f.text_field :name, autofocus: true, class: "form-control", placeholder: "Add a Name?" %>
      </div>
      <% if current_user.picture? %>
        <div class="form-group">
          <p>Current Profile Picture</p>
          <%= image_tag( current_user.picture.main.url ) %>
        </div>
      <% end %>
      <div class="form-group">
        <%= f.label :profile_picture %>
        <%= f.file_field :picture %>
        <%= f.hidden_field :picture_cache %>
      </div>

      <div class="form-group">
        <%= f.submit "Update", class: "btn btn-md btn-success" %>
      </div>
    <% end %>
  </div>
</div>

<h2>Change Password</h2>
<div class="row">
  <div class="col-md-8">
    <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
      <%= devise_error_messages! %>

      <div class="form-group">
        <%= f.label :email %><br />
        <%= f.email_field :email, class: "form-control", placeholder: "Enter Email" %>
      </div>

      <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
        <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
      <% end %>

      <div class="form-group">
        <%= f.label :password %>
        <%= f.password_field :password, autocomplete: "off", class: "form-control", placeholder: "Enter New Password" %>
      </div>

      <div class="form-group">
        <%= f.label :password_confirmation %>
        <%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control", placeholder: "Confirm New Password" %>
      </div>

      <div class="form-group">
        <%= f.label :current_password %>
        <%= f.password_field :current_password, autocomplete: "off", class: "form-control", placeholder: "Confirm Current Password" %>
      </div>

      <div class="form-group">
        <%= f.submit "Update", class: "btn btn-md btn-success" %>
      </div>
    <% end %>
  </div>
</div>

<h3>Cancel my account</h3>

<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), class: 'btn btn-md btn-danger', data: { confirm: "Are you sure you want to cancel your account?" }, method: :delete %></p>

<%= link_to "Back", :back %>

I'm curious to figure out what the issue was in case I use cloudinary in the future.