Encoding issues when uploading files

Hello everybody,

I have some troubles with uploading files in my Rails project. I use Rails 3, Ruby 1.9.2, rack 1.2.1, and both webrick / passenger on apache

I was investigating and have isolated the strange behaviour on a simple empty project:

view:

<% form_tag({:action => 'upload'}, :multipart => true) do %>   <%=text_field_tag :desc %>   <%=file_field_tag :file %>   <%=submit_tag %> <% end %>

controller:

class IndexController < ApplicationController   def index   end

  def upload     render :text => params[:desc] + params[:file].original_filename   end end

The problem occurs, when I use national-specific characters in both "desc" field and the name of the file I'm uploading

Error:

incompatible character encodings: UTF-8 and ASCII-8BIT

Full trace: app/controllers/index_controller.rb:6:in `upload' actionpack (3.0.0) lib/action_controller/metal/implicit_render.rb:4:in `send_action' actionpack (3.0.0) lib/abstract_controller/base.rb:150:in `process_action' actionpack (3.0.0) lib/action_controller/metal/rendering.rb:11:in `process_action' actionpack (3.0.0) lib/abstract_controller/callbacks.rb:18:in `block in process_action' activesupport (3.0.0) lib/active_support/callbacks.rb:435:in `_run__1754744357340717012__process_action__4234728288224173498__callbacks' activesupport (3.0.0) lib/active_support/callbacks.rb:409:in `_run_process_action_callbacks' activesupport (3.0.0) lib/active_support/callbacks.rb:93:in `run_callbacks' actionpack (3.0.0) lib/abstract_controller/callbacks.rb:17:in `process_action' actionpack (3.0.0) lib/action_controller/metal/instrumentation.rb: 30:in `block in process_action' activesupport (3.0.0) lib/active_support/notifications.rb:52:in `block in instrument' activesupport (3.0.0) lib/active_support/notifications/instrumenter.rb: 21:in `instrument' activesupport (3.0.0) lib/active_support/notifications.rb:52:in `instrument' actionpack (3.0.0) lib/action_controller/metal/instrumentation.rb: 29:in `process_action' actionpack (3.0.0) lib/action_controller/metal/rescue.rb:17:in `process_action' actionpack (3.0.0) lib/abstract_controller/base.rb:119:in `process' actionpack (3.0.0) lib/abstract_controller/rendering.rb:40:in `process' actionpack (3.0.0) lib/action_controller/metal.rb:133:in `dispatch' actionpack (3.0.0) lib/action_controller/metal/rack_delegation.rb: 14:in `dispatch' actionpack (3.0.0) lib/action_controller/metal.rb:173:in `block in action' actionpack (3.0.0) lib/action_dispatch/routing/route_set.rb:62:in `call' actionpack (3.0.0) lib/action_dispatch/routing/route_set.rb:62:in `dispatch' actionpack (3.0.0) lib/action_dispatch/routing/route_set.rb:27:in `call' rack-mount (0.6.13) lib/rack/mount/route_set.rb:148:in `block in call' rack-mount (0.6.13) lib/rack/mount/code_generation.rb:93:in `block in recognize' rack-mount (0.6.13) lib/rack/mount/code_generation.rb:75:in `optimized_each' rack-mount (0.6.13) lib/rack/mount/code_generation.rb:92:in `recognize' rack-mount (0.6.13) lib/rack/mount/route_set.rb:139:in `call' actionpack (3.0.0) lib/action_dispatch/routing/route_set.rb:492:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/ best_standards_support.rb:17:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/head.rb:14:in `call' rack (1.2.1) lib/rack/methodoverride.rb:24:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/params_parser.rb: 21:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/flash.rb:182:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/session/ abstract_store.rb:149:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/cookies.rb:287:in `call' activerecord (3.0.0) lib/active_record/query_cache.rb:32:in `block in call' activerecord (3.0.0) lib/active_record/query_cache.rb:10:in `cache' activerecord (3.0.0) lib/active_record/query_cache.rb:31:in `call' activerecord (3.0.0) lib/active_record/connection_adapters/abstract/ connection_pool.rb:355:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/callbacks.rb:46:in `block in call' activesupport (3.0.0) lib/active_support/callbacks.rb:415:in `_run_call_callbacks' actionpack (3.0.0) lib/action_dispatch/middleware/callbacks.rb:44:in `call' rack (1.2.1) lib/rack/sendfile.rb:107:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/remote_ip.rb:48:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/show_exceptions.rb: 46:in `call' railties (3.0.0) lib/rails/rack/logger.rb:13:in `call' rack (1.2.1) lib/rack/runtime.rb:17:in `call' activesupport (3.0.0) lib/active_support/cache/strategy/local_cache.rb: 72:in `call' rack (1.2.1) lib/rack/lock.rb:11:in `block in call' <internal:prelude>:10:in `synchronize' rack (1.2.1) lib/rack/lock.rb:11:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/static.rb:30:in `call' railties (3.0.0) lib/rails/application.rb:168:in `call' railties (3.0.0) lib/rails/application.rb:77:in `method_missing' railties (3.0.0) lib/rails/rack/log_tailer.rb:14:in `call' rack (1.2.1) lib/rack/content_length.rb:13:in `call' rack (1.2.1) lib/rack/handler/webrick.rb:52:in `service' /usr/local/lib/ruby/1.9.1/webrick/httpserver.rb:111:in `service' /usr/local/lib/ruby/1.9.1/webrick/httpserver.rb:70:in `run' /usr/local/lib/ruby/1.9.1/webrick/server.rb:183:in `block in start_thread'

