scala + jersey で rails のフォームにファイルアップロード

サンプルはどれが重要なコードが曖昧にする紋切り型を削除しています。
このコードは新規作成のみで、しかも画像以外のデータもアップロード出来ますが
本番では編集画面などの対応、サイズやファイルタイプのバリデーションやエラー表示をしてください。

環境

rails

rails test
cd test
script/generate scaffold test filename:string content_type:string size:integer data:binary
rake db:migrate
script/server

  • app/models/test.rb
class Test < ActiveRecord::Base
  def image=(args)
    self.size         = args.size
    self.content_type = args.content_type
    self.filename     = args.original_filename
    self.data         = args.read
  end
end
  • app/views/tests/new.html.erb
<% form_for(@test, :html => { :multipart => true }) do |f| %>
  <p><%= f.file_field :image %></p>
  <p><%= f.submit 'Create' %></p>
<% end %>
<%= link_to 'Back', tests_path %>
  • app/controllers/tests_controller.rb

クラスの一番下に追加

  def image
    @test = Test.find(params[:id])
    send_data(@test.data, :type => @test.content_type, :filename => @test.filename)
  end
  • app/views/tests/index.html.erb

ノイズになるので除外したが Show Edit Destroy のリンクはそのままでもOK

<table> 
<% @tests.each do |test| %>
  <tr>
    <td><%=h test.filename %></td>
    <td><%=h test.content_type %></td>
    <td><%=h test.size %></td>
    <td><%= image_tag(url_for(:action => :image, :id => test.id), :size => '100x32') %></td>
  </tr>
<% end %>
</table>
<br />
<%= link_to 'New test', new_test_path %>

scala

それぞれの jar に CLASSPATH を通す。
apidocs はバージョンが違うので詳しく知りたい人は自分で探してくだしあ。

  • jersey-client.jar, jersey-core.jar

http://jersey.java.net/nonav/documentation/latest/user-guide.html#core_client
http://jersey.java.net/nonav/apidocs/latest/jersey/index.html

  • mimepull.jar, jersey-multipart.jar

http://jersey.java.net/nonav/documentation/latest/user-guide.html#d4e1825
http://jersey.java.net/nonav/apidocs/1.5/contribs/jersey-multipart/index.html

import com.sun.jersey.api.client.{Client, WebResource}
import com.sun.jersey.multipart.FormDataMultiPart
import javax.ws.rs.core.MediaType

object Test {
  def main(args: Array[String]) {
    val file = new java.io.File("/Users/alphaneet/Pictures/test.jpg")
    // field(送信先のフォームの名前、ファイルパス、ファイルタイプ)
    val form = new FormDataMultiPart().field("test[image]", file, MediaType.valueOf("image/jpeg"))
    val wr = Client.create.resource("http://localhost:3000/tests")
    // post(戻り値の型、フォーム)
    val ret = wr.`type`(MediaType.MULTIPART_FORM_DATA).post(classOf[String], form)
    println(ret)
  }
}

scalac test.scala
scala Test

画像ファイルのパス や MediaType.valueOf("image/jpeg") は自分の環境に合わせる。
type メソッドは scala予約語なので バッククォーテーション でくくる。


ブラウザからアップロードする時と違ってファイル名(original_name)が設定されていない。
postのデータに何か追加してやればいいような気がするんですが、いまいち分かりません。
正直 http プロトコルについて詳しく知りません。api叩いてるだけみたいな。
誰か分かったら教えてください。