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ファイルを作成しましょう。
バイデザイン 74,800 131
東芝 78,000 7
シャープ 80,000 18
三菱電機 80,500 45
SONY 83,800 27
ユニデン 88,000 310
シャープ 89,800 30
SONY 89,800 66
東芝 91,200 123
東芝 92,684 8
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) コントローラの編集
class XmlController < ApplicationController
require "rexml/document"
include REXMLdef index
@doc = Document.new File.new("tvbest10.xml")
end
end
(3) ビューの作成
<%=h @doc %>
(4) 動作確認
登録したxmlファイルが読み込まれることを確認するため、ブラウザからhttp://127.0.0.1:3000/xml/でプログラムを起動します。
1-4.さまざまな機能
詳細な仕様はhttp://pub.cozmixng.org/~kou/rexml-doc-ja/でみることができますが、ここではその幾つかを紹介します。
(1) 要素の取り出し
class XmlController < ApplicationController
require "rexml/document"
include REXMLdef index
@doc = Document.new File.new("tvbest10.xml")
# 要素の取り出し
@makers=""
@doc.elements.each("tv/model/maker") { |element|
@makers += element.to_s + "<br>"
}
end
end
<br/>
makers<br/>
--------<br/><%= @makers %>
makers
----------
バイデザイン
東芝
シャープ
三菱電機
SONY
ユニデン
シャープ
SONY
東芝
東芝
(2) 属性の取り出し
class XmlController < ApplicationController
require "rexml/document"
include REXMLdef index
@doc = Document.new File.new("tvbest10.xml")
# 属性の取り出し
@names=""
XPath.each(@doc, "//model/attribute::name") { |element|
@names += element.to_s + "<br>"
}
end
end
<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の削除
class XmlController < ApplicationController
require "rexml/document"
include REXMLdef index
@doc = Document.new File.new("tvbest10.xml")
# XMLデータの削除
@doc.elements.delete("tv/model[1]") # modelという名の要素の中で一番目の要素を削除する
end
end
doc<br>
--------</br><%=h @doc %>
doc
--------
バイデザイン 74,800 131
東芝 78,000 7
シャープ 80,000 18
三菱電機 80,500 45
SONY 83,800 27
ユニデン 88,000 310
シャープ 89,800 30
SONY 89,800 66
東芝 91,200 123
東芝 92,684 8
(4) XMLの更新
class XmlController < ApplicationController
require "rexml/document"
include REXMLdef 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
<br/>
doc<br/>
--------<br/><%=h @doc %>
doc
--------
東芝 78,000 7
シャープ 80,000 18
三菱電機 80,500 45
SONY 83,800 27
ユニデン 88,000 310
シャープ 89,800 30
SONY 89,800 66
東芝 91,200 123
東芝 91,500 8
(5) XMLの追加
class XmlController < ApplicationController
require "rexml/document"
include REXMLdef index
@doc = Document.new File.new("tvbest10.xml")# XMLデータの追加
root = @doc.rootmodel = 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
<br/>
doc<br/>
--------<br/><%=h @doc %>
doc
--------
東芝 78,000 7
シャープ 80,000 18
三菱電機 80,500 45
SONY 83,800 27
ユニデン 88,000 310
シャープ 89,800 30
SONY 89,800 66
東芝 91,200 123
東芝 92,684 8
シャープ 92,000 30
(6) XMLの出力
class XmlController < ApplicationController
require "rexml/document"
include REXMLdef index
@doc = Document.new File.new("tvbest10.xml")
# XMLファイルの出力
File.open("tvbest11.xml","w") do |outfile|
@doc.write(outfile)
end
end
end
OpenFlashChart
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'}
となります。
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) コントローラの作成
class SalesController < ApplicationController
def test_graph
@graph = open_flash_chart_object(600,400, "/graph/test1_code")
enddef 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) ビューの修正
<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) コントローラの作成
テストプログラムごとにコントローラとビューを書くのは大変です。少しロジックに手を入れてコーディングの量を減らしましょう。
class SalesController < ApplicationController
def test_graph
path="/graph/test" + params[:id].to_s + "_code"
@graph = open_flash_chart_object(600,400,path)
enddef test1_code
:
enddef 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となります。
<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) コントローラの作成
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) コントローラの作成
ここで注意しなければならないのがデータ値は上から順に設定していますが、
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_moon | amount_of_sales |
---|---|
2009-01 | 18,300,000 |
2009-02 | 14,900,000 |
2009-03 | 16,900,000 |
2009-04 | 9,800,000 |
2009-05 | 11,300,000 |
2009-06 | 12,500,000 |
2009-07 | 16,500,000 |
2009-08 | 15,200,000 |
2009-09 | 20,600,000 |
2009-10 | 23,100,000 |
2009-11 | 21,300,000 |
2009-12 | 20,000,000 |
2010-01 | 19,600,000 |
2010-02 | 15,200,000 |
2010-03 | 15,800,000 |
2010-04 | 13,300,000 |
2010-05 | 9,500,000 |
2010-06 | 8,800,000 |
2010-07 | 6,000,000 |
1-10.折れ線グラフによる売上推移表の作成
(1) コントローラの作成
class SalesController < ApplicationController
:
:
def line_graph
@graph = open_flash_chart_object(600,400,"/graph/line_graph_code")
enddef 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] # 売上月を文字列に変換
endtitle = 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 = ychart.add_element(line_pv)
render :text => chart.to_s
end
:
:
end
(2) ビューの修正
<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) コントローラの作成
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
endtitle = 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 = ychart.add_element(bar)
chart.add_element(bar2)render :text => chart.to_s
end
:
:
end
(2) ビューの修正
<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} |
null | null |
(2) グラフデータの構造
まず具体例として公式ページhttp://teethgrinder.co.uk/open-flash-chart-2/より抜粋したものを提示します。
新らたに出現したキーについてはコメントを入れました。
{
"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) 詳細な設定
棒のひとつだけ色を変えてみましょう。
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 = valsx = 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 = 10chart = 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で起動します。
ディレクトリとファイルの操作
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を利用するときは文字コードは次の定数で指定します。
定数 | 文字コード |
---|---|
JIS | ISO-2022-JP |
EUC | EUC-JP |
SJIS | Shift_JIS |
BINARY | バイナリ |
ASCII | ASCII |
UTF8 | UTF-8 |
UTF16 | UTF-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) |
\nnn | 8 進数表記 (n は 0-7) |
\xnn | 16 進数表記 (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を利用し、ファイル操作の結果を同一画面に表示させながら進行するプログラムとしましょう。
class CommandsController < ApplicationController
def index
enddef 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
enddef operate_chdir
Dir::chdir(@strarray[1]) # カレントディレクトリの変更
@result="<br>" + File::expand_path('.') + ">chdir #{@strarray[1]} <br>"
enddef operate_mkdir
Dir::mkdir(@strarray[1]) unless File::exist?(@strarray[1]) # ディレクトリの作成
@result="<br>" + File::expand_path('.') + ">mkdir #{@strarray[1]} <br>"
enddef operate_rmdir
Dir::delete(@strarray[1]) # ディレクトリの削除(但し空であること)
@result="<br>" + File::expand_path('.') + ">rmdir #{@strarray[1]} <br>"
enddef operate_rename
FileUtils::mv(@strarray[1], @strarray[2]) # ファイル名やディレクトリ名の変更
@result="<br>" + File::expand_path('.') + ">rename #{@strarray[1]} #{@strarray[2]} <br>"
enddef 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"
endend
(3) レイアウトファイルの作成
Ajaxを利用するため、基本的なレイアウトファイルを作成します。
<!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"><
:position => "top",
:url => {:action => "operate"} do -%>
Command: <%= text_field :commandarea, :commandline, :size => 80 %><% end -%>
<br/>
<div id="resultarea"></div>
<%= "#{@result}" %>
1-6.動作確認
(1) 実装されたコマンドの種類
Command | 内容 |
---|---|
dir | カレントディレクトリ直下のディレクトリ名およびファイメ名の取得 |
chdir | カレントディレクトリの変更 | <
mkdir | ディレクトリの新規作成 |
rmdir | デイレクトリの削除(但しディレクトリ直下は空であること) |
rename | ディレクトリ名の変更 |
1-7.ファイル操作のプログラム作成
(1) ディレクトリの操作プログラムの機能追加
class CommandsController < ApplicationController
def index
enddef 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
enddef operate_chdir
Dir::chdir(@strarray[1]) # カレントディレクトリの変更
@result="<br>" + File::expand_path('.') + ">chdir #{@strarray[1]} <br>"
enddef operate_mkdir
Dir::mkdir(@strarray[1]) unless File::exist?(@strarray[1]) # ディレクトリの作成
@result="<br>" + File::expand_path('.') + ">mkdir #{@strarray[1]} <br>"
enddef operate_rmdir
Dir::delete(@strarray[1]) # ディレクトリの削除(但し空であること)
@result="<br>" + File::expand_path('.') + ">rmdir #{@strarray[1]} <br>"
enddef operate_rename
FileUtils::mv(@strarray[1], @strarray[2]) # ファイル名やディレクトリ名の変更
@result="<br>" + File::expand_path('.') + ">rename #{@strarray[1]} #{@strarray[2]} <br>"
enddef operate_copy
FileUtils::cp(@strarray[1], @strarray[2]) # ファイルのコピー
@result="<br>" + File::expand_path('.') + ">copy #{@strarray[1]} #{@strarray[2]} <br>"
enddef 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
enddef 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
enddef 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>"
enddef 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"
endend
1-8.動作確認
(1) 新たに実装されたコマンドの種類
Command | 内容 |
---|---|
rename | ファイル名の変更 |
copy | ファイルのコピー (ファイル名) → (ファイル名) (ファイル名) → (フォルダ名) |
read | テキストファイルの読み込み |
clearlog | ログファイルの初期化 |
printlog | ログのプリントアウト |
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) ライブラリの修正
/*
* 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) マイグレーションのプログラム修正
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) モデルの編集
class Gallery < ActiveRecord::Base
MAX_FILE_SIZE = 1.megabytevalidates_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
enddef 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) コントローラの編集
class GalleriesController < ApplicationController
def index
@folders = Folder.find(:all)
enddef new
end
def create
@gallery = Gallery.new(params[:upload])
if @gallery.valid? then
@gallery.save
redirect_to :action => 'index'
end
enddef destroy
@gallery = Gallery.find(params[:id])
@gallery.destroy
redirect_to :action => 'index'
end
end
1-5.ビューの編集
(1) 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
<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
<h1>Create</h1><%= error_messages_for :gallery %><%= link_to('index', {:action => 'index'}) %>
(4) 不用なビュープログラムの削除
/app/views/galleries/destroy.html.erb
(5) レイアウトファイルの作成
HTMLのヘッダー部分など各ページ共通に利用される表示要素を作成します。
今回はprotothickboxも使用するための準備もします。
<!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
<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'}) -%>
ファイルのアップロードとダウンロード
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) マイグレーションのプログラム修正
class CreateFolders < ActiveRecord::Migration
def self.up
create_table :folders do |t|
t.string :filename
t.string :content_type
t.integer :sizet.timestamps
end
enddef 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) モデルの編集
class Folder < ActiveRecord::Base
MAX_FILE_SIZE = 1.megabytevalidates_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
enddef 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) コントローラの編集
class FoldersController < ApplicationController
def index
@folders = Folder.find(:all)
enddef new
end
def create
@folder = Folder.new(params[:upload])
if @folder.valid? then
@folder.save
redirect_to :action => 'index'
end
enddef destroy
@folder = Folder.find(params[:id])
@folder.destroy
redirect_to :action => 'index'
enddef 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
<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
<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
<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のヘッダー部分など各ページ共通に利用される表示要素を作成します。
<!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ディレクトリーの作成
公開ディレクトリー上で右クリックして[新規]→[フォルダ...]を選択します。
(3) ファイルの格納先
/public/files/[id]_[original_filename]
1-6.動作確認
http://127,0,0,1:3000/folders/で起動します。
1-7.表示の改善
(1) 数値のカンマ編集
サイズの表示方法をカンマ編集し見やすくしましょう。
<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'}) %>
(3) 漢字を含むファイル名をアップロードするときの不具合を修正
文字コードがWindowsとRuby on Railsでは異なるため、漢字を含むファイル名のときはファイル名称が正しく伝わりません。
例えばUTF8コードで、”すいれん_Water lilies.jpg”のファイルをそのままWindowsに渡すと”縺吶>繧後s_Water lilies.jpg”となってしまいます。
そこでRuby on Rails からWindowsOSへファイルを渡すときに文字コードをutf8からshiftjisにコンバージョンするロジックを組み込みます。
class Attachment < ActiveRecord::Base
MAX_FILE_SIZE = 1.megabytevalidates_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
enddef 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にコンバージョンするロジックを組み込みます。
これでファイル名はWindowsへも正しく引き継がれます。
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
(5) 文字コード関係のまとめ
アップロードおよびダウンロードにおける文字コードの推移については次の図が理解しやすいでしょう。
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プラグインの修正
このまま利用すると、実行時にエラーをするため、一部プログラムを修正します。
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) マイグレーションの確認
class AddImageToAddresses < ActiveRecord::Migration
def self.up
add_column :addresses, :image, :string
enddef 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) モデルの修正
class Address < ActiveRecord::Base
file_column :image
end
(6) ビューの修正
<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 %>
<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 %>
<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 %>
<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を修正します。
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
filenameend
end
(9) 動作確認
これで日本語のファイル名も扱うことができます。
・(アップロードするファイル名が「日の入り_Sunset.jpg」の場合)
・(アップロードされたファイル名も「日の入り_Sunset.jpg」となる)
(10) 画像の表示
さらに画像についてはファイル名ではなく画像を表示させましょう。
<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) 画像の拡大縮小
<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
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の特徴
ActiveResourceはRuby on Rails 2.0 から追加された機能で、Railsのインストールどきに一緒にインストールされます。Web上のRESTful APIをActiveRecordのモデルと同じようなインターフェースで利用可能にする、いわば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 にアクセスして、データの取得・保存を行います。
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) コントローラの修正
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を区別するため、表示画面の背景色を「白」から「青系」に変更します。
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アプリケーションを実行します。