REXML

[16]REXML
1.REXML
Ruby上で動作するXMLプロセッサで、ツリー解析とストリーム解析の両方の文書解析をサポートします。Ruby1.8からは標準添付されているライブラリです。

1-1.プロジェクトの生成
(1) プロジェクトAppli026を生成する
(2) 日本語環境の設定
(3) データベースの作成
テストをする場合はProject_testの環境で実施されるのでDBもそれに対応します。(db:create:allの指定)
NetBeansで[Rakeタスクを実行/デバッグ..]を選択します。
    フィルタ(F):
    パラメータ(P):
    一致するタスク(M):db:create:all


実行結果
(in D:/Rails_Projects/Appli026)

1-2.xmlファイルの作成
価格.comからサンプルデータを得て、次のようなxmlファイルを作成しましょう。


tvbest10.xml


バイデザイン74,800131


東芝78,0007


シャープ80,00018


三菱電機80,50045


SONY83,80027


ユニデン88,000310


シャープ89,80030


SONY89,80066


東芝91,200123


東芝92,6848


1-3.アプリケーションの作成
(1) コントローラの生成
NetBeansで[生成…]を選択します。
    ジェネレート(G): controller
    名前(N): xml
    ビュー(V):


実行結果
exists app/controllers/
exists app/helpers/
create app/views/xml
exists test/functional/
create test/unit/helpers/
create app/controllers/xml_controller.rb
create test/functional/xml_controller_test.rb
create app/helpers/xml_helper.rb
create test/unit/helpers/xml_helper_test.rb

(2) コントローラの編集


/app/controllers/xml_controller.rb
class XmlController < ApplicationController
require "rexml/document"
include REXML

def index
@doc = Document.new File.new("tvbest10.xml")
end
end

(3) ビューの作成


/app/views/xml/index.html.erb

<%=h @doc %>

(4) 動作確認
登録したxmlファイルが読み込まれることを確認するため、ブラウザからhttp://127.0.0.1:3000/xml/でプログラムを起動します。

1-4.さまざまな機能
詳細な仕様はhttp://pub.cozmixng.org/~kou/rexml-doc-ja/でみることができますが、ここではその幾つかを紹介します。

(1) 要素の取り出し


/app/controllers/xml_controller.rb
class XmlController < ApplicationController
require "rexml/document"
include REXML

def index
@doc = Document.new File.new("tvbest10.xml")
# 要素の取り出し
@makers=""
@doc.elements.each("tv/model/maker") { |element|
@makers += element.to_s + "<br>"
}
end
end




/app/views/xml/index.html.erb
<br/>
makers<br/>
--------<br/><%= @makers %>




実行結果
makers
----------
バイデザイン
東芝
シャープ
三菱電機
SONY
ユニデン
シャープ
SONY
東芝
東芝

(2) 属性の取り出し

/app/controllers/xml_controller.rb
class XmlController < ApplicationController
require "rexml/document"
include REXML

def index
@doc = Document.new File.new("tvbest10.xml")
# 属性の取り出し
@names=""
XPath.each(@doc, "//model/attribute::name") { |element|
@names += element.to_s + "<br>"
}
end
end




/app/views/xml/index.html.erb
<br/>
names<br/>
--------

<%= @names %>




実行結果
names
--------
ALF-4205DB (42)
REGZA 40A8000 (40)
AQUOS LC-40AE6 (40)
REAL LCD-40MXW300 (40)
BRAVIA KDL-40EX500 (40)
TL42DZ1-B (42)
AQUOS LC-40DS6 (40)
BRAVIA KDL-40V5 (40)
REGZA 42C8000 (42)
REGZA 40R9000 (40)

(3) XMLの削除


/app/controllers/xml_controller.rb
class XmlController < ApplicationController
require "rexml/document"
include REXML

def index
@doc = Document.new File.new("tvbest10.xml")
# XMLデータの削除
@doc.elements.delete("tv/model[1]") # modelという名の要素の中で一番目の要素を削除する
end
end





/app/views/xml/index.html.erb
doc<br>
--------</br><%=h @doc %>




実行結果(実際はベタ表示)
doc
--------


バイデザイン74,800131


東芝78,0007


シャープ80,00018


三菱電機80,50045


SONY83,80027


ユニデン88,000310


シャープ89,80030


SONY89,80066


東芝91,200123


東芝92,6848



(4) XMLの更新

/app/controllers/xml_controller.rb
class XmlController < ApplicationController
require "rexml/document"
include REXML

def index
@doc = Document.new File.new("tvbest10.xml")
# XMLデータの更新
@doc.elements["tv/model[@name='REGZA 40R9000 (40)']/price"].text = "91,500"
# modelという要素のnameという属性が'REGZA 40R9000 (40)'である要素に含まれるpriceの値を
# 91,500に変更する
end
end




/app/views/xml/index.html.erb
<br/>
doc<br/>
--------<br/><%=h @doc %>




実行結果(実際はベタ表示)
doc
--------


東芝78,0007


シャープ80,00018


三菱電機80,50045


SONY83,80027


ユニデン88,000310


シャープ89,80030


SONY89,80066


東芝91,200123


東芝91,5008


(5) XMLの追加


/app/controllers/xml_controller.rb
class XmlController < ApplicationController
require "rexml/document"
include REXML

def index
@doc = Document.new File.new("tvbest10.xml")

# XMLデータの追加
root = @doc.root

model = Element.new "model"
model.attributes["name"] = "AQUOS LC-40DS6 (40)"

maker = Element.new "maker"
price = Element.new "price"
ranking = Element.new "ranking"

model.add_element "maker"
model.elements["maker"].text = "シャープ"
model.add_element "price"
model.elements["price"].text = "92,000"
model.add_element "ranking"
model.elements["ranking"].text = "30"

root.add_element model
end
end




/app/views/xml/index.html.erb
<br/>
doc<br/>
--------<br/><%=h @doc %>




実行結果(実際はベタ表示)
doc
--------


東芝78,0007


シャープ80,00018


三菱電機80,50045


SONY83,80027


ユニデン88,000310


シャープ89,80030


SONY89,80066


東芝91,200123


東芝92,6848


シャープ92,00030


(6) XMLの出力


/app/controllers/xml_controller.rb
class XmlController < ApplicationController
require "rexml/document"
include REXML

def index
@doc = Document.new File.new("tvbest10.xml")
# XMLファイルの出力
File.open("tvbest11.xml","w") do |outfile|
@doc.write(outfile)
end
end
end



Open Flash Chart | index | 地図の表示 →

OpenFlashChart

[15]OpenFlashChart
1.Open Flash Chart
Web上でグラフ表示が簡単にできるOpenFlashChartを紹介します。

1-1.プロジェクトの生成
(1) プロジェクトAppli024を生成する
(2) 日本語環境の設定
(3) データベースの作成
テストをする場合はProject_testの環境で実施されるのでDBもそれに対応してください。(db:create:allの指定)
NetBeansで[Rakeタスクを実行/デバッグ..]を選択します。
    フィルタ(F):
    パラメータ(P):
    一致するタスク(M):db:create:all


実行結果
(in D:/Rails_Projects/Test000)

1-2.Open Flash Chartのインストール
(1) Open Flash Chartのダウンロード
Open Flash Chartはhttp://github.com/pullmonkey/open_flash_chartにあり、をクリックして、
ここから直接pullmonkey-open_flash_chart-1489b25.zipをダウンロードします。

(2) Open Flash Chartのインストール
解凍したフォルダをopen_flash_chartにリネームして/vendor/plugins/配下にコピーします。

(3) swfobject.jsファイルのコピー
プラグインに入っている/vendor/plugins/open_flash_chart/assets/javascripts/swfobject.js ファイルを /public/javascriptsディレクトリにコピーします。

(4) open-flash-chart.swfファイルのコピー
プラグインに入っている/vendor/plugins/open_flash_chart/assets/open-flash-chart.swf ファイルを /publicディレクトリにコピーします。

1-3.アプリケーションの作成
(1) scaffoldの利用
NetBeansで[生成..]を選択します。
    ジェネレータ(G): scaffold
    モデル(N):Sale
    属性ペア(フィールド型)(A): sales_moon:date amount_of_sales:integer


