sinatra + html5_canvas + jquery 画像ドラッグドロップでファイル保存

こんにちは。麺処まつば副店長です。風が凄まじいですね(台風)
ここ暫く更新せずにいたら、ついに店長の大目玉をくらいました。
台風と店長の大目玉のダブルパンチ。恐ろしや……。

さて今日は、sinatra + HTML5 + jquerycanvas にドラッグドロップされた画像を
サーバに送信ファイル保存しつつ表示というのをやってみようと思います。
どれだけ需要があるか分かりませんが(笑)

手順はこんなカンジです。
1.views/index.haml
2.public/javascripts/dragdrop.js
3.app.rb

それでは作っていきましょう。

views/index.haml

副店長の悪いクセなんですが、まず見た目から入ります。
canvas をひとつだけおいたファイルを用意します。

  1 !!! XML
  2 !!!
  3 
  4 %html{:lang => "ja"}
  5   %head
  6     %meta{ :content=>"text/html", :charset=>"utf-8" }
  7     %title 画像
  8     %link{ :rel => "stylesheet", :href =>"/style.css" }
  9     %script{ :src => "javascript/jquery-1.6.2.min.js" }
 10     %script{ :src => "javascript/dragdrop.js" }
 11   %body
 12     #main
 13     %canvas{ :id=> "img_canvas",
 14              :width => "500", :height => "500",
 15              :ondragover => "onDragOver(event)", :ondrop => "onDrop(event)",
 16              :style => "border: medium dotted #666;"}

9、10行目で、自作する js ファイルと、使用する jquery を指定しています。
13〜16行目で、canvas を設置しています。
ondragover / ondrop で、自作 js の関数を呼びます。
それから、canvas の width と height は、
スタイルシートで指定しないほうがいいみたいです。
こないだ参加したHTML5勉強会の講師の先生が
スタイルシートで書くと何故かうまくいかないって仰ってました。
(そして自分では試してないので、どううまくいかないのかは良く分かりません(笑))

public/javascript/dragdrop.js

上記で書いた canvas に画像がドラッグドロップされたときに動く
javascript をかいていきます。

  1 function onDrop(event){
  2   // drop されたファイルの取得
  3   var f = event.dataTransfer.files[0];
  4 
  5   // drop されたファイルが画像ファイルの場合の処理
  6   if(/^image/.test(f.type)){
  7     // 画像ファイルを読み込むための準備 
  8     var img = document.createElement('img');
  9     var fr = new FileReader();
 10     
 11     fr.onload = function(){
 12       img.src = fr.result;
 13       img.onload = function() {
 14         // jquery ajax を使ってPOST
 15         new $.ajax({ 
 16           url: "/post_img",
 17           type: "POST", 
 18           data: {file: img.src},
 19           success: function(){
 20                      // canvas に画像描画
 21                      canvas = document.getElementById("img_canvas");
 22                      context = canvas.getContext("2d");
 23                      canvas.width = img.width;
 24                      canvas.height = img.height;
 25                      context.drawImage(img, 0, 0);
 26                    },
 27           error: function(){ alert("ごめん失敗した。");},
 28           complete: function(){ alert("保存した!"); }
 29         });
 30       }
 31     }
 32     fr.readAsDataURL(f);
 33   }
 34   
 35   // ブラウザがファイル自体を表示するのを防止
 36   event.preventDefault();
 37 } // end funciton [openDrop]
 38 
 39 function onDragOver(event){
 40   event.preventDefault();
 41 } // end function [onDragOver]

こんなカンジです。
15行目から、ajax を使って画像をPOSTしています。
成功すれば、canvas に読み込んだ画像を表示するようにしています。

app.rb

sinatraruby のファイルです。
画面表示と送信された画像を受けてファイル保存なぞします。

 1 #coding:utf-8
  2 
  3 require 'rubygems'
  4 require 'sinatra'
  5 require 'haml'
  6 
  7 configure :production do
  8 end
  9 
 10 get '/' do
 11   set :haml, :format => :html5
 12   haml :index
 13 end # end [get /]
 14 
 15 post '/post_img' do
 16   # 画像ファイルの取得
 17   img_array = params[:file].split(/\s*,\s*/)
 18   
 19   # 拡張子
 20   ext = ".dat"
 21   case img_array[0]
 22   when "data:image/jpeg;base64"
 23     ext = ".jpg"
 24   when "data:image/gif;base64"
 25     ext = ".gif"
 26   when "data:image/png;base64"
 27     ext = ".png"
 28   end
 29   
 30   # 画像ファイル保存
 31   f = File.open("tmp/image#{ext}",'w')
 32   f.puts img_array[1].unpack('m')[0]
 33   f.close
 34   return ""
 35 end
 36 
 37 get '/style.css' do
 38   content_type 'text/css', :charset => 'utf-8'
 39   sass :style
 40 end