This is obviously just a silly example. But my real application makes use of the paperclip gem to attach gallery images to documents.

# encoding: utf-8 class GalleryImageController < ApplicationController   def create     @image = GalleryImage.create(params[:gallery_image])     redirect_to '/' + @image.document.url   end end

# encoding: utf-8 class GalleryImage < ActiveRecord::Base   belongs_to :document   has_attached_file :image, :styles => {:thumbnail => "250x200#"} end

When user tries to upload a file with name containing local characters and at the same time enters a description containg these characters, I get this error - only difference is, that it is burried somewhere deep inside AREL:

incompatible character encodings: UTF-8 and ASCII-8BIT

arel (1.0.1) lib/arel/engines/sql/relations/compiler.rb:85:in `join' arel (1.0.1) lib/arel/engines/sql/relations/compiler.rb:85:in `insert_sql' arel (1.0.1) lib/arel/algebra/relations/writes.rb:32:in `to_sql' arel (1.0.1) lib/arel/engines/sql/engine.rb:30:in `create' arel (1.0.1) lib/arel/algebra/relations/writes.rb:24:in `call' arel (1.0.1) lib/arel/session.rb:17:in `create' arel (1.0.1) lib/arel/algebra/relations/relation.rb:159:in `insert' activerecord (3.0.0) lib/active_record/relation.rb:14:in `insert' activerecord (3.0.0) lib/active_record/persistence.rb:271:in `create' activerecord (3.0.0) lib/active_record/timestamp.rb:47:in `create' activerecord (3.0.0) lib/active_record/callbacks.rb:281:in `block in create' activesupport (3.0.0) lib/active_support/callbacks.rb:413:in `_run_create_callbacks' activerecord (3.0.0) lib/active_record/callbacks.rb:281:in `create' activerecord (3.0.0) lib/active_record/persistence.rb:247:in `create_or_update' activerecord (3.0.0) lib/active_record/callbacks.rb:277:in `block in create_or_update' activesupport (3.0.0) lib/active_support/callbacks.rb:418:in `_run_save_callbacks' activerecord (3.0.0) lib/active_record/callbacks.rb:277:in `create_or_update' activerecord (3.0.0) lib/active_record/persistence.rb:39:in `save' activerecord (3.0.0) lib/active_record/validations.rb:43:in `save' activerecord (3.0.0) lib/active_record/attribute_methods/dirty.rb: 21:in `save' activerecord (3.0.0) lib/active_record/transactions.rb:237:in `block (2 levels) in save' activerecord (3.0.0) lib/active_record/transactions.rb:289:in `block in with_transaction_returning_status' activerecord (3.0.0) lib/active_record/connection_adapters/abstract/ database_statements.rb:139:in `transaction' activerecord (3.0.0) lib/active_record/transactions.rb:204:in `transaction' activerecord (3.0.0) lib/active_record/transactions.rb:287:in `with_transaction_returning_status' activerecord (3.0.0) lib/active_record/transactions.rb:237:in `block in save' activerecord (3.0.0) lib/active_record/transactions.rb:248:in `rollback_active_record_state!' activerecord (3.0.0) lib/active_record/transactions.rb:236:in `save' activerecord (3.0.0) lib/active_record/base.rb:498:in `create' app/controllers/gallery_image_controller.rb:5:in `create' actionpack (3.0.0) lib/action_controller/metal/implicit_render.rb:4:in `send_action' actionpack (3.0.0) lib/abstract_controller/base.rb:150:in `process_action' actionpack (3.0.0) lib/action_controller/metal/rendering.rb:11:in `process_action' actionpack (3.0.0) lib/abstract_controller/callbacks.rb:18:in `block in process_action' activesupport (3.0.0) lib/active_support/callbacks.rb:445:in `_run__606477216504222700__process_action__611054854482167000__callbacks' activesupport (3.0.0) lib/active_support/callbacks.rb:409:in `_run_process_action_callbacks' activesupport (3.0.0) lib/active_support/callbacks.rb:93:in `run_callbacks' actionpack (3.0.0) lib/abstract_controller/callbacks.rb:17:in `process_action' actionpack (3.0.0) lib/action_controller/metal/instrumentation.rb: 30:in `block in process_action' activesupport (3.0.0) lib/active_support/notifications.rb:52:in `block in instrument' activesupport (3.0.0) lib/active_support/notifications/instrumenter.rb: 21:in `instrument' activesupport (3.0.0) lib/active_support/notifications.rb:52:in `instrument' actionpack (3.0.0) lib/action_controller/metal/instrumentation.rb: 29:in `process_action' actionpack (3.0.0) lib/action_controller/metal/rescue.rb:17:in `process_action' actionpack (3.0.0) lib/abstract_controller/base.rb:119:in `process' actionpack (3.0.0) lib/abstract_controller/rendering.rb:40:in `process' actionpack (3.0.0) lib/action_controller/metal.rb:133:in `dispatch' actionpack (3.0.0) lib/action_controller/metal/rack_delegation.rb: 14:in `dispatch' actionpack (3.0.0) lib/action_controller/metal.rb:173:in `block in action' actionpack (3.0.0) lib/action_dispatch/routing/route_set.rb:62:in `call' actionpack (3.0.0) lib/action_dispatch/routing/route_set.rb:62:in `dispatch' actionpack (3.0.0) lib/action_dispatch/routing/route_set.rb:27:in `call' rack-mount (0.6.13) lib/rack/mount/route_set.rb:148:in `block in call' rack-mount (0.6.13) lib/rack/mount/code_generation.rb:93:in `block in recognize' rack-mount (0.6.13) lib/rack/mount/code_generation.rb:82:in `optimized_each' rack-mount (0.6.13) lib/rack/mount/code_generation.rb:92:in `recognize' rack-mount (0.6.13) lib/rack/mount/route_set.rb:139:in `call' actionpack (3.0.0) lib/action_dispatch/routing/route_set.rb:492:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/ best_standards_support.rb:17:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/head.rb:14:in `call' rack (1.2.1) lib/rack/methodoverride.rb:24:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/params_parser.rb: 21:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/flash.rb:182:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/session/ abstract_store.rb:149:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/cookies.rb:287:in `call' /home/jenda/.bundler/ruby/1.9.1/rails-ckeditor-ffb4026/lib/ckeditor/ middleware.rb:15:in `call' activerecord (3.0.0) lib/active_record/query_cache.rb:32:in `block in call' activerecord (3.0.0) lib/active_record/connection_adapters/abstract/ query_cache.rb:28:in `cache' activerecord (3.0.0) lib/active_record/query_cache.rb:12:in `cache' activerecord (3.0.0) lib/active_record/query_cache.rb:31:in `call' activerecord (3.0.0) lib/active_record/connection_adapters/abstract/ connection_pool.rb:355:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/callbacks.rb:46:in `block in call' activesupport (3.0.0) lib/active_support/callbacks.rb:415:in `_run_call_callbacks' actionpack (3.0.0) lib/action_dispatch/middleware/callbacks.rb:44:in `call' rack (1.2.1) lib/rack/sendfile.rb:107:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/remote_ip.rb:48:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/show_exceptions.rb: 46:in `call' railties (3.0.0) lib/rails/rack/logger.rb:13:in `call' rack (1.2.1) lib/rack/runtime.rb:17:in `call' activesupport (3.0.0) lib/active_support/cache/strategy/local_cache.rb: 72:in `call' rack (1.2.1) lib/rack/lock.rb:11:in `block in call' <internal:prelude>:10:in `synchronize' rack (1.2.1) lib/rack/lock.rb:11:in `call' actionpack (3.0.0) lib/action_dispatch/middleware/static.rb:30:in `call' railties (3.0.0) lib/rails/application.rb:168:in `call' railties (3.0.0) lib/rails/application.rb:77:in `method_missing' railties (3.0.0) lib/rails/rack/log_tailer.rb:14:in `call' rack (1.2.1) lib/rack/content_length.rb:13:in `call' rack (1.2.1) lib/rack/handler/webrick.rb:52:in `service' /usr/local/lib/ruby/1.9.1/webrick/httpserver.rb:111:in `service' /usr/local/lib/ruby/1.9.1/webrick/httpserver.rb:70:in `run' /usr/local/lib/ruby/1.9.1/webrick/server.rb:183:in `block in start_thread'

I'm able to make a workaround like this:

  def create

    # force encoding of the original filename to utf-8     params[:gallery_image] [:image].original_filename.force_encoding('utf-8')

    @image = GalleryImage.create(params[:gallery_image])     redirect_to '/' + @image.document.url.url   end

But I don't think it's supposed to be like this. Shouldn't rack take care of this for me ?

Thanks for contributions,

Best regards Jan Koritak