実行結果
exists app/models/
exists app/controllers/
exists app/helpers/
create app/views/sales
exists app/views/layouts/
exists test/functional/
exists test/unit/
create test/unit/helpers/
exists public/stylesheets/
create app/views/sales/index.html.erb
create app/views/sales/show.html.erb
create app/views/sales/new.html.erb
create app/views/sales/edit.html.erb
create app/views/layouts/sales.html.erb
create public/stylesheets/scaffold.css
create app/controllers/sales_controller.rb
create test/functional/sales_controller_test.rb
create app/helpers/sales_helper.rb
create test/unit/helpers/sales_helper_test.rb
route map.resources :sales
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/sale.rb
create test/unit/sale_test.rb
create test/fixtures/sales.yml
create db/migrate
create db/migrate/20100310054934_create_sales.rb

(2) マイグレーションの実行
NetBeansで[データベースマイグレーション]→[現在のバージョンへ]を選択します。


実行結果
(in D:/Rails_Projects/Appli024)
== CreateSales: migrating ====================================================
-- create_table(:sales)
-> 0.1880s
== CreateSales: migrated (0.1880s) ===========================================

1-4.ルーティングの設定
グラフ表示のメソッドの起動をRESTfulから外したルーティング設定とします。
これによりhttp://127.0.0.1:3000/graph/:action/:idで目的のメソッドが起動できるようになります。
例えば、
http://127.0.0.1:3000/graph/line_graph → {:controller=>'sales', :action=>'line_graph'}
http://127.0.0.1:3000/graph/test_graph/1 → {:controller=>'sales', :action=>'test_graph'}
http://127.0.0.1:3000/graph/test_graph/2 → {:controller=>'sales', :action=>'test_graph'}
http://127.0.0.1:3000/graph/test1_code → {:controller=>'sales', :action=>'test1_code'}
http://127.0.0.1:3000/graph/test2_code → {:controller=>'sales', :action=>'test2_code'}
となります。


/config/routes.rb
ActionController::Routing::Routes.draw do |map|
map resources :sales


# consider removing or commenting them out if you're using named routes and resources.

map.connect '/graph/:action/:id', :controller => 'sales'

map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end


1-5.棒グラフ
(1) コントローラの作成


/app/controllers/sales_controller.rb
class SalesController < ApplicationController
def test_graph
@graph = open_flash_chart_object(600,400, "/graph/test1_code")
end

def test1_code
title = Title.new("Bar Chart")
bar = Bar.new
bar.set_values([1,2,3,4,5,6,7,8,9])
chart = OpenFlashChart.new
chart.set_title(title)
chart.add_element(bar)
render :text => chart.to_s
end


end

(2) ビューの修正


/app/views/test1_graph.html.erb
<script type="text/javascript" src="/javascripts/swfobject.js"></script><%= @graph %>

(3) 動作確認
ブラウザからhttp://127.0.0.1:3000/graph/test1_graphで起動します。
このURLにより設定したルーティングに従って{:controller=>'sales', :action=>'test1_graph'}が起動されます。
(棒グラフ)

1-6.折れ線グラフ
(1) コントローラの作成
テストプログラムごとにコントローラとビューを書くのは大変です。少しロジックに手を入れてコーディングの量を減らしましょう。


/app/controllers/sales_controller.rb
class SalesController < ApplicationController
def test_graph
path="/graph/test" + params[:id].to_s + "_code"
@graph = open_flash_chart_object(600,400,path)
end

def test1_code

end

def test2_code
title = Title.new("Line Chart")
line = Line.new
line.set_values([1,6,2,7,3,8,4,9,5])
chart = OpenFlashChart.new
chart.set_title(title)
chart.add_element(line)
render :text => chart.to_s
end


end

(2) ビューの修正
コントローラのメソッドがtest_graph一本になり、ビューはそれに対応する一つのプログラムでOKとなります。


/app/views/test_graph.html.erb
<script type="text/javascript" src="/javascripts/swfobject.js"></script><%= @graph %>

(3) 動作確認
ブラウザからhttp://127.0.0.1:3000/graph/test_graph/2で起動します。
このURLにより設定したルーティングに従って{:controller=>'sales', :action=>'test_graph'}が起動されます。
さらにtest_graphメソッドの中で/graph/test2_codeが呼ばれることになります。

(折れ線グラフ)

1-7.円グラフ
(1) コントローラの作成


/app/controllers/sales_controller.rb
class SalesController < ApplicationController


def test3_code
title = Title.new("Pie Chart")
pie = Pie.new
pie.start_angle = -90
pie.colours = ["#0000ff", "#00ff00", "#00ffff", "#ff0000", "#ff00ff"]
pie.values = [2, 3, 4, 5, 6]
chart = OpenFlashChart.new
chart.set_title(title)
chart.add_element(pie)
render :text => chart.to_s
end


end

(2) 動作確認
ブラウザからhttp://127.0.0.1:3000/graph/test_graph/3で起動します。
(円グラフ)

1-8.横棒グラフ
(1) コントローラの作成


/app/controllers/sales_controller.rb
class SalesController < ApplicationController

def test4_code
title = Title.new("Horizontal Bar chart Chart")
hbar = HBar.new
hbar.values = [HBarValue.new(0,4), HBarValue.new(4,8), HBarValue.new(8,11)]
chart = OpenFlashChart.new
chart.set_title(title)
chart.add_element(hbar)
x = XAxis.new
x.set_offset(false)
x.set_labels(['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'])
chart.set_x_axis(x)
y = YAxis.new
y.set_offset(true)
y.set_labels(["Phase3", "Phase2", "Phase1"])
chart.set_y_axis(y)
render :text => chart.to_s
end

end
ここで注意しなければならないのがデータ値は上から順に設定していますが、
Y軸のラベルは下から設定していることです。

(2) 動作確認
ブラウザからhttp://127.0.0.1:3000/graph/test_graph/4で起動します。
(横棒グラフ)

1-9.データの登録
ブラウザからhttp://127.0.0.1:3000/sales/でアプリケーションを起動しテスト用の売上データを登録します。

sales_moonamount_of_sales
2009-0118,300,000
2009-0214,900,000
2009-0316,900,000
2009-049,800,000
2009-0511,300,000
2009-0612,500,000
2009-0716,500,000
2009-0815,200,000
2009-0920,600,000
2009-1023,100,000
2009-1121,300,000
2009-1220,000,000
2010-0119,600,000
2010-0215,200,000
2010-0315,800,000
2010-0413,300,000
2010-059,500,000
2010-068,800,000
2010-076,000,000

1-10.折れ線グラフによる売上推移表の作成
(1) コントローラの作成


/app/controllers/sales_controller.rb
class SalesController < ApplicationController


def line_graph
@graph = open_flash_chart_object(600,400,"/graph/line_graph_code")
end