10〜13行目で、/ へのGETの定義
15〜35行目で、post された画像を保存する処理を書いています。
ajaxからどんなデータが渡ってくるかなって思ったら、
base64エンコードされた文字列でした。
こんな感じの→「画像情報, エンコードされた文字列」

"data:image/jpeg;base64", "/9j/4AAQSkZJRgAB…

カンマ区切りだったんで配列化して、0番目の情報から画像情報を取得、
ファイル保存時の拡張子を指定しています(19〜28行目)
30〜33行目の間でファイルを保存しています。
終わりです。
※あ。「tmp」ディレクトリ作っといてくださいね。

では、さっそくできた画面内の canvas 領域に画像をドラッグドロップしてみましょう。
canvas に画像が表示されますか?→OK
サーバに画像は保存されますか?→OK

できました。
次回はコレをストレージに保存してみるところをやってみようと思います。

お世話になりますm(_ _)m
HTML5基礎

sinatra + haml + scss で stylesheet

おはようございます。麺処まつば副店長です。
珍しく朝っぱらからの更新です。

さて、先日まで sinatra + haml でゴニョゴニョやってたんですが、
ふとスタイルシートを使いたくなったので調べてみたら
sinatra は scss のテンプレートに対応しているようです。

ということで、今回は sinatra + haml + scss の使い方について簡単にまとめてみます。
本家→http://www.sinatrarb.com/intro-jp.html

手順はこんなカンジ

  • app.rb
  • views/style.scss
  • views/index.haml

では作っていきましょうー。

app.rb

  1 #coding:utf-8
  2 
  3 require 'rubygems'
  4 require 'sinatra'
  5 require 'haml'
  6 
  7 configure :production do
  8 end
  9 
 10 get '/' do
 11   set :haml, :format => :html5
 12   haml :index
 13 end # end [get /]
 14 
 15 get '/style.css' do
 16   content_type 'text/css', :charset => 'utf-8'
 17   sass :style
 18 end

10〜13行目にかけて「/」へのGETの定義。
15〜18行目にかけて、「/styhle.css」の定義をしています。

views/style.scss

  1 body
  2   padding:     20px
  3   background:  #d3d3d3
  4 
  5 img
  6   margin: 10px
  7   border: 5px
  8   solid:  #000000

scssを使うと、すっきりかけますね。

views/index.haml

  1 !!! XML
  2 !!!
  3 
  4 %html{:lang => "ja"}
  5   %head
  6     %meta{ :content=>"text/html", :charset=>"utf-8" }
  7     %title テスト
  8     %link{ :rel => "stylesheet", :href =>"/style.css" }
  9   %body
 10     #main

8行目で css 呼んでます。

勿論 public 配下において読み込んでも良いんですけど
scss 使うと css が綺麗に書けるからいいですね。

sinatra + haml で html5

こんにちは。麺処まつば副店長です。
先日からずっと目が痒かったのですが、放置していたら大変なことになりました。
慌てて病院に行って目薬をもらってきましたが
…年々抵抗力が落ちてきている気がしております…。

さて、副店長、最近やっとこさ HTML5 の勉強をはじめました。
で、折角なんで、こないだ中やってた sinatra + haml 上でやってみようと思いまして、
どうやるのか調べてたらすごい簡単にできたので、書いておきます。

#本当は書くまでもないくらい簡単なんですが、
#店長に「ちゃんと書いてます」アピールの記事稼ぎとかいうのは内緒です。

やり方は本当に簡単でした。
sinatra のファイルの下記一行追加するだけ。

set :haml, :format => :html5

終わりです(笑)
さすがにこれだけだと、「ちゃんと書いてます」アピールとして弱い気がするので
例も書いてみます

app.rb

  1 #coding:utf-8
  2 
  3 require 'rubygems'
  4 require 'sinatra'
  5 require 'haml'
  6 
  7 configure :production do
  8 end
  9 
 10 
 11 get '/' do
 12   set :haml, :format => :html5
 13   haml :index
 14 end # end [get /]

12行目で、html5の指定をしています。これだけです。
\わぁかんたん/

DataMapper Model

こんにちは。麺処まつば副店長です。

今日は DataMapper でレコードを扱う方法について少し調べてみました。
本家から、(副店長が)よく使いそうなものを拾ってきました。

