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