Arrayに対してfields_forを適用する
Railsを使い始めて3日目、詰まった・・・
問題
eventとparticipantのように1対nの関係を持ったモデルを作成して、それらを同時に一つのフォームで入力したい場合にfields_forを使うと思うのだが、
participantがparticipantsのような場合にfields_forを使って配列をPostする方法がわからなかった。
とりあえずぐぐってみたが、いい結果を見つけることができなかった・・・
まぁ検索方法が悪いのかもしれないけど
探すなら一番確かなのは本家のマニュアルを見ることだと心得ているので、以下のAPIマニュアルを見ることにした。
http://api.rubyonrails.org/
うーんわからん。でも手がかりはあった。
解決方法1
<% for i in 0..@participants.size -1 do %> <%= fields_for @participants[i] do |p| %> <div class="field"> <p>participant's name</p> <%= p.text_field :name %> </div> <% end %> <% end %>
泥臭い感じがするが、とりあえず以下のような出力を得ることができる
<div class="field"> <p>participant's name</p> <input id="participants_0_name" name="participants[0][name]" size="30" type="text" /> </div> <div class="field"> <p>participant's name</p> <input id="participants_1_name" name="participants[1][name]" size="30" type="text" /> </div> ...
配列でparticipantが出力されている
解決方法2
解決方法1よりも少しだけ綺麗にする<% for i in 0..@participants.size-1 do %> <%= fields_for :participants, @participants[i], { :index => i } do |p| %> <div class="field"> <p>participant's name</p> <%= p.text_field :name %> </div> <% end %> <% end %>
終わり
もっといい方法ないかなXeon E3-1275V2マシン
現在のCore2マシンがだんだんと使いにくくなってきたので、思い切ってPC自作することにした
そしてパーツ選びに迷い、いろいろ調べてメモった
- 予算:7万
- 用途:「OpenStackで遊ぶ」+「通常のPC」
- 備考:なるべく安く。ドライブは現在のマシンのものを流用する
CPU
CPUはどうせならいいのを積んでおきたい。そこで選択候補に上がったのが、以下の2つである。(値段は2012年6月17日の価格COMの最安値)- Core i7 3770K Ivy Bridge \28,699
- Xeon E3-1275V2 \29,980
これらはほぼ同じ機能を持っていて、値段も似通っている。
Intelの公式ページで比較を行った。http://ark.intel.com/ja/compare/65523,65729,65726
大きな違いはXeonがIntel VT-dに対応していることだ。
インテルが提供する仮想化支援には(1)Intel VT-xと(2)Intel VT-dの2つの機能があり、
VT-xはCPUを仮想化し、VT-dはI/Oを仮想化する。
両方搭載されているXeonを選択する。
(実はcore i7 3770(kがつかない製品)もIntel VT-dが付いていることに購入後に気づいた・・・)
Xeon E3-1275V2よりも値段が安いXeon E3-1245V2(¥23,800)に決めた。
マザーボード(MB)
チップセットはZ77 or H77Z77が上位機種であり、Z77を搭載すればオーバクロックとグラフィックボード二枚刺しが可能になるらしい。
http://www.btopcshop.com/info/parts/z77h77z68.html
とりあえずH77マザーボードを探すことにした。
安いMBを探して、公式ページでXeon E3-1245V2に対応しているか確認した。
探していて安かったGIGABYTEのGA-H77-D3Hに決めた。
メモリ
合計16GBあれば足りるだろうと踏んだ。価格COMで探して売れ筋だったCFD W3U1600HQ-4Gに決めた。(2枚セットが¥3273でこれを2セット買うと¥6546)
HDD(SSD)
Intel 330 128GBが一万円ぐらいで安いと感じたので即決筐体と電源
筐体はANTEC ONEHUNDRED電源は剛力短2プラグイン SPGT2-500P
まとめ
以上を踏まえて以下のパーツを買った。購入先はAmazonとツクモ。- CPU Xeon E3-1245V2 ¥23,800
- Memory CFD W3U1600HQ-4G(2枚組) x 2 ¥ ¥6,940(3,470x2)
- MB GIGABYTE intel H77 LGA1155 ATX GA-H77-D3H ¥ 8,890
- SSD Intel 330 Series 120GB ¥ 9,960
- 筐体 ANTEC ONEHUNDRED ¥ 4,836
- 電源 剛力短2プラグイン SPGT2-500P \5,880
合計金額:¥60,306(送料込み)
ちなみにE3-1225V2を搭載したBTOマシンが6万円で売られている。
http://bto-pc.jp/btopc-com/select/xeon-cg-cad-bto-60k.html
自分の構成に比べると
- 上記のマシンはOSとDVDドライブを搭載している
- 自分のマシンはCPUが上位、SSD搭載、筐体が良い
自分の用途にあったマシンを作れたし、パーツもそこそこのものを組み込めたので満足である。
パーツが届くまでしばしの辛抱である
続buildrootによるinitramfsのビルド
udevを使うとカーネルパニックが発生する問題を解決
udevを使うとカーネルパニックが発生する現象に遭遇したので
使用するbuildrootのバージョンを上げた.ステーブルなバージョン(2011.11,2011.08)だとうまく行かないので,スナップショットを持ってきてビルドしたところ起動するようになった.
/initの中で発生するエラー
Arch linuxから持ってきた/initがエラーを吐く
まず/runが無いと怒られる.これはディレクトリがないだけなので作る
次に/configがないと言われる.よくわからんのでconfigを使う箇所をコメントアウト
(その後,Arch linuxのinitramfsを解凍して入手したconfigを入れた)
最大の問題が/dev/disk/by-uuidが作成されないこと
UUIDをサポート
make busybox-menuconfigでいろいろ設定を変更
まずuuid関連を全て'y'にする
でもだめ
findfsを追加.
でもだめ
適当にblockdev,acpid,support for old /etc/mtabを追加
でもだめ
blkidを実行してみると何も結果を返さない!これが諸悪の根源だろう
Print filesystem type ,Filesystem/Volume identificationにextとsysvを追加
blkidが結果を返すようになったが,root=/dev/disk/by-uuid/... は使えない.
Filesystem/Volume identificationにlinux swap filesystemを追加
procも追加
依然として/dev/disk/by-uuidは作成されないが,
findfs UUID="disk uuid"とすれば/dev/sda*と表示されるのでfindfsが問題なく動いている
GRUBの記述方法にはroot=/dev/disk/by-uuid/の他にroot=UUID=という指定方法があるので,
そっちも試してみたがだめ.うーん
Archから持ってきた/initに問題があるかも
/init_functionsというスクリプトファイルの中にあるresolve_devices()を見るとUUID=による記述が使えるきがする.
でも現実はそうじゃない.どういうことだ?
resolve_device() { local major minor dev device=$1 case $device in # resolve tag name to block device UUID=*|LABEL=*) dev=$(blkid -lt "$device" -o device) [ -n "$device" ] && device=$dev ;; esac case $device in /dev/*) if poll_device "$device" "$rootdelay"; then echo "$device" return 0 fi # block device, e.g. (/dev/sda1) -> /sys/class/block/sda1/dev if [ -e /sys/class/block/${device:5}/dev ]; then IFS=':' read major minor < "/sys/class/block/${device:5}/dev" fi ;; [0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]|[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]) # hex encoded major/minor, such as from LILO major=$(( 0x0$device >> 8 )) minor=$(( 0x0$device & 0xff )) ;; 0x[0-9a-fA-F][0-9a-fA-F]*) major=$(( $device >> 8 )) minor=$(( $device & 0xff )) ;; esac if [ -n "$major" -a -n "$minor" ]; then device=$(major_minor_to_device "$major" "$minor" || echo '/dev/root') if [ ! -b "$device" ]; then msg "Creating device node with major $major and minor $minor." >&2 mknod "$device" b "$major" "$minor" fi echo "$device" return 0 fi return 1 }
blkidを-ltと-oをつけて使用すると結果がおかしい気がする
まず-o deviceによって本来の結果は
/dev/sda1 /dev/sda2 /dev/sda3 /dev/sda4
と表示されるはずなのにオプションを付けなかった時と同じ表示になってしまう.
"-lt"で値が一致するものだけを表示するはずのところが,付けなかった時と同じ表示になる.
つまりblkidのオプションが全く動作していない.なんてことだ.
オプション群はおそらくlibblkで提供されていると思うので,調べてみるが,驚愕の事実が・・・
$ grep libblkid . -R -I ./output/build/busybox-1.19.3/e2fsprogs/old_e2fsprogs/blkid/tag.c: * Tag iteration routines for the public libblkid interface. ./output/build/busybox-1.19.3/e2fsprogs/old_e2fsprogs/blkid/dev.c: * dev iteration routines for the public libblkid interface. ./output/build/busybox-1.19.3/e2fsprogs/old_e2fsprogs/blkid/blkid.h: * blkid.h - Interface for libblkid, a library to identify block devices ./output/build/busybox-1.19.3/e2fsprogs/old_e2fsprogs/blkid/blkidP.h: * blkidP.h - Internal interfaces for libblkid ./output/build/busybox-1.18.5/e2fsprogs/old_e2fsprogs/blkid/tag.c: * Tag iteration routines for the public libblkid interface. ./output/build/busybox-1.18.5/e2fsprogs/old_e2fsprogs/blkid/dev.c: * dev iteration routines for the public libblkid interface. ./output/build/busybox-1.18.5/e2fsprogs/old_e2fsprogs/blkid/blkid.h: * blkid.h - Interface for libblkid, a library to identify block devices ./output/build/busybox-1.18.5/e2fsprogs/old_e2fsprogs/blkid/blkidP.h: * blkidP.h - Internal interfaces for libblkid ./output/build/udev-173/NEWS:repository. Libvolume_id is merged with libblkid from the util-linux-ng grep: ./output/target/etc/resolv.conf: No such file or directory grep: ./output/target/etc/mtab: No such file or directory grep: ./output/target/dev/log: No such file or directory ./package/util-linux/util-linux.mk: $(if $(BR2_PACKAGE_UTIL_LINUX_LIBBLKID),,--disable-libblkid) \ ./package/util-linux/Config.in: bool "build libblkid and blkid utilities" grep: ./fs/skeleton/etc/resolv.conf: No such file or directory grep: ./fs/skeleton/etc/mtab: No such file or directory grep: ./fs/skeleton/dev/log: No such file or directory
なんと--disable-libblkidとなっている.なんでだ?
findfsコマンドをblkidの代りにしてやるか
resolve_device()を書き換え
- dev=$(blkid -lt "$device" -o device) + dev=$(findfs $device)
GRUBのroot=をroot=UUID=ディスクのUUIDと設定したら起動できるようになった.
buildrootインストール
buildrootのインストール
buildrootは組み込み用途のLinuxを簡単にビルドするためのツール
今回はこのツールを使って高機能なinitramfsを作る
説明
initramfsはディスクをルートにマウントする前の一時的なファイルシステムだと思うけど,
initramfsに必要なものをいろいろ突っ込んでしまえば,そこそこ使えるはず
別の使い方としてはkdump用に作っておけば,デバッグの時にいろいろできるだろう
インストール
以下からダウンロードしてファイルを解凍して適当なディレクトリに展開しましょう
[](http://buildroot.uclibc.org/)
自分は/usr/src以下に展開しました
$ cd /usr/src/buildroot/ $ make menuconfig $ make
使った計算機はx86_64なので,menuconfigではまずCPUのアーキテクチャをx86_64を選択した.
次にBusyBoxの設定を変更することでいろんなツール(NFS,sshdなど)をinitramfsにインストールできる.
入れるツールはお好みで.
あとはinitramfs(initrd)の圧縮形式の選択でcpio.gzにした.これも好みの問題?
Linuxカーネルをビルドする必要はない.(initramfsをカーネルに組み込む場合はこの限りではない)
makeが完了するとoutput/images/にinitramfsがrootfs.cpioとrootfs.cpio.gzという名前で作成されている
/bootにコピーして,GRUBのメニューを書き換える.
$ cp output/images/rootfs.cpio /boot $ sudo emacs /boot/grub/menu.lst
#(0) title buildroot root (hd0,0) kernel /vmlinuz-2.6.38.7-MK root=/dev/ram0 ro iommu=soft initrd /rootfs.cpio.gz
以上でとりあえず起動する.
この状態で以下の点が不満だった
- ログインシェルが表示されないこと
- 通信ができないこと
ログインシェルが出ないのでキーボードからユーザ名とパスワードを打ってログインすることできない.
そして通信ができないのでsshで接続することもできない.要するに使えない(シリアルケーブル経由ならいけるかも)
ログインシェルが表示されない問題は以下のページでよくある質問として扱われていた
()http://buildroot.uclibc.org/downloads/buildroot.html#custom_targetfs
make menuconfigにおいてSystem configuration->Port to run a getty (login prompt)を変更すればいいらしい
初期値はttyS0となっていたところをtty1に変更し,起動したところログイン可能になった
次に通信だが,これは通信の設定ファイルを書き換える必要がある.
initramfsに入れられるファイルはbuildroot/output/target以下にあるので,
それを編集してmakeを実行すればrootfs.cpio.*のファイルが書き換わる.
書き換えるファイルはbuildroot/output/target/etc/network/interfacesである.
以下のように設定すればethernetにIPアドレスが振られて通信できるようになる
auto lo eth0 iface lo inet loopback iface eth0 inet static address 123.45.67.890 network 123.45.67.0 netmask 255.255.255.0 broadcast 123.45.67.255 gateway 123.45.67.1 dns-nameservers 123.45.2.1
今日はここまで
initrd/initramfs
initramfsの中身を調べる
方法としては initramfsを解凍する方法もあるが,改変することを考えるとソースとなるディレクトリを知る必要がある
使用したディストリビューションはArch Linux.
ソースディレクトリの特定
カーネルビルドにおいてmake installをすると/boot以下にカーネル本体の他にinitramfsが生成される.
このinitramfsを生成するのはArch linuxではmkinitcpioコマンド(シェルスクリプト)である.
mkinitcpioの中身を確認する.
$ less `which mkinitcpio`
中身を見ると,initramfsの中身の所在は/lib/initcpio/にありそうだとわかる
$ ls /lib/initcpio busybox* functions hooks/ init* init_functions install/ udev/
busyboxが入っているところを見るとビンゴっぽい
/initの中身を読んでみる
/lib/initcpio/initがinitramfsをマウントした時の/initになるわけで,
このスクリプトが仮のルートファイルシステム(initramfs)からリアルルートファイルシステムへ移行するための処理をするはずである.
読んでみる
$ emacs /lib/initcpio/init
(抜粋) mkdir -p /new_root ... ${mount_handler:-default_mount_handler} /new_root ... for d in proc sys dev run; do if [ -d /new_root/${d} ]; then mount --move /${d} /new_root/${d} else umount /${d} fi done exec env -i TERM=$TERM /sbin/switch_root -c /dev/console /new_root ${init} "$@"
initの中では後にリアルルートになるファイルシステムを/new_rootとして作成する.
/new_rootがのちのリアルルートディレクトリになるもので,default_mount_handler(init_functionsに記述)によりnew_rootにディスク(ルートディレクトリとなるディスクパーティション)をマウントする.(まだ詳しくは調べていない)
最後にmount --moveによって/proc, /sys, /dev, /runを/new_root/以下に移動する.
以上で準備が完了するのでswitch_rootコマンドによってルートディレクトリを/new_rootに変更し,/sbin/initを実行する.
他にもいくつか処理があるので,調べるが,今回はここまで終わり