本家はこちらです。
http://datamapper.org/docs/create_and_destroy
http://rubydoc.info/gems/dm-core/1.1.0/frames

検索

Zoo.all                                   # 全部取得
Zoo.all(:open => true)                    # open が true のものだけ
Zoo.all(:opened_on => start..end)         # opend_on が start 〜 end の期間のもの
Zoo.all(:order => [ :tiger_count.desc ])  # 虎の数で並び替え

Zoo.get(1)                # プライマリーキーが 1 
Zoo.get!(1)               # プライマリーキーが 1 失敗すると ObjectNotFoundError
Zoo.get('DFW')            # 自然(プライマリー)キーもサポート
Zoo.get('Metro', 'DFW')   # 複合キーでもいけます

更新(作成・更新・削除)

Zoo.create(
  :column1 => "column1 column1",
  :column2 => 15,
  :column3 => Time.now
)

# インスタンス生成して保存
zoo = Zoo.new(
  :column1 => "column1 column1",
  :column2 => 15,
  :column3 => Time.now
)
zoo.save

# 更新
Person.update(:allow_beer => true)

# 保存失敗で例外発生
User.raise_on_save_failure 

# 削除
zoo = Zoo.get(5)
zoo.destroy
# 全部消す
Zoo.all.destroy

# 合わせ技1:検索してなかったらcreate
zoo = Zoo.first_or_create(:name => 'The Glue Factory')

なんとなく分かったツモリになりました(気分だけ)

DataMapper property 

こんばんは。麺処まつば副店長です。
なんか知らんですが、目がかゆいです。
…と店長に訴えたら「ギガもあるのか」と言われました。エクサ目指して頑張ります。

さて、前回、DataMapper に挑戦したので、
それについてもう少し調べてみようと思います。
今回のターゲットは「property」です。

本家 API ページの Property から(副店長が)使いそうな情報だけ引っこ抜いてきました。
抜粋したものを簡単に並べてみます。
本家APIはコチラ→http://rubydoc.info/gems/dm-core/1.1.0/frames

property 定義の方法

 property :[プロパティ名], [型], :[オプション]

デフォルトで使える型

Boolean
Class (datastore primitive is the same as String. Used for Inheritance)
Date
DateTime
Decimal
Float
Integer
Object (marshalled out during serialization)
String (default length is 50)
Text (limit of 65k characters by default)
Time

オプション

プロパティに指定できるオプション