def line_graph_code
# 2009年の売上のみ抽出
@sales=Sale.find(:all,
:conditions => ['sales_moon>? and sales_moon 'sales_moon')

@amountofsales=[]
@salesmoon=[]
for i in 0..11 do
@amountofsales<<@sales[i][:amount_of_sales].to_i # 売上額を数値に変換
@salesmoon<<@sales[i][:sales_moon].to_s[2..6] # 売上月を文字列に変換
end

title = Title.new("売上推移表")

line_pv = Line.new
line_pv.text = "売上額"
line_pv.width = 1
line_pv.colour = '#4682B4'
line_pv.dot_size = 2
line_pv.values = @amountofsales # 売上額データのセット

# the X Axis Labels
x_labels = XAxisLabels.new

# text: Label text
x_labels.labels = @salesmoon # X軸ラベルのセット

# steps: show every other label
x_labels.set_steps(1)

# color: HTML Hex colour
x_labels.set_colour('#0000ff')

# size: Font size in pixels
x_labels.set_size(10)

# rotate: String can be one of "vertical" "diaganol" or "horizontal"
x_labels.set_rotate('vertical')

# Add the X Axis Labels to the X Axis
x = XAxis.new
x.set_labels(x_labels)

y = YAxis.new
y.set_range(0,40000000,2000000) # Y軸基準データのセット

x_legend = XLegend.new("Time")
x_legend.set_style('{font-size: 20px; color: #778877}')

y_legend = YLegend.new("Amount")
y_legend.set_style('{font-size: 20px; color: #770077}')

chart =OpenFlashChart.new
chart.set_title(title)
chart.set_x_legend(x_legend)
chart.set_y_legend(y_legend)
chart.x_axis = x
chart.y_axis = y

chart.add_element(line_pv)

render :text => chart.to_s
end


end

(2) ビューの修正


/app/views/line_graph.html.erb
<script type="text/javascript" src="/javascripts/swfobject.js"></script><%= @graph %>

(3) 動作確認
ブラウザからhttp://127.0.0.1:3000/graph/line_graphで起動します。
このURLにより設定したルーティングに従って{:controller=>'sales', :action=>'line_graph'}が起動されます。
(折れ線グラフ)

1-11.棒グラフによる売上前年比較表の作成
(1) コントローラの作成


/app/controllers/sales_controller.rb
class SalesController < ApplicationController


def bar_graph
@graph = open_flash_chart_object(600,400,"/graph/bar_graph_code")
end


def bar_graph_code
@sales2009=Sale.find(:all,
:conditions => ['sales_moon>? and sales_moon 'sales_moon')
@sales2010=Sale.find(:all,
:conditions => ['sales_moon>? and sales_moon 'sales_moon')
@amountofsales=[]
@amountofsales2=[]
@salesmoon=["01","02","03","04","05","06","07","08","09","10","11","12"]
for i in 0..11 do
@amountofsales<<@sales2009[i][:amount_of_sales].to_i
@amountofsales2<<@sales2010[i][:amount_of_sales].to_i if i < @sales2010.count
end

title = Title.new("売上前年比較表")

bar = Bar.new
bar.values = @amountofsales
bar.tooltip = "前年
金額=#val#"
bar.colour = '#47092E'

bar2 = Bar.new
bar2.values = @amountofsales2
bar2.tooltip = "当年
金額=#val#"
bar2.colour = '#CC2A43'

# the X Axis Labels
x_labels = XAxisLabels.new

# text: Label text
x_labels.labels = @salesmoon

# steps: show every other label
x_labels.set_steps(1)

# color: HTML Hex colour
x_labels.set_colour('#0000ff')

# size: Font size in pixels
x_labels.set_size(10)

# rotate: String can be one of "vertical" "diaganol" or "horizontal"
x_labels.set_rotate('vertical')

# Add the X Axis Labels to the X Axis
x = XAxis.new
x.set_labels(x_labels)

y = YAxis.new
y.set_range(0,40000000,2000000)

x_legend = XLegend.new("Time")

x_legend.set_style('{font-size: 20px; color: #778877}')

y_legend = YLegend.new("Amount")
y_legend.set_style('{font-size: 20px; color: #770077}')

chart =OpenFlashChart.new
chart.set_title(title)
chart.set_x_legend(x_legend)
chart.set_y_legend(y_legend)
chart.x_axis = x
chart.y_axis = y

chart.add_element(bar)
chart.add_element(bar2)

render :text => chart.to_s
end


end

(2) ビューの修正


/app/views/bar_graph.html.erb
<script type="text/javascript" src="/javascripts/swfobject.js"></script><%= @graph %>

(3) 動作確認
ブラウザからhttp://127.0.0.1:3000/graph/bar_graphで起動します。
このURLにより設定したルーティングに従って{:controller=>'sales', :action=>'bar_graph'}が起動されます。
(棒グラフ)



2.Open Flash Chart 2の文法
2-1.JSON
Open Flash ChartはJSONジェイソン(JavaScript Object Notation)形式で記述されたグラフデータをJavaScriptが読み込みグラフ描画しています。
(1) データ型

データ型
数値(整数、浮動小数点数555, 1234.56
文字列(ダブルコーテーションで囲む)"one"
真偽値true, false
配列["one", "two", "three"]
ハッシュ(キーは文字列のみ){"code":"A001", "name":"Apple", "price":250}
nullnull

(2) グラフデータの構造
まず具体例として公式ページhttp://teethgrinder.co.uk/open-flash-chart-2/より抜粋したものを提示します。
新らたに出現したキーについてはコメントを入れました。


data.json
{
"title":{
"text": "Many data lines",
"style": "{font-size: 20px; color:#0000ff; font-family: Verdana; text-align: center;}"
},

"y_legend":{
"text": "Open Flash Chart",
"style": "{color: #736AFF; font-size: 12px;}"
},

"elements":[
{
"type": "bar", # "bar", "bar_glass", "bar_3d",...
"alpha": 0.5, # 透明度 0=>完全透明,1=>完全不透明
"colour": "#9933CC",
"text": "Page views",
"font-size": 10,
"values" : [9,6,7,9,5,7,6,9,7]
},
{
"type": "bar",
"alpha": 0.5,
"colour": "#CC9933",
"text": "Page views 2",
"font-size": 10,
"values" : [6,7,9,5,7,6,9,7,3]
}
],

"x_axis":{
"stroke": 1, # x軸の幅
"tick_height": 10, # x軸メモリ線の長さ
"colour": "#d000d0",
"grid_colour": "#00ff00",
"labels": {
"labels": ["January","February","March","April","May","June","July","August","Spetember"]
}
},

"y_axis":{
"stroke": 4, # y軸の幅
"tick_length": 3, # y軸メモリ線の長さ
"colour": "#d000d0",
"grid_colour": "#00ff00",
"offset": 0, # true=>棒と棒の間隔の半分を起点とする
# false=>x軸のラインを起点とする
"max": 20
}
}

(3) 公式ドキュメンテーション
http://teethgrinder.co.uk/open-flash-chart-2/doxygen/html/index.htmlに全てが記されていますので、
こちらを参照することで細かな設定が可能になります。
例えば、棒グラフは次のような種類が用意されています。
bar
bar_3d
bar_cylinder
bar_dome
bar_glass
bar_round
bar_round3d
bar_round_glass (公式ページではbar_rounded_glassとなっているがエラーします)
bar_sketch

(4) 詳細な設定
棒のひとつだけ色を変えてみましょう。


/app/controllers/sales_controller.rb
class SalesController < ApplicationController

def test5_code
title = Title.new("Bar Chart")
bar = Bar.new
bar.type = "bar"
bar.alpha = 0.5


vals =[1,2,3,4]
tmp = BarValue.new(5) # 5番目のデータは細かな設定
tmp.set_colour("#ff0000")
vals << tmp
vals << [6,7,8,9]
vals = vals.flatten # 配列を平滑化
bar.values = vals

x = XAxis.new
x.stroke = 1
x.tick_height = 10
x.offset = true
x.set_labels(['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'])

y = YAxis.new
y.stroke = 1
y.tick_length = 10

chart = OpenFlashChart.new
chart.set_title(title)
chart.x_axis = x
chart.y_axis = y
chart.add_element(bar)
render :text => chart.to_s
end


end

(5) 動作確認
ブラウザからhttp://127.0.0.1:3000/graph/test_graph/5で起動します。



ディレクトリとファイルの操作 | index | REMXL

ディレクトリとファイルの操作

[14]ディレクトリとファイルの操作
1.ディレクトリとファイルの操作
Ruby にはDir、File、FileUtilsというディレクトリやファイルを操作する組み込みライブラリが用意されています。ここでは、その使い方を紹介します。なお、FileUtilsを利用する場合は、Ruby on Railsでは明示的なrequireは必要としませんが、Rubyではrequireが必要となります。

1-1.文字コード変換
Ruby on Railsと外部OSとのやり取りをする場合は、文字コードに注意しなければなりません。Ruby on Railsの世界ではUTF-8が使用されていますか゛、外部では異なるコード体系で動作していることが多くあります。そのため文字コード変換のライブラリが標準で用意されています。

(1) Kconv


require 'kconv'

filenames = Dir.glob('*') # 全てのファイル名をシフトJISコードで取得

filenames.each do |f|
p "****"
p f # ShiftJISのまま表示
p f.kconv(Kconv::UTF8, Kconv::SJIS) # ShiftJIS から UTF-8 に変換し表示
end

上記の例としてファイル名が”あいうえお.txt”であるとき
f => \202\240 \202\242 \202\244 \202\246 \202\250.txt
f.kconv => \343\201\202 \343\201\204 \343\201\206 \343\201\210 \343\201\212.txt
となります。

16進表現では
f => x82A0 x82A2 x82A4 x82A6 x82A8.txt
f.kconv => xE38182 xE38184 xE38186 xE38188 xE3818A.txt
です。

Kconvを利用するときは文字コードは次の定数で指定します。

定数文字コード
JISISO-2022-JP
EUCEUC-JP
SJISShift_JIS
BINARYバイナリ
ASCIIASCII
UTF8UTF-8
UTF16UTF-16

1-2.バックスラッシュ記法
プログラム内部では”あ い う え お”を”\202\240 \202\242 \202\244 \202\246 \202\250”のように文字そのものではなくコードで表現する場合があります。この表現方法の一つにバックスラッシュ記法があります。

バックスラッシュ記法意味
\tタブ(0x09)
\n改行(0x0a)
\rキャリッジリターン(0x0d)
\f改ページ(0x0c)
\bバックスペース (0x08)
\aベル (0x07)
\eエスケープ (0x1b)
\s空白 (0x20)
\nnn8 進数表記 (n は 0-7)
\xnn16 進数表記 (n は 0-9,a-f)
\cx\C-xコントロール文字 (x は ASCII 文字)
\M-xメタ x (c | 0x80)
\M-\C-xメタ コントロール x
\x文字 x そのもの

1-3.カレントディレクト
プログラムを起動したときカレントディレクトリは実行しているプロジェクトのディリクトリにあり、Ruby on RailsではRAILS_ROOTにパスが入っています。

1-4.プロジェクトの生成
(1) プロジェクトAppli022を生成する
(2) 日本語環境の設定
(3) データベースの作成

1-5.ディレクトリ操作のプログラム作成
(1) コントローラの生成
NetBeansで[生成..]を選択します。
    ジェネータ(G): controller
    名前(N): commands
    ビュー(V): index


実行結果
exists app/controllers/
exists app/helpers/
create app/views/commands
exists test/functional/
create test/unit/helpers/
create app/controllers/commands_controller.rb
create test/functional/commands_controller_test.rb
create app/helpers/commands_helper.rb
create test/unit/helpers/commands_helper_test.rb
create app/views/commands/index.html.erb

(2) コントローラの編集
Ajaxを利用し、ファイル操作の結果を同一画面に表示させながら進行するプログラムとしましょう。


/app/controllers/commands_controller.rb
class CommandsController < ApplicationController
def index
end

def operate_dir
filenames = Dir.glob('*') # 全てのファイル名を取得
@result="<br>" + File::expand_path('.') + ">dir <br>"
filenames.each do |f|
fn = f.kconv(Kconv::UTF8, Kconv::SJIS) # ShiftJIS から UTF-8 に変換し表示
@result = @result + fn + "<br>"
end
end

def operate_chdir
Dir::chdir(@strarray[1]) # カレントディレクトリの変更
@result="<br>" + File::expand_path('.') + ">chdir #{@strarray[1]} <br>"
end

def operate_mkdir
Dir::mkdir(@strarray[1]) unless File::exist?(@strarray[1]) # ディレクトリの作成
@result="<br>" + File::expand_path('.') + ">mkdir #{@strarray[1]} <br>"
end

def operate_rmdir
Dir::delete(@strarray[1]) # ディレクトリの削除(但し空であること)
@result="<br>" + File::expand_path('.') + ">rmdir #{@strarray[1]} <br>"
end

def operate_rename
FileUtils::mv(@strarray[1], @strarray[2]) # ファイル名やディレクトリ名の変更
@result="<br>" + File::expand_path('.') + ">rename #{@strarray[1]} #{@strarray[2]} <br>"
end

def operate
str=params[:commandarea][:commandline]
@strarray=str.split("\040", 3) # 最初の空白で文字列を分割し配列に格納
case @strarray[0]
def operate
when "dir"
operate_dir
when "chdir"
operate_chdir
when "mkdir"
operate_mkdir
when "rmdir"
operate_rmdir
when "rename"
operate_rename
else
@result="#{@strarray[0]} <br> command error <br>"
end
render :partial => "resultarea"
end

end

(3) レイアウトファイルの作成
Ajaxを利用するため、基本的なレイアウトファイルを作成します。


/app/views/layouts/commands.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Appli022: <%= controller.action_name %></title>
<%= javascript_include_tag :defaults %>
</head>
<body><%= yield %>

</body>
</html>

ここでRuby on Railsではjavascript_include_tag :defaultsと書いていますが、これは次のように展開されます。

<script src="/javascripts/prototype.js" type="text/javascript"></script>
<script src="/javascripts/effects.js" type="text/javascript"><

/app/views/commands/index.html.erb
<h1>ディレクトリとファイルの操作</h1><% form_remote_tag :update => "resultarea",
:position => "top",
:url => {:action => "operate"} do -%>
Command: <%= text_field :commandarea, :commandline, :size => 80 %><% end -%>
<br/>

<div id="resultarea"></div>


/app/views/commands/_resultarea.html.erb

<%= "#{@result}" %>

1-6.動作確認
(1) 実装されたコマンドの種類

<
Command内容
dirカレントディレクトリ直下のディレクトリ名およびファイメ名の取得
chdirカレントディレクトリの変更
mkdirディレクトリの新規作成
rmdirデイレクトリの削除(但しディレクトリ直下は空であること)
renameディレクトリ名の変更

(2) 動作確認

1-7.ファイル操作のプログラム作成
(1) ディレクトリの操作プログラムの機能追加


/app/controllers/commands_controller.rb
class CommandsController < ApplicationController
def index
end

def operate_dir
filenames = Dir.glob('*') # 全てのファイル名を取得
@result="<br>" + File::expand_path('.') + ">dir <br>"
filenames.each do |f|
fn = f.kconv(Kconv::UTF8, Kconv::SJIS) # ShiftJIS から UTF-8 に変換し表示
@result = @result + fn + "<br>"
end
end

def operate_chdir
Dir::chdir(@strarray[1]) # カレントディレクトリの変更
@result="<br>" + File::expand_path('.') + ">chdir #{@strarray[1]} <br>"
end

def operate_mkdir
Dir::mkdir(@strarray[1]) unless File::exist?(@strarray[1]) # ディレクトリの作成
@result="<br>" + File::expand_path('.') + ">mkdir #{@strarray[1]} <br>"
end

def operate_rmdir
Dir::delete(@strarray[1]) # ディレクトリの削除(但し空であること)
@result="<br>" + File::expand_path('.') + ">rmdir #{@strarray[1]} <br>"
end

def operate_rename
FileUtils::mv(@strarray[1], @strarray[2]) # ファイル名やディレクトリ名の変更
@result="<br>" + File::expand_path('.') + ">rename #{@strarray[1]} #{@strarray[2]} <br>"
end

def operate_copy
FileUtils::cp(@strarray[1], @strarray[2]) # ファイルのコピー
@result="<br>" + File::expand_path('.') + ">copy #{@strarray[1]} #{@strarray[2]} <br>"
end

def operate_read
@result="<br>" + File::expand_path('.') + ">read #{@strarray[1]} <br>"
File::open(@strarray[1], "r") do |f| # ファイルの読み込み
while str=f.gets
@result += str + "<br>"
end
end
end

def operate_clearlog
@result="<br>" + File::expand_path('.') + ">clearlog <br>"
File::open(RAILS_ROOT + "/appli022_log.txt", "w+") do |f| # Logファイルの初期化
f.print "appli022_log.txt \n"
end
end

def operate_printlog
@result="<br>" + File::expand_path('.') + ">printlog <br>"
@result += "Begin VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV <br>"
File::open(RAILS_ROOT + "/appli022_log.txt", "r") do |f| # Logファイルの読み込み
while str=f.gets
@result += str + "<br>"
end
end
@result += "End VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV <br>"
end

def operate
str=params[:commandarea][:commandline]
@strarray=str.split("\040", 3) # 最初の空白で文字列を分割し配列に格納
case @strarray[0]
when "dir"
operate_dir
when "chdir"
operate_chdir
when "mkdir"
operate_mkdir
when "rmdir"
operate_rmdir
when "rename"
operate_rename
when "copy"
operate_copy
when "read"
operate_read
when "clearlog"
operate_clearlog
when "printlog"
operate_printlog
else
@result="#{@strarray[0]} <br> command error <br>"
end
File::open(RAILS_ROOT + "/appli022_log.txt", "a+") do |f| # Logファイルの追記型オープン
f.print @result, "\n"
end
render :partial => "resultarea"
end

end

1-8.動作確認
(1) 新たに実装されたコマンドの種類

Command内容
renameファイル名の変更
copyファイルのコピー

(ファイル名) → (ファイル名)

(ファイル名) → (フォルダ名)
readテキストファイルの読み込み
clearlogログファイルの初期化
printlogログのプリントアウト

(2) 動作確認



ProtoThickBox | index | OpenFlashChart

ProtoThickBox

[13]ProtoThickBox
1.ProtoThickBox
画像をブラウザ上で効果的に見せるThickBoxというライブラリを紹介します。

1-1.プロジェクトの生成
(1) プロジェクトAppli020を生成する
(2) 日本語環境の設定
(3) データベースの作成

1-2.protothickboxのインストール
(1) protothickboxのダウンロード
http://labs.spookies.co.jp/2007/12/26/protothickbox-js-3-1-release/より【downloadはこちら】を選択し、protothickbox-js-3.1.4.zipをダウンロードします。


(2) protothinkbox.jsのコピー
ダウンロードしたファイルを展開し
javascriptsフォルダにあるprotothinkbox.jsを/public/javascriptsにコピーします。

(3) http://jquery.com/demo/thinkbox/より2ファイルをダウンロード


(4) ThickBox.css、loadingAnimation.gifのコピー
ダウンロードしたThickBox.cssを/public/stylesheetsにコピーします。
またダウンロードしたloadingAnimation.gifは/public/imagesにコピーします。

(5) ライブラリの修正


/public/javascripts/protorhinkbox.js
/*
* Thickbox 3.1 - One Box To Rule Them All.
* By Cody Lindley (http://www.codylindley.com)
* Copyright (c) 2007 cody lindley
* Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
*
* Protothickbox 3.1.4
* Modified By Spookies Labs(http://labs.spookies.jp)
* depends on prototype.js 1.6 or later + effects.js
*/
var tb_pathToImage = "/images/loadingAnimation.gif";
  :
  :

1-3.モデルの作成
(1) モデルの生成
NetBeansで生成を選択します。
    ジェネレータ(G): model
    引数(A): Gallery


実行結果
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/gallery.rb
create test/unit/gallery_test.rb
create test/fixtures/galleries.yml
create db/migrate
create db/migrate/20100218051321_create_galleries.rb

(2) マイグレーションのプログラム修正


/db/migrate/20100218051321_create_galleries.rb
class CreateGalleries < ActiveRecord::Migration
def self.up
create_table :galleries do |t|
t.string :title
t.string :filename
t.string :content_type
t.integer :size
t.timestamps
end
end

def self.down
drop_table :galleries
end
end

(3) マイグレーションの実行
NetBeansで[データベースマイグレーション]→[現在のバージョンへ]を選択します。


実行結果
(in D:/Rails_Projects/Appli020)
== CreateGalleries: migrating ================================================
-- create_table(:galleries)
-> 0.1250s
== CreateGalleries: migrated (0.1250s) =======================================

(4) モデルの編集


/app/models/gallery.rb
class Gallery < ActiveRecord::Base
MAX_FILE_SIZE = 1.megabyte

validates_presence_of :filename, :message => 'Please choose a file.'
validates_inclusion_of :size, :in => (1..MAX_FILE_SIZE),
:message => "File size is too big or 0. Maximum size is #{MAX_FILE_SIZE} bytes."

def file=(file)
self.filename = file.original_filename if file.respond_to?(:original_filename)
self.content_type = file.content_type if file.respond_to?(:content_type)
self.size = file.size if file.respond_to?(:size)
@tmp = file
end

def after_save
File.open(filepath, "wb") { |f|
f.write @tmp.read
}
end

def after_destroy
File.delete filepath if File.exist? filepath
end

def filepath
"public/galleries/#{self.id}_#{self.filename}"
end
end

1-4.コントローラの作成
(1) コントローラの生成
NetBeansで[生成]を選択します。
    ジェネレータ(G): controller
    名前(N): galleries
    ビュー(V): index, new, create, destroy


実行結果
exists app/controllers/
exists app/helpers/
create app/views/galleries
exists test/functional/
create test/unit/helpers/
create app/controllers/galleries_controller.rb
create test/functional/galleries_controller_test.rb
create app/helpers/galleries_helper.rb
create test/unit/helpers/galleries_helper_test.rb
create app/views/galleries/index.html.erb
create app/views/galleries/new.html.erb
create app/views/galleries/create.html.erb
create app/views/galleries/destroy.html.erb

(2) コントローラの編集


/app/controllers/galleries_controller.rb
class GalleriesController < ApplicationController
def index
@folders = Folder.find(:all)
end

def new
end

def create
@gallery = Gallery.new(params[:upload])
if @gallery.valid? then
@gallery.save
redirect_to :action => 'index'
end
end

def destroy
@gallery = Gallery.find(params[:id])
@gallery.destroy
redirect_to :action => 'index'
end
end

1-5.ビューの編集
(1) index.html.erb


/app/views/galleries/index.html.erb
<h1>Index</h1>
<table><% i=0 -%><% @galleries.each do |gallery| -%><% i+=1 -%><% i=1 if i>5 -%><% if i==1 then -%>
<tr><% end -%>
<td>
<img src=<%=h "galleries/#{gallery.id}_#{gallery.filename}" -%> width=100><br/>
<%= link_to('[D]',
{:action => 'destroy',
:id => gallery.id}) -%>
<%=h "#{gallery.title}" -%>
</td><% if i==5 then -%>
</tr><% end -%><% end -%><% if i==0 then -%>
<tr><% end -%><% if i<5 then -%>
</tr><% end -%>
</table><%= link_to('new', {:action => 'new'}) -%>


(2) new.html.erb


/app/views/galleries/new.html.erb
<h1>New</h1><% form_tag({:action => 'create'}, :multipart => true) do %>
Title:<%= text_field('upload', 'title') %><br/>
<br/>
File: <%= file_field('upload', 'file') %><br/>
<br/>
<%= submit_tag('upload') %><br/><% end %>
<br/><%= link_to('index', {:action => 'index'}) %>

(3) create.html.erb


/app/views/galleries/create.html.erb
<h1>Create</h1><%= error_messages_for :gallery %><%= link_to('index', {:action => 'index'}) %>

(4) 不用なビュープログラムの削除
/app/views/galleries/destroy.html.erb

(5) レイアウトファイルの作成
HTMLのヘッダー部分など各ページ共通に利用される表示要素を作成します。
今回はprotothickboxも使用するための準備もします。


/app/views/layouts/galleries.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Appli020: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'thickbox' %>
<%= javascript_include_tag :defaults %>
<%= javascript_include_tag 'protothickbox' %>
</head>
<body><%= yield %>

</body>
</html>

1-6.ファイル格納先の作成
(1) galleriesディレクトリーの作成
/public/の直下にgalleriesディレクトリーを作ります。
公開ディレクトリー上で右クリックして[新規]→[フォルダ...]を選択し、フォルダ名(N):にgalleriesを設定します。

(2) ファイルの格納先
/public/galleries/[id]_[original_filename]

1-7.動作確認
http://127.0.0.1:3000/galleries/を起動し動作を確認します。

1-8.thickboxへの対応
(1) index.html.erb


/app/views/galleries/index.html.erb
<h1>Index</h1>
<table><% i=0 -%><% @galleries.each do |gallery| -%><% i+=1 -%><% i=1 if i>5 -%><% if i==1 then -%>
<tr><% end -%>
<td>
<% fn = "../galleries/#{gallery.id}_#{gallery.filename}" -%>
<%= link_to(image_tag(fn, :width=>"100", :border=>'0'),
fn,
:class=> 'thickbox',
:title=> gallery.title) -%><br/>

<%= link_to('[D]',
{:action => 'destroy', :id => gallery.id}) -%>
<%=h "#{gallery.title}" -%>
</td><% if i==5 then -%>
</tr><% end -%><% end -%><% if i==0 then -%>
<tr><% end -%><% if i<5 then -%>
</tr><% end -%>
</table><%= link_to('new', {:action => 'new'}) -%>

1-9.動作確認
画像の上でマウスクリックします。



ファイルのアップロードとダウンロード | index | ディレクトリとファイルの操作

ファイルのアップロードとダウンロード

[12]ファイルのアップロードとダウンロード
1.ファイルのアップロードとダウンロード
Windows環境でのファイルのアップロードやダウンロードを行うプログラムを紹介します。
1-1.プロジェクトの生成
(1) プロジェクトAppli018を生成する
(2) 日本語環境の設定
(3) データベースの作成

1-2.モデルの作成
(1) モデルの生成
NetBeansで生成を選択します。
    ジェネレータ(G): model
    引数(A): Folder


実行結果
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/folder.rb
create test/unit/folder_test.rb
create test/fixtures/folders.yml
create db/migrate
create db/migrate/20100217040348_create_folders.rb

(2) マイグレーションのプログラム修正


/db/migrate/20100217040348_create_folders.rb
class CreateFolders < ActiveRecord::Migration
def self.up
create_table :folders do |t|
t.string :filename
t.string :content_type
t.integer :size

t.timestamps
end
end

def self.down
drop_table :folders
end
end

(3) マイグレーションの実行
NetBeansで[データベースマイグレーション]→[現在のバージョンへ]を選択します。


実行結果
(in D:/Rails_Projects/Appli018)
== CreateFolders: migrating ==================================================
-- create_table(:folders)
-> 0.1100s
== CreateFolders: migrated (0.1100s) =========================================

(4) モデルの編集


/app/models/folder.rb
class Folder < ActiveRecord::Base
MAX_FILE_SIZE = 1.megabyte

validates_presence_of :filename, :message => 'Please choose a file.'
validates_inclusion_of :size, :in => (1..MAX_FILE_SIZE),
:message => "File size is too big or 0. Maximum size is #{MAX_FILE_SIZE} bytes."

def file=(file)
self.filename = file.original_filename if file.respond_to?(:original_filename)
self.content_type = file.content_type if file.respond_to?(:content_type)
self.size = file.size if file.respond_to?(:size)
@tmp = file
end

def after_save
File.open(filepath, "wb") { |f|
f.write @tmp.read
}
end

def after_destroy
File.delete filepath if File.exist? filepath
end

def filepath
"public/files/#{self.id}_#{self.filename}"
end
end

1-3.コントローラの作成
(1) コントローラの生成
NetBeansで[生成]を選択します。
    ジェネレータ(G): controller
    名前(N): folders
    ビュー(V): index, new, create, destroy, download


実行結果
exists app/controllers/
exists app/helpers/
create app/views/folder
exists test/functional/
create test/unit/helpers/
create app/controllers/folders_controller.rb
create test/functional/folders_controller_test.rb
create app/helpers/folders_helper.rb
create test/unit/helpers/folders_helper_test.rb
create app/views/folders/index.html.erb
create app/views/folders/new.html.erb
create app/views/folders/create.html.erb
create app/views/folders/destroy.html.erb
create app/views/folders/download.html.erb

(2) コントローラの編集


/app/controllers/folders_controller.rb
class FoldersController < ApplicationController
def index
@folders = Folder.find(:all)
end

def new
end

def create
@folder = Folder.new(params[:upload])
if @folder.valid? then
@folder.save
redirect_to :action => 'index'
end
end

def destroy
@folder = Folder.find(params[:id])
@folder.destroy
redirect_to :action => 'index'
end

def download
@folder = Folder.find(params[:id])
send_file(@folder.filepath,
{:filename => @folder.filename,
:type => @folder.content_type})
end
end

1-4.ビューの編集
(1) index.html.erb


/app/views/folders/index.html.erb
<h1>Index</h1>
<table>
<tr>
<th>filename</th>
<th>content_type</th>
<th>size</th>
<th>action</th>
</tr><% @folders.each do |folder| %>
<tr>
<td><%= link_to(h(folder.filename),
{:action => 'download',
:id => folder.id}) %>
</td>
<td><%= h(folder.content_type) %></td>
<td><%= h(folder.size) %></td>
<td>
<%= link_to('[destroy]',
{:action => 'destroy',
:id => folder.id}) %>
</td>
</tr><% end %>
</table><%= link_to('new', {:action => 'new'}) %>

(2) new.html.erb


/app/views/folders/new.html.erb
<h1>New</h1><% form_tag({:action => 'create'}, :multipart => true) do %>
<%= file_field('upload', 'file') %>
<%= submit_tag('upload') %><% end %><%= link_to('index', {:action => 'index'}) %>

(3) create.html.erb


/app/views/folders/create.html.erb
<h1>Create</h1><%= error_messages_for :folder %><%= link_to('index', {:action => 'index'}) %>

(4) 不用なビュープログラムの削除
/app/views/folders/destroy.html.erb
/app/views/folders/download.html.erb

(5) レイアウトファイルの作成
HTMLのヘッダー部分など各ページ共通に利用される表示要素を作成します。


/app/views/layouts/folders.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Appli018: <%= controller.action_name %></title>
</head>
<body><%= yield %>

</body>
</html>

1-5.ファイルの格納先の作成
/public/の直下にfilesディレクトリーを作ります。

(1) filesディレクトリーの作成
公開ディレクトリー上で右クリックして[新規]→[フォルダ...]を選択します。

(2) フォルダ名(N):をfilesに設定

(3) ファイルの格納先
/public/files/[id]_[original_filename]

1-6.動作確認
http://127,0,0,1:3000/folders/で起動します。

1-7.表示の改善
(1) 数値のカンマ編集
サイズの表示方法をカンマ編集し見やすくしましょう。


/app/views/folders/index.html.erb
<h1>Index</h1>
<table>
<tr>
<th>filename</th>
<th>content_type</th>
<th>size</th>
<th>action</th>
</tr><% @folders.each do |folder| %>
<tr>
<td><%= link_to(h(folder.filename),
{:action => 'download',
:id => folder.id}) %>
</td>
<td><%= h(folder.content_type) %></td>
<td align="right"><%= folder.size.to_s.reverse.gsub( /(\d{3})(?=\d)/, '\1,' ).reverse %></td>
<td>
<%= link_to('[destroy]',
{:action => 'destroy',
:id => folder.id}) %>
</td>
</tr><% end %>
</table><%= link_to('new', {:action => 'new'}) %>

(2) 動作確認

(3) 漢字を含むファイル名をアップロードするときの不具合を修正
文字コードWindowsRuby on Railsでは異なるため、漢字を含むファイル名のときはファイル名称が正しく伝わりません。
例えばUTF8コードで、”すいれん_Water lilies.jpg”のファイルをそのままWindowsに渡すと”縺吶>繧後s_Water lilies.jpg”となってしまいます。
そこでRuby on Rails からWindowsOSへファイルを渡すときに文字コードをutf8からshiftjisにコンバージョンするロジックを組み込みます。


/app/models/folder.rb
class Attachment < ActiveRecord::Base
MAX_FILE_SIZE = 1.megabyte

validates_presence_of :filename, :message => 'Please choose a file.'
validates_inclusion_of :size, :in => (1..MAX_FILE_SIZE),
:message => "File size is too big or 0. Maximum size is #{MAX_FILE_SIZE} bytes."

def file=(file)
self.filename = file.original_filename if file.respond_to?(:original_filename)
self.content_type = file.content_type if file.respond_to?(:content_type)
self.size = file.size if file.respond_to?(:size)
@tmp = file
end

def after_save
File.open(filepath, "wb") { |f|
f.write @tmp.read
}
end

def after_destroy
File.delete filepath if File.exist? filepath
end

def filepath
str=self.filename
str_shiftjis = str.kconv(Kconv::SJIS, Kconv::UTF8) #UTF8 から Shift_JIS に変換
"public/files/#{self.id}_#{str_shiftjis}"

end
end

(4) 漢字を含むファイル名をダウンロードするときの不具合を修正
同様にダウンロードのときもRuby on RailsからWindowsにファイルを渡すとき、漢字を含むファイル名は正しく伝わりません。

そこで文字コードをutf8からshiftjisにコンバージョンするロジックを組み込みます。


/app/models/folder.rb
class FoldersController < ApplicationController


def download
@folder = Folder.find(params[:id])
str=@folder.filename
str_shiftjis = str.kconv(Kconv::SJIS, Kconv::UTF8) # UTF8 から Shift_JIS に変換
send_file(@folder.filepath,
{:filename => str_shiftjis,
:type => @folder.content_type})

end
end
これでファイル名はWindowsへも正しく引き継がれます。

(5) 文字コード関係のまとめ
アップロードおよびダウンロードにおける文字コードの推移については次の図が理解しやすいでしょう。



FileColumn | index | ProtoThinkBox

FileColumn

[11]FileColumn


1.FileColumn
データファイルや画像ファイルなどファイルの扱いがWeb上で簡単にできるFileColumnを紹介します。

1-1.プロジェクトの生成
(1) プロジェクトAppli016を生成する
(2) 日本語環境の設定
(3) データベースの作成

1-2.file_columnのインストール
(1) プラグインの導入


コマンド プロンプト
D:\Rails_Projects\Appli016>
ruby script/plugin install &3104;ttp://filecolumn.googlecode.com/svn/tags/file_column
./CHANGELOG
./README
./Rakefile
./TODO
./init.rb
./lib/file_column.rb
./lib/file_column_helper.rb
./lib/file_compat.rb
./lib/magick_file_column.rb
./lib/rails_file_column.rb
./lib/test_case.rb
./lib/validations.rb
./test/abstract_unit.rb
./test/connection.rb
./test/file_column_helper_test.rb
./test/file_column_test.rb
./test/fixtures/entry.rb
./test/fixtures/invalid-image.jpg
./test/fixtures/kerb.jpg
./test/fixtures/mysql.sql
./test/fixtures/schema.rb
./test/fixtures/skanthak.png
./test/magick_test.rb
./test/magick_view_only_test.rb

(2) file_columnプラグインの修正
このまま利用すると、実行時にエラーをするため、一部プログラムを修正します。


/vender/plugins/file_column/lib/file_column.rb
require 'fileutils'
require 'tempfile'
require 'magick_file_column'

module FileColumn # :nodoc:


def file_column(attr, options={})
options = DEFAULT_OPTIONS.merge(options) if options

my_options = FileColumn::init_options(options,
self.name.to_s.underscore,
attr.to_s) :

end


end

1-3.アプリケーションの作成
(1) scaffoldの利用
NetBeansで[生成..]を選択します。
    ジェネレータ(G): scaffold
    モデル(N):Address
    属性ペア(フィールド型)(A): namae:string yubin:string jusho:string denwa:string


コマンド プロンプト
exists app/models/
exists app/controllers/
exists app/helpers/
create app/views/addresses
exists app/views/layouts/
exists test/functional/
exists test/unit/
create test/unit/helpers/
exists public/stylesheets/
create app/views/addresses/index.html.erb
create app/views/addresses/show.html.erb
create app/views/addresses/new.html.erb
create app/views/addresses/edit.html.erb
create app/views/layouts/addresses.html.erb
create public/stylesheets/scaffold.css
create app/controllers/addresses_controller.rb
create test/functional/addresses_controller_test.rb
create app/helpers/addresses_helper.rb
create test/unit/helpers/addresses_helper_test.rb
route map.resources :addresses
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/address.rb
create test/unit/address_test.rb
create test/fixtures/addresses.yml
create db/migrate
create db/migrate/20100216023604_create_addresses.rb

(2) 項目の追加
NetBeansで[生成..]を選択する
    ジェネレータ(G):migration
    引数(A):add_image_to_addresses image:string


コマンド プロンプト
exists db/migrate
create db/migrate/20100216023855_add_image_to_addresses.rb

(3) マイグレーションの確認


/db/migrate/20100216023855_add_image_to_addresses.rb
class AddImageToAddresses < ActiveRecord::Migration
def self.up
add_column :addresses, :image, :string
end

def self.down
remove_column :addresses, :image
end
end

(4) マイグレーションの実行
NetBeansで[データベースマイグレーション]→[現在のバージョンへ]を選択する


コマンド プロンプト
(in D:/Rails_Projects/Appli016)
== CreateAddresses: migrating ================================================
-- create_table(:addresses)
-> 0.1250s
== CreateAddresses: migrated (0.1250s) =======================================

== AddImageToAddresses: migrating ============================================
-- add_column(:addresses, :image, :string)
-> 0.2650s
== AddImageToAddresses: migrated (0.2650s) ===================================

(5) モデルの修正


/app/models/address.rb
class Address < ActiveRecord::Base

file_column :image

end

(6) ビューの修正


/app/views/index.html.erb
<h1>Listing addresses</h1>

<table>
<tr>
<th>Namae</th>
<th>Yubin</th>
<th>Jusho</th>
<th>Denwa</th>
<th>Image</th>
</tr><% @addresses.each do |address| %>
<tr>
<td><%=h address.namae %></td>
<td><%=h address.yubin %></td>
<td><%=h address.jusho %></td>
<td><%=h address.denwa %></td>
<td><%=h address.image %></td>
<td><%= link_to 'Show', address %></td>
<td><%= link_to 'Edit', edit_address_path(address) %></td>
<td><%= link_to 'Destroy', address, :confirm => 'Are you sure?', :method => :delete %></td>
</tr><% en %>
</table>

<br/><%= link_to 'New address', new_address_path %>




/app/views/new.html.erb
<h1>New address</h1>

<% form_for(@address, :html => {:multipart => true}) do |f| %>
<%= f.error_messages %>

<p>
<%= f.label :namae %><br/>
<%= f.text_field :namae %>
</p>
<p>
<%= f.label :yubin %><br/>
<%= f.text_field :yubin %>
</p>
<p>
<%= f.label :jusho %><br/>
<%= f.text_field :jusho %>
</p>
<p>
<%= f.label :denwa %><br/>
<%= f.text_field :denwa %>
</p>
<p>
<%= f.label :image %><br/>
<%= f.file_field :image %>
</p>

<p>
<%= f.submit 'Create' %>
</p><% end %><%= link_to 'Back', addresses_path %>




/app/views/edit.html.erb
<h1>Editing address</h1>

<% form_for(@address, :html => {:multipart => true}) do |f| %>
<%= f.error_messages %>

<p>
<%= f.label :namae %><br/>
<%= f.text_field :namae %>
</p>
<p>
<%= f.label :yubin %><br/>
<%= f.text_field :yubin %>
</p>

<p>
<%= f.label :jusho %><br/>
<%= f.text_field :jusho %>
</p>
<p>
<%= f.label :denwa %><br/>
<%= f.text_field :denwa %>
</p>
<p>
<%= f.label :image %><br/>
<%= f.file_field :image %>
</p>

<p>
<%= f.submit 'Update' %>
</p><% end %><%= link_to 'Show', @address %> |<%= link_to 'Back', addresses_path %>




/app/views/show.html.erb
<p>
<b>Namae:</b>
<%=h @address.namae %>
</p>

<p>
<b>Yubin:</b>
<%=h @address.yubin %>
</p>

<p>
<b>Jusho:</b>
<%=h @address.jusho %>
</p>

<p>
<b>Denwa:</b>
<%=h @address.denwa %>
</p>

<p>
<b>Image:</b>
<%=h @address.image %>
</p>

<%= link_to 'Edit', edit_address_path(@address) %> |<%= link_to 'Back', addresses_path %>

(7) 動作確認
実際にプログラムを実行してみると、ファイル名が英字の場合はうまくアップロードされますが、漢字の場合うまくいきません。
・(アップロードするファイル名が「冬景色_Winter.jpg」の場合)

・(アップロードされたファイル名が「_______Winter.jpg」となってしまう)

(8) file_columnプラグインプログラムの修正
日本語のファイル名も使用できるようにするために、ふたたびfile_columnを修正します。


/vender/plugins/file_column/lib/file_column.rb
require 'fileutils'
require 'tempfile'
require 'magick_file_column'

module FileColumn # :nodoc:



def self.sanitize_filename(filename)

filename = File.basename(filename.gsub("\\", "/")) # work-around for IE
filename.gsub!(/[^\w\.\-\+_]/,"_")
filename = "_#{filename}" if filename =~ /^\.+$/
filename = "unnamed" if filename.size == 0
filename

end

end

(9) 動作確認
これで日本語のファイル名も扱うことができます。
・(アップロードするファイル名が「日の入り_Sunset.jpg」の場合)

・(アップロードされたファイル名も「日の入り_Sunset.jpg」となる)

(10) 画像の表示
さらに画像についてはファイル名ではなく画像を表示させましょう。


/app/views/show.html.erb
<p>
<b>Namae:</b>
<%=h @address.namae %>
</p>

<p>
<b>Yubin:</b>
<%=h @address.yubin %>
</p>

<p>
<b>Jusho:</b>
<%=h @address.jusho %>
</p>

<p>
<b>Denwa:</b>
<%=h @address.denwa %>
</p>

<p>
<b>Image:</b>
<%= image_tag url_for_file_column(@address, :image) %>
</p><%= link_to 'Edit', edit_address_path(@address) %> |<%= link_to 'Back', addresses_path %>

(実際に画像を表示した場合)

(11) 画像の拡大縮小


/app/views/show.html.erb
<p>
<b>Namae:</b>
<%=h @address.namae %>
</p>

<p>
<b>Yubin:</b>
<%=h @address.yubin %>
</p>

<p>
<b>Jusho:</b>
<%=h @address.jusho %>
</p>

<p>
<b>Denwa:</b>
<%=h @address.denwa %>
</p>

<p>
<b>Image:</b>
<%= image_tag url_for_file_column(@address, :image), :size=>"50x50" %>
</p><%= link_to 'Edit', edit_address_path(@address) %> |<%= link_to 'Back', addresses_path %>

なお、ここで:size=>"50x50"を:width=>"50"や:hight=>"50"と書くことができます。これにより横幅を揃えたり、高さを揃えたりします。

・(縮小された画像を表示)



ActiveResource | index | ファイルのアップロードとダウンロード

ActiveResource

[10]ActiveResource


1.ActiveResource
Ruby on Railsで扱うことのできるWebサービスプロトコールにはSOAPとRESTがあります。SORPはActiveWebServiceパッケージに含まれ、RESTはActiveResourceパッケージに含まれています。Ruby on Rails2.0以降はActiveResourceが標準装備となり、ActiveWebServiceは外出しとなりました。ここでは標準装備されたRESTを扱うこととします。
まず2 つのRailsアプリケーションを作成し、ActiveResourceを使って片方のアプリケーションから別のアプリケーションのリソースにアクセスしデータが授受できることを学びましょう。

なお、SOAPを扱う場合はgemで簡単に導入できます。


コマンド プロンプト

C:\Ruby>gem install actionwebservice

1-1.ActiveResourceの特徴
ActiveResourceRuby on Rails 2.0 から追加された機能で、Railsのインストールどきに一緒にインストールされます。Web上のRESTful APIActiveRecordのモデルと同じようなインターフェースで利用可能にする、いわばObject / RESTful APIマッパーです。とくに同じRailsアプリケーションで提供されるRESTful APIに最適化して設計されていて、Railsの作法に沿って作られたAPIであれば、僅か数行のコーディングで利用できます。その他の特徴は以下のとおりです。
    ・Rails上ではActiveRecord同様にデータモデルとして扱える。
    ・ActiveRecord と互換性の高いインターフェース。
    ・ActiveRecordのValidation エラーを取得可能。
    ・BASIC 認証を標準サポート。



2.バックエンドとなるアプリケーションの作成
2-1.プロジェクトの生成
(1) プロジェクトAppli012を生成する
(2) 日本語環境の設定
(3) データベースの作成

2-2.テーブル保守プログラムの作成
(1) scaffoldの利用
NetBeansで生成を選択
    ジェネレータ(G): scaffold
    モデル名(N): Bookmark
    属性ペア(フィールド型)(A): title:string url:string comment:text


実行結果
exists app/models/
exists app/controllers/
exists app/helpers/
create app/views/bookmarks
exists app/views/layouts/
exists test/functional/
exists test/unit/
create test/unit/helpers/
exists public/stylesheets/
create app/views/bookmarks/index.html.erb
create app/views/bookmarks/show.html.erb
create app/views/bookmarks/new.html.erb
create app/views/bookmarks/edit.html.erb
create app/views/layouts/bookmarks.html.erb
create public/stylesheets/scaffold.css
create app/controllers/bookmarks_controller.rb
create test/functional/bookmarks_controller_test.rb
create app/helpers/bookmarks_helper.rb
create test/unit/helpers/bookmarks_helper_test.rb
route map.resources :bookmarks
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/bookmark.rb
create test/unit/bookmark_test.rb
create test/fixtures/bookmarks.yml
create db/migrate
create db/migrate/20100210045330_create_bookmarks.rb

(2) マイグレーションの実行
NetBeansで[データベースマイグレーション]→[現在のバージョンへ]を選択します。


実行結果
(in D:/Rails_Projects/Appli012)
== CreateBookmarks: migrating ================================================
-- create_table(:bookmarks)
-> 0.1250s
== CreateBookmarks: migrated (0.1250s) =======================================



3.フロントエンドとなるアプリケーションの作成
3-1.プロジェクトの生成
(1) プロジェクトAppli014を生成する
(2) 日本語環境の設定
(3) データベースの作成

3-2.テーブル保守アプリケーションの作成
(1) scaffoldの利用
NetBeansで[生成..]を選択
    ジェネレータ(G): scaffold
    モデル名(N): Bookmark
    属性ペア(フィールド型)(A): title:string url:string comment:text


実行結果
exists app/models/
exists app/controllers/
exists app/helpers/
create app/views/bookmarks
exists app/views/layouts/
exists test/functional/
exists test/unit/
create test/unit/helpers/
exists public/stylesheets/
create app/views/bookmarks/index.html.erb
create app/views/bookmarks/show.html.erb
create app/views/bookmarks/new.html.erb
create app/views/bookmarks/edit.html.erb
create app/views/layouts/bookmarks.html.erb
create public/stylesheets/scaffold.css
create app/controllers/bookmarks_controller.rb
create test/functional/bookmarks_controller_test.rb
create app/helpers/bookmarks_helper.rb
create test/unit/helpers/bookmarks_helper_test.rb
route map.resources :bookmarks
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/bookmark.rb
create test/unit/bookmark_test.rb
create test/fixtures/bookmarks.yml
create db/migrate
create db/migrate/20100210051742_create_bookmarks.rb

(2) マイグレーションファイルの削除
frontendではDB は使わないので削除しておきます。

(3) モデルクラスの書き換え
基底クラスをActiveResource::Baseにします。これによって Bookmark クラスはActiveResource のモデルになり、 DB の代わりに self.site で指定されたサイトの Web API にアクセスして、データの取得・保存を行います。


/app/controllers/bookmark_controller.rb
class Bookmark < ActiveResource::Base
self.site = 'http://127.0.0.1:3000/'
self.user = 'root'
self.password = 'pwMySQL'

alias_method :new_record?, :new?
def initialize(attr={})
super({:title => nil, :url => nil, :comment => nil}.update(attr))
end
end

(4) コントローラの修正


/app/models/bookmark.rb
class BookmarksController < ApplicationController
# GET /bookmarks
# GET /bookmarks.xml
def index
@bookmarks = Bookmark.find(:all)

respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @bookmarks }
end
end
:
:
# GET /bookmarks/1/edit
def edit
@bookmark = Bookmark.find(params[:id])
end
:
:
# PUT /bookmarks/1
# PUT /bookmarks/1.xml
def update
@bookmark = Bookmark.find(params[:id])

respond_to do |format|
@bookmark.title = params[:bookmark][:title]
@bookmark.url = params[:bookmark][:url]
@bookmark.comment = params[:bookmark][:comment]
if @bookmark.save
flash[:notice] = 'Bookmark was successfully updated.'
format.html { redirect_to(@bookmark) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @bookmark.errors, :status => :unprocessable_entity }
end
end
end
:
:
end

(5) 背景色の変更
Appli012とAppli014を区別するため、表示画面の背景色を「白」から「青系」に変更します。


/public/stylesheets/scaffold.css
body { background-color: #8888ff; color: #333; }

body, p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}

pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
}

a { color: #000; }
a:visited { color: #666; }
a:hover { color: #fff; background-color:#000; }

.fieldWithErrors {
padding: 2px;
background-color: red;
display: table;
}

#errorExplanation {
width: 400px;
border: 2px solid red;
padding: 7px;
padding-bottom: 12px;
margin-bottom: 20px;
background-color: #f0f0f0;
}

#errorExplanation h2 {
text-align: left;
font-weight: bold;
padding: 5px 5px 5px 15px;
font-size: 12px;
margin: -7px;
background-color: #c00;
color: #fff;
}

#errorExplanation p {
color: #333;
margin-bottom: 0;
padding: 5px;
}

#errorExplanation ul li {
font-size: 12px;
list-style: square;
}



4.動作確認
(1) Appli012(Backendアプリケーション)の起動
NetBeansで[実行]を選択する

port番号3000で起動されます。

(2) Appli014(Frontendアプリケーション)の起動

port番号3001で起動されます。

(3) backendアプリケーションの実行
クライアントからhttp://127,0,0,1:3000/bookmarks/を入力してbackendアプリケーションを実行します。

(4) frontendアプリケーションの実行
クライアントからhttp://127,0,0,1:3001/bookmarks/を入力してfrontendアプリケーションを実行します。



Actionmailer | index | FileColumn