jckly
jckly

Reputation: 851

Where should I put images in a heroku rails app?

I have an iOS api linking to a rails app. I have sent the rails app an iOS image which I'm trying to store as header_img but am getting an error that they're is no public directory. What is a good path to specify for images in my heroku api?

Here is the heroku error:

2014-04-04T21:51:47.179916+00:00 app[web.1]: 
2014-04-04T21:51:47.179916+00:00 app[web.1]: Errno::EISDIR (Is a directory - public/header_img/):
2014-04-04T21:51:47.179916+00:00 app[web.1]:   app/controllers/groups_controller.rb:98:in `initialize'
2014-04-04T21:51:47.179916+00:00 app[web.1]:   app/controllers/groups_controller.rb:98:in `open'
2014-04-04T21:51:47.179916+00:00 app[web.1]:   app/controllers/groups_controller.rb:98:in `upload_header_img'
2014-04-04T21:51:47.179916+00:00 app[web.1]:   app/controllers/groups_controller.rb:44:in `create'

Here is my Groups Controller:

class GroupsController < ApplicationController
  # GET /groups
  # GET /groups.json

  before_filter :require_auth

  def index
    @privategroups = @user.groups
    @publicgroups = @user.followees(Group)

    @groups = (@privategroups + @publicgroups).sort_by( &:created_at ).reverse
  end

  # GET /groups/1
  # GET /groups/1.json
  def show
    @group = Group.find(params[:id])
    @posts = @group.posts
  end

  # GET /groups/new
  # GET /groups/new.json
  def new
    @group = Group.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @group }
    end
  end

  # GET /groups/1/edit
  def edit
    @group = Group.find(params[:id])
  end

  # POST /groups
  # POST /groups.json
  def create
    @group = Group.new(params[:group])
    @group.owner_id = @user.id
    header_img = @group.header_img || @group.decode_header_img_data
    if header_img.present?
      upload_header_img(header_img)
    end

    respond_to do |format|
      if @group.save
        @membership = @user.memberships.build(group_id: @group.id)
        @membership.save
        format.html { redirect_to @group, notice: 'Group was successfully created.' }
        format.json { render json: @group, status: :created, location: @group }
      else
        format.html { render action: "new" }
        format.json { render json: @group.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /groups/1
  # PUT /groups/1.json
  def update
    @group = Group.find(params[:id])

    respond_to do |format|
      if @group.update_attributes(params[:group])
        format.html { redirect_to @group, notice: 'Group was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @group.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /groups/1
  # DELETE /groups/1.json
  def destroy
    @group = Group.find(params[:id])
    @group.destroy

    respond_to do |format|
      format.html { redirect_to groups_url }
      format.json { head :no_content }
    end
  end

  private  
   def upload_header_img(header_img_io)           
      # upload to the exact location account id and extension
      extension = File.extname(header_img_io.original_filename)
      # rails take public as root directory
      # under the root directory (public)
      # there are a icon directory
      header_img_url = "/header_img/"[email protected]_s + extension

      # open in binary mode
      File.open("public"+header_img_url,'wb') do |file|
      file.write(header_img_io.read)
      end

      @group.update_attribute(:header_img_url, header_img_url)
   end
end

Upvotes: 1

Views: 132

Answers (1)

Richard Peck
Richard Peck

Reputation: 76774

Although I can't provide a direct answer, I have some ideas which may help:


According to Heroku, they run a read-only filesystem:

Your app is compiled into a slug for fast distribution by the dyno manager. The filesystem for the slug is read-only, which means you cannot dynamically write to the filesystem for semi-permanent storage. The following types of behaviors are not supported:

  • Caching pages in the public directory
  • Saving uploaded assets to local disk (e.g. with attachment_fu or paperclip)
  • Writing full-text indexes with Ferret Writing to a filesystem database like SQLite or GDBM
  • Accessing a git repo for an app like git-wiki

CORRECTION

Have since found the above is for their Bamboo stack (old). The cedar stack (new) supports temporary file writing:

Each dyno gets its own ephemeral filesystem, with a fresh copy of the most recently deployed code. During the dyno’s lifetime its running processes can use the filesystem as a temporary scratchpad, but no files that are written are visible to processes in any other dyno and any files written will be discarded the moment the dyno is stopped or restarted.

We do use Paperclip & upload to Heroku (when in test), it's generally not supported and any files will be overwritten each time you redeploy your app


Storage

ChrisBarthol gave a good suggestion - store any user-submitted assets on S3 or another third party system. I would go further and say that you'll probably benefit profusely from using Paperclip to save the files:

#app/models/group.rb
Class Group < ActiveRecord::Base
    has_attached_file :header_img
       :storage => :s3,
       :s3_credentials => Proc.new{|a| a.instance.s3_credentials }

    validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/   
end

Upvotes: 1

Related Questions