オプション 意味
:accessor accessor の設定。falseでreader + writer が作られない
:reader reader の設定。false で、reader が作られない
:writer writer の設定。false で writer が作られない
:lazy 遅延読み込み。false で設定解除。group指定もできる。
:default デフォルト値の設定
:allow_nil nil を許可するかどうか。true で許可。
:key キーの設定
:field フィールド(カラム名
:length 文字列の長さ設定。
:format autovalidationのフォーマット設定。dm-validations使う時
:index index の設定。trueにするとindex が作られる。
:unique_index ユニークな index 設定かな。true で指定
:auto_validation 自動 validation の設定。true で実行される。
:validates validation context 。dm-validations使う時に
:unique true でユニーク指定。Serial指定するとデフォルトでユニーク

あとは、IDとかにしたいカラムには「Serial」つけるとか。

その他

あとはメソッドが allow_blank? とか色々あるけどあんまり使わなそうなので、
使うときに見に行く形ですかね。

次回、find とか update とかそのへんの操作についてもう少し調べてみようと思います。

sinatra + heroku + DataMapper + postgreSQL

こんばんは。麺処まつば副店長です。
いやー空が禍々しいですね(雷)

さて、今日は heroku + sinatra で、DB を扱う部分をやってみようと思います。
あとから詳しくかきますけど、今回は postgreSQL と DataMapper 使います。

そんなわけで、今回のメニューはコチラです。

フォームから入力された文字列の最後に
勝手に「。。。多分。」と付加することにより
そこはかとなく胡散臭い文字列に仕立て上げた上でDBに保存する。
かつ保存された、そこはかとなく胡散臭い文字列を表示する。

今回の作り方はこのような流れです。

  • postgreSQL の用意
  • DataMapper の用意
  • bundler
  • migrate
  • モデルの用意
  • app.rb の用意
  • view の用意
  • ローカル動作確認
  • heroku に反映

それでは作っていきましょう。

postgreSQL の用意

heroku で使える DB は、標準で PostgreSQL や、あと MySQL
それから巷で話題の NoSQL なんかも扱えるみたいですが、
今回は、とりあえず、ということで標準の postgreSQL を使ってみようと思います。
(NoSQL は個人的に非常に気になる材料なので、後日やります。(宣言))

まずは、ローカルに PostgreSQL をいれちゃいましょう。
これは、環境によってインストール方法が違うと思うので特に書きません。…が、
副店長の Mac に postgreSQL 入れた時の記録でしたらこちらです
http://d.hatena.ne.jp/noodles_mtb/20110805/1312509838

DataMapper の用意

sinatra はモデルの機能持ってないので、どっかから調達してきます。
ActiveRecord とか、DataMapper とか、Sequelとか色々あるみたいですけど
今回は DataMapper 使ってみようと思います。
まず、DataMapper と、その postgreSQL のアダプター、
それから migrate もお願いしようと思うのでそれも。

$ gem install dm-core
$ gem install dm-postgres-adapter
$ gem install dm-migrations

DataMapper本家→http://datamapper.org/getting-started.html

bundler

DataMapper とか新しく入れたので、bundle する必要があります。
Gemfile

  1 source :rubygems
  2 gem 'sinatra'
  3 gem 'haml'
  4 gem 'dm-core'
  5 gem 'dm-postgres-adapter'
  6 gem 'dm-migrations'

4〜6行目が DataMapper 系の記述です。
これができたら、bundle しましょう

$ bundle update

これで DataMapper を使う準備は整いました。

モデルの用意

それでは、model を書いていきます。
今回は、フォームから入力されたテキストを胡散臭くして
DBに保存するだけなので、大したことは書きません。
word.rb

  1 require 'rubygems'
  2 require 'dm-core'
  3 
  4 class Word
  5 
  6   include DataMapper::Resource
  7   property :id, Serial
  8   property :msg, String
  9 
 10 end

これだけです。

migrate

モデルを作りましたが、肝心の DB がないとダメですね。
まず、postgreSQL に DB つくっといてください。

そしたら、dm-migrations を使って migrate をしましょう。
DataMapper で migrate する場合には、自動と手動の2種類があるようです。
(→http://route477.net/ramaze/?DataMapper
今回は自動の migrate を使ってみます。
(自動の場合、model 内に定義した propery をもとにmigrate するようです)
Rakefile

  1 require 'dm-core'
  2 require 'dm-migrations'
  3 require './word.rb'
  4 
  5 task 'db:migrate' do
  6   DataMapper.setup(:default, ENV['DATABASE_URL'] || 'postgres://user_name:user_password@localhost/db_name')
  7   DataMapper.auto_upgrade!
  8   self
  9 end

1〜2行目で、dm-core と dm-migrateions を使う宣言
3行目は、自作のモデルを呼んでいます(migrate の対象)
5〜9行目で、「db:migrate」の定義をしています。
6行目は、DataMapperを使ってDBに接続にいきます。6行目のコレ↓ですが、

ENV['DATABASE_URL'] || 'postgres://user_name:user_password@localhost/db_name')

これは、前者があれば前者、なければ後者につなぎにいきます。
ここでは、前者は heroku 上で使う DB 、これがなけば後者につなぎにいきます。
ここでは前者がないので後者、つまりローカルの postgreSQL に接続します。
それから、7行目の「auto_upgrade!」
これは、既存テーブルのデータを保持したまま自動 migration を行うものです。
「auto_migrate!」というのもありますが、既存テーブルのデータはなくなってしまいます。
場合に合わせてご利用ください。

※他の方が Rakefile をどういう風に書いてるのか拝見したところ
Rakefile の中で、別の Ruby のプログラムを呼んで
そこから migrate している方が多いようだったのですが
副店長はめんどks……げほげほ…
えー…、今回はお手軽版ということで、このように書いています。

それでは、migrate してみましょう。

$ rake db:migrate

きっと、db_name で指定した DB に新しくテーブルが追加されていると思います。

app.rbの用意

上記までの手順で、モデルを使う準備が整いました。
では、それを使っていきましょう。
app.rb

  1 #coding:utf-8
  2 
  3 require 'rubygems'
  4 require 'sinatra'
  5 require 'haml'
  6 require 'dm-core'
  7 require './word.rb'
  8 
  9 configure :production do
 10 end
 11 
 12 DataMapper.setup(:default, ENV['DATABASE_URL'] || 'postgres://user_name:user_password@localhost/db_name')
 13 
 14 get '/' do
 15   haml :index
 16 end # end [post /]
 17 
 18 post '/' do
 19   str = params[:str] + "。。。多分。"
 20   Word.create(:msg => str)
 21 
 22   @messages = Word.all(:order => [:id.desc])
 23   haml :index
 24 end # end [post /]

大したことはやってません。
6行目で dm-core を require
7行目で 自作の model ( word.rb ) を require
12行目で DB 接続設定。です。

18〜24行目で、post の定義をしています
19行目で 入力された文字列を胡散臭く加工。
20行目で DB に INSERT
22行目で DB に保存された word の一覧を取得しています。
はい、本当に大したことはしていません。

view の用意。

おっと。これでできたと思っていましたが
view のことをすっかり忘れておりました。
views/index.haml

  1 !!! XML
  2 !!!
  3 %html
  4   %head
  5     %meta{ :content=>"text/html", :charset=>"utf-8" }
  6     %title 胡散臭いよー
  7   %body
  8     #main
  9       %h1 胡散臭いよー
 10       %div 胡散臭い文字列なら任せてください。
 11       %form{:action=>"/", :method=>"post"}
 12         %input{:type=>"texfield",:name=>"str"}
 13         %input{:type=>"submit", :value=>"send"}
 14       - if @messages && !@messages.blank?
 15         - for msg in @messages
 16           %div= msg['msg']

本気で大したことしてないので、説明は省略します。

ローカルで動作確認

さて、できたかどうかためしてみましょう

$ rackup

http://localhost:9292/
で入力した任意の文字列が胡散臭くなってかえってきたら成功です。
→あぁぁ…胡散臭い。成功です。

heroku に反映

ローカルで確認できたので、heroku 上にあげてしまいましょう。
まずは、ファイルを上げてしまいます。

$ git commit -a -c "usan kusai"
$ git push heroku master

次に DB です。
rails 以外のプロジェクトの場合、デフォルトでDBが用意されてないそうなので
使う場合はこんなコマンドをたたいた上で migrate します

$ heroku addons:add shared-databasee
$ heroku rake db:migrate

そして、動作確認

$ heroku open

うさんくさくなりましたか?
→すっごい胡散臭いです。成功です。

これで、heroku をなんとなく使える気がしてきました。
どんどん胡散臭いものを作っていきましょう>自分

MacOS X Lion にpostgreSQLを入れる

こんにちは。麺処まつば副店長です。
今日はお休みをいただいてるんですが、今日もゴニョゴニョやってます。

さてさて、heroku + sinatra で DB を扱ってみようと思うんですが
まず自分のローカルにDB入ってないとダメでしょう。
ということで、本日のメニューは
「新しい相棒 MacBook Air (「にぼし号」と命名)に、
postgreSQLを入れてみよう!」 です。
( なぜかというと、heroku のデフォルトが postgreSQL だから)

手順はこんなカンジです

  • postgreSQL のインストール
  • pgAdmin のインストール

あ、予めMacPorts入れといてくださいね。
では作っていきましょう。

postgreSQL のインストール

コレがないとどうにもなりません。
まずは、このコマンドでpostgreSQLのバージョンを確認しましょう。

$ port search postgresql

見てみたところ、現時点では9.0が最新のようですので
コレをいれちゃいます。

$ sudo port install postgresql90
$ sudo port install postgresql90-server

入ったら、次は自動起動の設定をします。
(なんかログに出るやつそのままたたけば大丈夫です)

$ sudo launchctl load -w /Library/LaunchDaemons/org.macports.postgresql90-server.plist

DBの領域を確保して、初期化します

$ sudo mkdir -p /opt/local/var/db/postgresql90/defaultdb

$ sudo chown postgres:postgres /opt/local/var/db/postgresql90/defaultdb

$ sudo su postgres -c '/opt/local/lib/postgresql90/bin/initdb -D /opt/local/var/db/postgresql90/defaultdb'

あとそれと、起動と停止はこうです。

$ sudo su postgres -c '/opt/local/lib/postgresql90/bin/pg_ctl -D /opt/local/var/db/postgresql90/defaultdb -l /opt/local/var/db/postgresql90/logfile start'

$ sudo su postgres -c '/opt/local/lib/postgresql90/bin/pg_ctl -D /opt/local/var/db/postgresql90/defaultdb -m immediate stop'

では、入ったかやってみましょう。

$ /opt/local/lib/postgresql90/bin/psql -U postgres -l

DB一覧が出たら成功です。
おめでとうございます>自分

pgAdmin のインストール

pgAdminなんて便利なのがあるので、折角ですし入れましょう。
↓これMac用。さっくり落として、さっくさっく入れちゃってください。
http://www.pgadmin.org/download/macosx.php

入ったらさっくり起動して、さっくさっく繋いじゃいましょう。
データベース作ったりとか色々使い倒しましょう。>自分