某所で行われた奥出研究室の最終発表レポート。
の前に、ちょっとこの素晴らしさを広めたく、blogに貼っちゃいます。
この完成度はやばいです。
さて、本題
名前出すのはNGかと思われるので伏せますが、某携帯会社の方達がお客さんとしていらっしゃいました。
Muliusもなかなか好評?でした。
しかし、問題としては、Muliusを使うにふさわしいシーンはライブ会場であったり、電車の中などシーンが限定されているのに対して、デモンストレーションを行うときは、会議室とか講堂とかですれちがうアクションをするだけ。
だから、良さがなかなか分かってもらえないという感じでした。どうゆうときに使うかいまいち分からないという意見も、シンポジウムのときから聞いていました。そんなとき、ライブや電車といったエピソードを話すと納得してもらえるのですが、体験はしてもらえない。
もどかしいです。。。くやしいです。。。苦笑
目次
2009年3月9日月曜日
音楽産業への考察
シナリオを考えながら、同時平行で、音楽産業についても少し調べて考察していました。
そんなこんなで、音楽業界考察めも。なんか思い上がりも甚だしい感じです。
初めて買ったCDは安室奈美恵ちゃんのアルバムでした。2500円くらいしたかな?当時は小学生でした。シングルとかはちっちゃいCDでした。(いまはあのサイズPCに入らなくて大変迷惑です笑)カラオケバージョンとか入ってて1000円くらい。当時はそれが普通でした。
10数年前までは「曲」そのものを販売すれば利益をあげる事が出来たのに、いまはそうは行きません。iTuneStoreで150円くらいです。一曲あたりの値段がどんどん下がっています。加えて、マスメディアの衰退により、とある一曲が爆発的に売れるということも少なくなりました。みんなが聴いているから聴く、という事をあまりしなくなったのでしょう。
ダブルミリオンって言葉、昔はけっこう聞いたけど、いまは200万ダウンロードで「すごい!」って感じですよね。
CD、売れません。いま考えるとCDってすっごい割が良かったんですね。カラオケバージョンくっつけるだけで10倍くらいの値段で売れたんだから。
いま成功しているモデルがiTuneStoreだとすると
たくさんのユーザーに曲を買ってもらうのではなく、一人のユーザーが購入する楽曲数を増やす
=さまざまな曲を取り揃える/☆いろいろな曲を買ってもらえるシステムを考える
=ジーニアス、最近だとShazamなどと連携させる。
☆マークの分野を多くの企業が注目している分野であり、lastFMやMySpaceはここに相当するでしょう。たくさんの曲が聞けるよ/聞いてね、という所をアピールしている。
しかし、いまはこのモデルでiTuneStoreが成功していますが、将来的にはどうなのでしょうか?
今、iTuneStoreで一曲200円以上の値を付けると、「金の亡者」とネットで叩かれます。昔はCDとはいえ1000円以上払っていたのに。一曲の値段がさがり続け、かぎりなく0に近くなることも考えられると思います。
サブスクリプション販売(いわゆる定額聴き放題)も注目されています。もしiTuneStoreで導入されれば、従来のモデルは完全に崩壊するでしょう。現にiTuneStoreでも導入が検討されているようですし、その日も遠くはないでしょうね。
アーティスト側もその事を敏感に感じ取って、行動している人たちもいます。
プリンスやナインインチネイルズというバンドが無料で楽曲をHPで公開した話はあまりにも有名です。スマッシングパンプキンズのマシーナⅡもそう。
最近ではレディオヘッドがダウンロードの際、購入者が自分で値段を決められるという新しい販売方法を始めました。
たくさんの人に楽曲を購入してもらって儲けるというのが「レコード会社の思うつぼ=かっこわるい」というイメージが固まりつつあります。
「たくさんの人に聴いてもらえさえすればいい。利益はどうでもいい」という態度を一流の人たちにされると、みんなマネしちゃうしかないですよ。
そうなってくると「音楽」というものに関わる人は、どうやって利益をあげるのかって話になってきます。
私は、「たくさんの楽曲を購入してもらうために、売り方を変える」と考え方では通用しないと思います。曲そのものには値段がつかなくなってしまっているため、曲を売るという考え方だけでは破綻するでしょう。lastFMのようなサービスも、「今は」いいんです。でも10年たったらどうなっているか分かりません。CDがこんなに売れなくなるなんて、10年前の私は思いもしませんでした。けど、10年たったらこんなに変わってしまったという現実がある。
さらに一歩先のビジネスモデルを考える必要があるのではないかと思っています。
一方、コンサートやライブに行く人は増え続けているようです。
マドンナはレコード会社ワーナーとの契約を切り、イベント興行会社の「米Live Nation(ライブネーション)」と契約しました。ローリング・ストーンズは、2005年から2007年にかけてのワールドツアーで4億3700万ドル(約500億円)の興行収入を得ています。
有名アーティストがツアーを行うという事は、単にアーティストが曲を聴かせ、お金をもらうだけではありません。たくさんの副収入も呼び込むと考えられます。会場内で販売されるグッズや飲食類、さらにはスポンサーもついて、膨大なお金が動くと考えられます。人が集まればそれだけ利益をあげるチャンスが生じるというわけです。
音楽業界/アーティストは、どんなイベントや体験を提供出来るかがこれからのキーだと思います。ライブに力を入れるのももちろんですが、フェスやクラブイベントといったミュージックエクスペリエンスを考え、提供していく。従来にないイベント=音楽体験を提供する。
こんなのいままでなかった!というイベントを提供できた会社が、一歩先に出て行くでしょう。アーティストが舞台にたち、観衆はそれを見るという形ではないパフォーマンスなり、何なり。。。その到来を観衆側も求めて、ヲタ芸という特殊な楽しみ方が出て来たんじゃないでしょうかね?
(ちょうどヲタ芸の話が出て来たときに戻ったなぁ!やっぱりMuliusの原点はそこなんだね)
この体験でのキーワードは「webサービス」そしてイベントは必ず「場所」性(現実に持って行く事といえばいいのかな?)をもつこと。webだけで終わらせるのは、ITの抱えるジレンマに行き着いちゃいますからね。
そんな感じで、Muliusを使ってなんか面白いイベントが開けないかと考察中...
一緒に仕事をしたい、Mulius見てみたいという企業の方、連絡ください(笑)
そんなこんなで、音楽業界考察めも。なんか思い上がりも甚だしい感じです。
曲で儲けるのは古い?
初めて買ったCDは安室奈美恵ちゃんのアルバムでした。2500円くらいしたかな?当時は小学生でした。シングルとかはちっちゃいCDでした。(いまはあのサイズPCに入らなくて大変迷惑です笑)カラオケバージョンとか入ってて1000円くらい。当時はそれが普通でした。
10数年前までは「曲」そのものを販売すれば利益をあげる事が出来たのに、いまはそうは行きません。iTuneStoreで150円くらいです。一曲あたりの値段がどんどん下がっています。加えて、マスメディアの衰退により、とある一曲が爆発的に売れるということも少なくなりました。みんなが聴いているから聴く、という事をあまりしなくなったのでしょう。
ダブルミリオンって言葉、昔はけっこう聞いたけど、いまは200万ダウンロードで「すごい!」って感じですよね。
CD、売れません。いま考えるとCDってすっごい割が良かったんですね。カラオケバージョンくっつけるだけで10倍くらいの値段で売れたんだから。
いま成功しているモデルがiTuneStoreだとすると
たくさんのユーザーに曲を買ってもらうのではなく、一人のユーザーが購入する楽曲数を増やす
=さまざまな曲を取り揃える/☆いろいろな曲を買ってもらえるシステムを考える
=ジーニアス、最近だとShazamなどと連携させる。
☆マークの分野を多くの企業が注目している分野であり、lastFMやMySpaceはここに相当するでしょう。たくさんの曲が聞けるよ/聞いてね、という所をアピールしている。
しかし、いまはこのモデルでiTuneStoreが成功していますが、将来的にはどうなのでしょうか?
今、iTuneStoreで一曲200円以上の値を付けると、「金の亡者」とネットで叩かれます。昔はCDとはいえ1000円以上払っていたのに。一曲の値段がさがり続け、かぎりなく0に近くなることも考えられると思います。
サブスクリプション販売(いわゆる定額聴き放題)も注目されています。もしiTuneStoreで導入されれば、従来のモデルは完全に崩壊するでしょう。現にiTuneStoreでも導入が検討されているようですし、その日も遠くはないでしょうね。
アーティスト側もその事を敏感に感じ取って、行動している人たちもいます。
プリンスやナインインチネイルズというバンドが無料で楽曲をHPで公開した話はあまりにも有名です。スマッシングパンプキンズのマシーナⅡもそう。
最近ではレディオヘッドがダウンロードの際、購入者が自分で値段を決められるという新しい販売方法を始めました。
たくさんの人に楽曲を購入してもらって儲けるというのが「レコード会社の思うつぼ=かっこわるい」というイメージが固まりつつあります。
「たくさんの人に聴いてもらえさえすればいい。利益はどうでもいい」という態度を一流の人たちにされると、みんなマネしちゃうしかないですよ。
そうなってくると「音楽」というものに関わる人は、どうやって利益をあげるのかって話になってきます。
私は、「たくさんの楽曲を購入してもらうために、売り方を変える」と考え方では通用しないと思います。曲そのものには値段がつかなくなってしまっているため、曲を売るという考え方だけでは破綻するでしょう。lastFMのようなサービスも、「今は」いいんです。でも10年たったらどうなっているか分かりません。CDがこんなに売れなくなるなんて、10年前の私は思いもしませんでした。けど、10年たったらこんなに変わってしまったという現実がある。
さらに一歩先のビジネスモデルを考える必要があるのではないかと思っています。
アーティストはライブ活動で利益をあげる
一方、コンサートやライブに行く人は増え続けているようです。
マドンナはレコード会社ワーナーとの契約を切り、イベント興行会社の「米Live Nation(ライブネーション)」と契約しました。ローリング・ストーンズは、2005年から2007年にかけてのワールドツアーで4億3700万ドル(約500億円)の興行収入を得ています。
有名アーティストがツアーを行うという事は、単にアーティストが曲を聴かせ、お金をもらうだけではありません。たくさんの副収入も呼び込むと考えられます。会場内で販売されるグッズや飲食類、さらにはスポンサーもついて、膨大なお金が動くと考えられます。人が集まればそれだけ利益をあげるチャンスが生じるというわけです。
ミュージックエクスペリエンス産業
音楽業界/アーティストは、どんなイベントや体験を提供出来るかがこれからのキーだと思います。ライブに力を入れるのももちろんですが、フェスやクラブイベントといったミュージックエクスペリエンスを考え、提供していく。従来にないイベント=音楽体験を提供する。
こんなのいままでなかった!というイベントを提供できた会社が、一歩先に出て行くでしょう。アーティストが舞台にたち、観衆はそれを見るという形ではないパフォーマンスなり、何なり。。。その到来を観衆側も求めて、ヲタ芸という特殊な楽しみ方が出て来たんじゃないでしょうかね?
(ちょうどヲタ芸の話が出て来たときに戻ったなぁ!やっぱりMuliusの原点はそこなんだね)
この体験でのキーワードは「webサービス」そしてイベントは必ず「場所」性(現実に持って行く事といえばいいのかな?)をもつこと。webだけで終わらせるのは、ITの抱えるジレンマに行き着いちゃいますからね。
そんな感じで、Muliusを使ってなんか面白いイベントが開けないかと考察中...
一緒に仕事をしたい、Mulius見てみたいという企業の方、連絡ください(笑)
制作で一番大変なところ。
なんか具合悪いや。。。でも、ちょこちょこ継続しております。
研究室の人たちにMuliusの設計モデルを役立てていただくため、資料を作ろうとblogを読み返していた所、おそろしい事実が判明しました。
シンポジウムで何人かに聞かれた質問でもあったのですが、
Q:どのくらい時間かかったんですか?
A:4ヶ月くらいかな。。。
と答えていたのですが訂正します。
まあアイディアとか設計を入れれば1年半なのですが、このシステムを頭で考えたのが11月頃。12月まではまだソフトの設計とかしてなかった。rubyとrailsの違いも分かっていないことがblogから分かります(笑)
railsを本気で触り出したのが今年に入ってからだから、作業としては2ヶ月弱ですね。
なにが言いたいかというと、設計図が出来ていればたいてい完成するってことです。
むしろ設計図が一番時間がかかると言って良いんです。
何が設計図かが、はっきりしていないからもたもたしてしまう。
いわゆる
概念モデル、論理モデル(物理モデル)というやつを書くということです。
概念モデルは奥出研でよく書いてるものです。
棒人間書いて、デバイス書いて、関連やアクションを書いて、、、というあれです。
それが出来たらUML書いて、、、、というやつですが、ここでSTOP!
まずは言語や、マイコン、通信手段その他使う技術を決めましょう。技術が出来ない人ほどここを決めます。
言語だけでも決めないとUMLとかよくわからなくて結局挫折してしまうと思うのです。オブジェクト思考が身に付いている人はいいんです。でも、なんとなく、とかわかりませんという人はまず使う言語を決めて、勉強をして、それから取り組めばいいと思うんです。
私の場合、概念モデルまではいいとしても、なかなか先に進めなかったのはそこが原因。出来るのか出来ないのか、とかそうゆうのは置いておく。(たいてい、解決策はあるのです)
まずは、
「ソフトはrails,マイコンはmoxa,無線にするにはWiPort」と3つを決めました。理由は使ってる人が居たから、というシンプルな考え方です。技術に関する知識がないのにそんなカンタンに決めていいのかと言われそうですが、技術がないからこそ何か1つ選んで習得しないと行けないんです。だからここで使う技術というのはイコール自分が勉強したいというものでいいんです。私の場合、railsの勉強を始めてみると、あっと言う間に設計図もかけて、上手くいったというわけです。
とは言え、そうカンタンに設計図はかけません。だから2ヶ月で終わるものを、1年以上悩んでいる。なかなか進まないからといってくじけないでください。
いきづまったら決めちゃいましょう!どうしても覚えられない言語なり技術なら、そう分かった時点でかえればいい。
まずは何を使うか決めましょう。
flashですか?PHPですか?railsですか?
マイコンはGainerですか?Arduino?
通信はBlueTooth?Zigbee?Wiport?
まずは決まったら半分出来たと思って良いです。
研究室の人たちにMuliusの設計モデルを役立てていただくため、資料を作ろうとblogを読み返していた所、おそろしい事実が判明しました。
シンポジウムで何人かに聞かれた質問でもあったのですが、
Q:どのくらい時間かかったんですか?
A:4ヶ月くらいかな。。。
と答えていたのですが訂正します。
A:2ヶ月でした(!!?)
まあアイディアとか設計を入れれば1年半なのですが、このシステムを頭で考えたのが11月頃。12月まではまだソフトの設計とかしてなかった。rubyとrailsの違いも分かっていないことがblogから分かります(笑)
railsを本気で触り出したのが今年に入ってからだから、作業としては2ヶ月弱ですね。
なにが言いたいかというと、設計図が出来ていればたいてい完成するってことです。
むしろ設計図が一番時間がかかると言って良いんです。
何が設計図かが、はっきりしていないからもたもたしてしまう。
いわゆる
概念モデル、論理モデル(物理モデル)というやつを書くということです。
概念モデルは奥出研でよく書いてるものです。
棒人間書いて、デバイス書いて、関連やアクションを書いて、、、というあれです。
それが出来たらUML書いて、、、、というやつですが、ここでSTOP!
まずは言語や、マイコン、通信手段その他使う技術を決めましょう。技術が出来ない人ほどここを決めます。
言語だけでも決めないとUMLとかよくわからなくて結局挫折してしまうと思うのです。オブジェクト思考が身に付いている人はいいんです。でも、なんとなく、とかわかりませんという人はまず使う言語を決めて、勉強をして、それから取り組めばいいと思うんです。
私の場合、概念モデルまではいいとしても、なかなか先に進めなかったのはそこが原因。出来るのか出来ないのか、とかそうゆうのは置いておく。(たいてい、解決策はあるのです)
まずは、
「ソフトはrails,マイコンはmoxa,無線にするにはWiPort」と3つを決めました。理由は使ってる人が居たから、というシンプルな考え方です。技術に関する知識がないのにそんなカンタンに決めていいのかと言われそうですが、技術がないからこそ何か1つ選んで習得しないと行けないんです。だからここで使う技術というのはイコール自分が勉強したいというものでいいんです。私の場合、railsの勉強を始めてみると、あっと言う間に設計図もかけて、上手くいったというわけです。
とは言え、そうカンタンに設計図はかけません。だから2ヶ月で終わるものを、1年以上悩んでいる。なかなか進まないからといってくじけないでください。
いきづまったら決めちゃいましょう!どうしても覚えられない言語なり技術なら、そう分かった時点でかえればいい。
まずは何を使うか決めましょう。
flashですか?PHPですか?railsですか?
マイコンはGainerですか?Arduino?
通信はBlueTooth?Zigbee?Wiport?
まずは決まったら半分出来たと思って良いです。
2009年3月4日水曜日
Muliusお披露目〜シンポジウム〜
2月27,28日 代官山で行われたシンポジウムに来てくださった方、ありがとうございました。Muliusは今回、外部へは初お披露目だったので、かなり緊張しましたが、とても貴重な意見ばかりで嬉しかったです。
そしてこのblogでも何回も登場したMaking Things Talkのtom igoe氏もMuliusを使ってくれました。
無理矢理持たせてパチり☆
そしていろんな人がMuliusを体験して、意見をくださいました。
今回のシンポジウムに出ていたものの中で一番!と言ってくれる方もちらほらといらっしゃって、「いやぁそんな、、、」といいながら鼻が天狗になってしまいました。
音楽以外にも、kindleなどと連携して本のリストを交換したいという声もあったり。デバイスをプラットフォームとして、さまざまなサービスを提供することも考えたいと思いました。
そして、かなりの人に「本気でサービスとして提供する気はないの?」とも言われました。ここまで言われると、「あぁ、なんかすごい高評じゃないですか。。。」と感無量になると同時に、「やっぱりそうだよね、みんな使いたいよね。もったいないよね。」と悩みも深まることに。
結局、もう少し本気でビジネスとして成立させる方向を視野にいれて、入社までの時間を有意義に使って行こうと思いました。
もうちょっとだけ、Muliusとがんばっていきます。
そしてこのblogでも何回も登場したMaking Things Talkのtom igoe氏もMuliusを使ってくれました。
無理矢理持たせてパチり☆
そしていろんな人がMuliusを体験して、意見をくださいました。
今回のシンポジウムに出ていたものの中で一番!と言ってくれる方もちらほらといらっしゃって、「いやぁそんな、、、」といいながら鼻が天狗になってしまいました。
音楽以外にも、kindleなどと連携して本のリストを交換したいという声もあったり。デバイスをプラットフォームとして、さまざまなサービスを提供することも考えたいと思いました。
そして、かなりの人に「本気でサービスとして提供する気はないの?」とも言われました。ここまで言われると、「あぁ、なんかすごい高評じゃないですか。。。」と感無量になると同時に、「やっぱりそうだよね、みんな使いたいよね。もったいないよね。」と悩みも深まることに。
結局、もう少し本気でビジネスとして成立させる方向を視野にいれて、入社までの時間を有意義に使って行こうと思いました。
もうちょっとだけ、Muliusとがんばっていきます。
2009年2月22日日曜日
スイッチ 〜モーメンタリーとオルタネイト〜
Mulius デバイスのスイッチを作っていました。
スイッチを押すと電源が入ります。
ぴか!
ここまで来るのに、結構時間が掛かってしまいました(苦笑)なぜかというと、部品を購入するために秋葉原に出なくちゃいけなくて、しかも一回目は違った種類のスイッチを買って来てしまったから。
押しボタン式のスイッチには、「モーメンタリー」と「オルタネイト」という方式のものがあり、「モーメンタリー」を一回目は大量購入してしまったからです。。。。「モーメンタリー」は押している間だけしかonになりません。
それに気づいて本日、またしても秋葉原に言って来たわけです。二日連続秋葉原(笑)
かなりどうでもいいんですけど、最近、マルツにいっても「♪マルツ〜マルツ〜」って曲流れてないですよね?なんかちょっと寂しいです。
スイッチを押すと電源が入ります。
ぴか!
ここまで来るのに、結構時間が掛かってしまいました(苦笑)なぜかというと、部品を購入するために秋葉原に出なくちゃいけなくて、しかも一回目は違った種類のスイッチを買って来てしまったから。
押しボタン式のスイッチには、「モーメンタリー」と「オルタネイト」という方式のものがあり、「モーメンタリー」を一回目は大量購入してしまったからです。。。。「モーメンタリー」は押している間だけしかonになりません。
それに気づいて本日、またしても秋葉原に言って来たわけです。二日連続秋葉原(笑)
かなりどうでもいいんですけど、最近、マルツにいっても「♪マルツ〜マルツ〜」って曲流れてないですよね?なんかちょっと寂しいです。
2009年2月21日土曜日
Mulius ver3.0
WiPortは繊細?
日新システムズさん、ごめんなさい。この場であやまっても仕方ないのですが、WiPortの問題は解決しました。
今日、DNPでWiPortを使おうとした所、まったく接続出来なくなってしまい、あわてて日新システムズに問い合わせのメールを送りました。
(問い合わせは二回目。しかも回答をもらう前に、こちらで解決してしまいました。)そして今回もまた、WiPortのせいではなく、DNPのネット環境で使えなくなっていただけだと判明しました。今日はDNPのネットワークはちょっと不安定だったようです。数時間後、問題なく使えていました。
そういえばXportを使っていたときも、なんで接続できないんだ!と数日間悩んだあげく、ネットワーク環境のせいだったと分かって拍子抜けしたことがあったな〜。。。。
でも、WiPort使うのは結構シビアになってまいりました。ネットがかなり安定してないとダメなのに、本番は未知のネットワークですからねー。ドキドキだ
今日、DNPでWiPortを使おうとした所、まったく接続出来なくなってしまい、あわてて日新システムズに問い合わせのメールを送りました。
(問い合わせは二回目。しかも回答をもらう前に、こちらで解決してしまいました。)そして今回もまた、WiPortのせいではなく、DNPのネット環境で使えなくなっていただけだと判明しました。今日はDNPのネットワークはちょっと不安定だったようです。数時間後、問題なく使えていました。
そういえばXportを使っていたときも、なんで接続できないんだ!と数日間悩んだあげく、ネットワーク環境のせいだったと分かって拍子抜けしたことがあったな〜。。。。
でも、WiPort使うのは結構シビアになってまいりました。ネットがかなり安定してないとダメなのに、本番は未知のネットワークですからねー。ドキドキだ
2009年2月20日金曜日
一番簡単なストリーミングサーバーって?
Muliusのお披露目の場所となる、代官山ヒルサイドテラスではネットワークの外部接続が出来ないということが判明し、設計変更を余儀なくされました。
OrbAPIを使おうと思っていたのですが、Orbは、Orbを提供している会社のサーバーにする必要があるのです。う〜ん。。。
Darwinをインストールしようかとも思ったのですが、もっとカンタンな方法がありました。
macに元からApacheが入っているのだから、そこに音楽ファイルを置いて、ipod touchで再生すればいいじゃない!
1、ライブラリ>WebServer>Documents の中に音楽ファイルやらhtmlやらを置く。
2、システム環境設定で「共有」>「Web共有」を有効にする。
これだけ。
1、に関して。
ipod touchで再生できる音楽ファイル/動画ファイルの形式は決まっている。形式は調べると分かるので割愛。ここは変換しておく必要がある。私はiTuneで変換。
さらに便利なのがembedタグ。これを使えばipodtouchで再生出来ます。
これを足すだけ。
ipod touchから
http://ipアドレス/ルートとかフォルダ名
を入力すると、
こんな感じで、再生ボタンがあるだけのシンプルなもの。
再生を押してみると、
ちゃんと再生されます。
余談ですが、railsでembedタグを使うと、PCから見たときはちゃんと再生出来るのですが、ipod touchからだとリンク切れになっていました。なんでだろう。。。?
これがちゃんと出来たら、かなりイイ感じなのになぁ。。。。。
OrbAPIを使おうと思っていたのですが、Orbは、Orbを提供している会社のサーバーにする必要があるのです。う〜ん。。。
Darwinをインストールしようかとも思ったのですが、もっとカンタンな方法がありました。
macに元からApacheが入っているのだから、そこに音楽ファイルを置いて、ipod touchで再生すればいいじゃない!
1、ライブラリ>WebServer>Documents の中に音楽ファイルやらhtmlやらを置く。
2、システム環境設定で「共有」>「Web共有」を有効にする。
これだけ。
1、に関して。
ipod touchで再生できる音楽ファイル/動画ファイルの形式は決まっている。形式は調べると分かるので割愛。ここは変換しておく必要がある。私はiTuneで変換。
さらに便利なのがembedタグ。これを使えばipodtouchで再生出来ます。
<embed src="test.m4a" />
これを足すだけ。
ipod touchから
http://ipアドレス/ルートとかフォルダ名
を入力すると、
こんな感じで、再生ボタンがあるだけのシンプルなもの。
再生を押してみると、
ちゃんと再生されます。
余談ですが、railsでembedタグを使うと、PCから見たときはちゃんと再生出来るのですが、ipod touchからだとリンク切れになっていました。なんでだろう。。。?
これがちゃんと出来たら、かなりイイ感じなのになぁ。。。。。
2009年2月16日月曜日
Mulius WebApp ver2.1
リチウムイオン充電池 LI-355SP を使ってみた
このリチウムイオン充電池 LI-355SP かなり小さくていい感じ!
3.7vということで、このまま使ってしまってもWiPortは大丈夫なんじゃないかと思いつつも、三端子レギュレーターを通して置きました。LEDも鮮やかに光り、大変満足です。
しかし、昨日はこれが出来なかった。。。専用充電器というのが、隣に並べて千石で売られていたので購入した所、とてもファジーな代物でした。
充電が完了したら、LEDの色が赤から緑にかわる、と書いてあり、そのLEDの色に従うとまず充電は完了していません。
LEDの色は無視して、だいたい、1時間〜2時間くらい充電してあげるといいと思います。
値段は1つ3000円と高価ではありますが、乾電池よりも全然小さくて軽いので、電子工作にはうってつけだと思います。
2009年2月13日金曜日
rails ちょっとしたテク。~プロジェクトをフォルダごとコピペして、新しいプロジェクトを作る~
Railsの開発をしている時、「この状態を一度とっておいて、続きを別のプロジェクトとして作りたい」ってときがあると思います。例えば、test001を開発している時、test001をコピペしてtest002という名前に変えて開発を続けたい、って時とかです。
ただコピペするだけだと、DB/test001_developmentがtest002で上書きされちゃう。どうするかとおうと、database.ymlを編集するだけでいいんです。
test002に置き換えるだけです。これでtest001に上書きされません。migrateする前に、mysqlでDBを作るのを忘れないようにしましょう。(rakeファイルがあるなら、rake db:initializeをしてもいいかもしれません。)
ただコピペするだけだと、DB/test001_developmentがtest002で上書きされちゃう。どうするかとおうと、database.ymlを編集するだけでいいんです。
development:
adapter: mysql
encoding: utf8
database: test001_development//ここを編集
pool: 5
username: root
password:
socket: /tmp/mysql.sock
adapter: mysql
encoding: utf8
database: test001_development//ここを編集
pool: 5
username: root
password:
socket: /tmp/mysql.sock
test002に置き換えるだけです。これでtest001に上書きされません。migrateする前に、mysqlでDBを作るのを忘れないようにしましょう。(rakeファイルがあるなら、rake db:initializeをしてもいいかもしれません。)
2009年2月12日木曜日
Mulius WebApp ver2.0
以前、railsでのMulius WebAppの詳細を書くといっておきながら、手を付けていなかったので、Muliusの機能説明も合わせて、ここで書く事にします。
ユーザーが使える機能はざっと3つ
[1]作っているリストを見る
[2]これまでに作ったリストを見る
[3]お気に入りに登録したリストを見る
それぞれをどのように実装したか、詳しく書いて行きます。
[1]作っているリストを見る
マイコン・moxaとWiPortがセットになったMuliusデバイスを持つユーザー同士がすれ違った瞬間、、、、
1,moxa同士がradio通信を行って、信号を送り合う。
2,moxaはradio通信によって得た信号に応じて、serialSendでWiPortにHTTP POSTの文章を送る。(※c192.168.0.111:3000 ~ \r\n\r\n という文字列)
3,WiPortはmoxaから受け取った文字列をもとに、Railsで作ったMulius WebAppへHTTP POSTを行う。
4,Rails/Mulius WebAppでは、WiPortから送られて来たPOST要求を元に、DBへのレコードの更新を行う。
「すれ違い」DBを管理するencounter_controller.rbで以下のようなコードを書いて行った。
同様にac、ad、ba、bc、、、、とメソッドを用意しておく。railsのRESTFULLな特製を活かし、POST /encounter/ab とHTTPリクエストを送るだけで、ボディーにメッセージを入れなくともカンタンにDBにレコードを追加して行く事が出来る。
またJavaScriptで、このページのみ5秒間隔でリロードするようにしてあるので、あたかもすれ違った瞬間、リアルタイムで更新されているように見せている。
[2]これまでに作ったリストを見る
playlistテーブルから、いまログインしているユーザー=@current_userのIDを用いてfindする。
[3]お気に入りに登録したリストを見る
favoriteという結合テーブルを作って、userテーブルとplaylistテーブルを結合させた。フィールドはシンプル。
|id|user_id|playlist_id|
こちらも「作ったリスト」と同様、user_idからfindする。
というわけで、encounterの部分に手こずりましたが、他はいたってシンプルな構造になっています。レコードの管理になれたら、コレくらいのWebAppはさくっと作れるrailsの凄さ。でも動作がちょっと遅いのと、仕様が「?」な時があるのがタマにきずってところですかね?
でも、メディアデザインを専攻しているような学生、つまり私なんかにはこの開発スピードは何よりも美味しい。
まだまだ流行って欲しいところです。
ユーザーが使える機能はざっと3つ
[1]作っているリストを見る
[2]これまでに作ったリストを見る
[3]お気に入りに登録したリストを見る
それぞれをどのように実装したか、詳しく書いて行きます。
[1]作っているリストを見る
マイコン・moxaとWiPortがセットになったMuliusデバイスを持つユーザー同士がすれ違った瞬間、、、、
1,moxa同士がradio通信を行って、信号を送り合う。
2,moxaはradio通信によって得た信号に応じて、serialSendでWiPortにHTTP POSTの文章を送る。(※c192.168.0.111:3000 ~ \r\n\r\n という文字列)
3,WiPortはmoxaから受け取った文字列をもとに、Railsで作ったMulius WebAppへHTTP POSTを行う。
4,Rails/Mulius WebAppでは、WiPortから送られて来たPOST要求を元に、DBへのレコードの更新を行う。
このとき、すれ違ったユーザーがその時聞いていた曲と、書いていたメッセージをレコードにストックする必要がある。
ユーザーIDだけをレコードにためては、ユーザーの情報が変化してしまったとき、その時聞いていた曲
がころころ変わってしまうことになる。どうやったかというと、まず「すれ違い」のテーブルをmysqlに作った。フィールドは、id|user_id(すれちがったユーザーのID)|song_id(すれ違ったユーザーがその時聞いていた曲のID)|message(すれちがったユーザーのその時のメッセージ)|playlist_id(主体ユーザーが現在作っているプレイリスト)の5つ。「すれ違い」DBを管理するencounter_controller.rbで以下のようなコードを書いて行った。
#aとbがすれ違った時
def ab
@encounter = Encounter.new(params[:encounter])#新しいencounterを作ります
@user1 = User.find(1)#ユーザー1のID
@user2 = User.find(2)#ユーザー2のID
conditions = ["user_id=?", 1 ]
@playlist = Playlist.find(:first, :conditions => conditions, :order => "updated_at DESC" )
@playlistid = @playlist.id #いま作っているプレイリストを探し出し、関連づける
@encounter.user_id = @user2.id
@encounter.song_id = @user2.song_id#ユーザーbのその時の曲をそのままencounterのsong_idとする。
@encounter.message = @user2.message#ユーザーbのその時のメッセージをそのままencounterのmessageとする。
@encounter.playlist_id = @playlistid
#最終的に、いろいろな所から引っ張って来たデータを、encounterの中に入れる。
if @encounter.save
flash[:notice] = '新規登録完了'
redirect_to :action => 'index'
else
render :action => 'new'
end
end
同様にac、ad、ba、bc、、、、とメソッドを用意しておく。railsのRESTFULLな特製を活かし、POST /encounter/ab とHTTPリクエストを送るだけで、ボディーにメッセージを入れなくともカンタンにDBにレコードを追加して行く事が出来る。
またJavaScriptで、このページのみ5秒間隔でリロードするようにしてあるので、あたかもすれ違った瞬間、リアルタイムで更新されているように見せている。
[2]これまでに作ったリストを見る
playlistテーブルから、いまログインしているユーザー=@current_userのIDを用いてfindする。
def index
@search = params[:id]
conditions = ["user_id=?",@search]
@playlists = Playlist.find(:all, :conditions=> conditions )
end
[3]お気に入りに登録したリストを見る
favoriteという結合テーブルを作って、userテーブルとplaylistテーブルを結合させた。フィールドはシンプル。
|id|user_id|playlist_id|
こちらも「作ったリスト」と同様、user_idからfindする。
というわけで、encounterの部分に手こずりましたが、他はいたってシンプルな構造になっています。レコードの管理になれたら、コレくらいのWebAppはさくっと作れるrailsの凄さ。でも動作がちょっと遅いのと、仕様が「?」な時があるのがタマにきずってところですかね?
でも、メディアデザインを専攻しているような学生、つまり私なんかにはこの開発スピードは何よりも美味しい。
まだまだ流行って欲しいところです。
ipod touch/iphone CSS ~URL欄を消す~
ちょこちょことCSSでレイアウトを整えております。
ipod touchやiphoneでのインターフェイスで、URLが非常に気になっておりました。完全に消し去ることは出来ないのですが、隠すようには出来るので、自分もまねしてみました。
application.rhtmlを編集します。
ようは、JavaScriptを使って、URL欄が隠れる位置まで自動スクロールするという仕組みです。なので<%= yield :layout %>の中身はipod touch/iphoneの画面の長さ(420pxくらい)より長くなければなりません。heightで高さを指定してあげるといいと思いますよ。
ipod touchやiphoneでのインターフェイスで、URLが非常に気になっておりました。完全に消し去ることは出来ないのですが、隠すようには出来るので、自分もまねしてみました。
application.rhtmlを編集します。
<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
<title><% if @page_title%><%= h(@page_title)%> -- <% end -%>Mulius</title>
<%= stylesheet_link_tag 'base' %>
<script type="text/javascript">
<!--
window.onload = function() {
// for hide URL bar
setTimeout(scrollTo, 100, 0, 1);
}
// -->
</script>
</head>
<body>
<div>
<%= yield :layout %>
</div>
</body>
</html>
ようは、JavaScriptを使って、URL欄が隠れる位置まで自動スクロールするという仕組みです。なので<%= yield :layout %>の中身はipod touch/iphoneの画面の長さ(420pxくらい)より長くなければなりません。heightで高さを指定してあげるといいと思いますよ。
Rails + フィジカルコンピューティング ~WiPortやXportを使って、マイコンとrailsを連携~
前回のblogでも長々とMuliusの制作の上でたどった手順を書きましたが、もうちょっと簡潔にまとめて置いて、他のrailsプロジェクトと連携させるときや、Arduinoやその他自作のマイコンと連携させるときの為に役立てようと思います。
手順:
[1]Xport/WiPortの設定
[2]XPort/WiPortをシリアル接続で、TeraTerm等から操作する。
[3]Proce55ingから、シリアル経由でHTTPリクエストを行う。
[4]マイコンにリクエスト用のコードを書き込む。
こんな手順でいけば大丈夫かと思われます。
[1]Xport/WiPortの設定
このblogでもこちらやこちらでちょこっと書いてあり、もっと詳しく解説しているサイトもあるので、詳しくは書きませんが注意すべき点があります。ActiveConnectionの設定を、Manual Connectionにしておく事です。
「TeraTermでリクエスト文を打っても、一行にCが出てこない」という場合は、ここの設定が原因の場合が多いようです。
[2]XPort/WiPortをシリアル接続で、TeraTerm等から操作する。
railsプロジェクトの場合、以下のようなリクエスト文になると思われます。
Winでは\を¥に変える場合もあるようです。確かめてください。
TeraTermの設定で変えられるらしいのですが、Cでサーバーに接続した後はCtrl+M/Ctrl+Jが改行/復帰(復帰=キャリッジリターン:CR/改行=ラインフィード:LF)になります。
どこに使ったか、何回使ったかを必ず確認しましょう。CRのみの場合や、LFのみの場合、CRLF両方の場合があります。1つのリクエストの中で、CRのみを使う箇所と、CRLFを使う箇所がある場合もあります。1つでも違うと、リクエストは通りません。きちんと把握しましょう。
[3]Proce55ingから、シリアル経由でHTTPリクエストを行う。
お世話になりっぱなしのMakingThingsTalkのサイトに載っているプログラム(Lantronix serial-to-ethernet HTTP request tester)を使いましょう。
CRとLFに注意して、
ここで上手くいかなければ、TeraTermからやり直して、もう一度確認です。
このときCR/LFだけでなく、記号(:や/)にも注意してください。:を/に変えたり、\を¥にしたりなど。
成功したら、いよいよマイコンからHTTPリクエスト文をXPort/WiPortに送ります。
[4]マイコンにリクエスト用のコードを書き込む。
ほとんどproce55ingで使ったリクエスト文のまんまです。プリント用のメソッド名がそれぞれのマイコンによって違うので合わせてください。未確認ですが、Arduinoだったらこんな感じ?
マイコンによっては、アスキー表のコード番号からCRとLFを引っ張ってくる必要があったりもします。とりあえずは、Proce55ingで上手くいったコードをそのまま流用してからです。
こちらも参考にしながら、Rails + Xport/Wiport + マイコン によるフィジカルコンピューティングライフを楽しんでみてください。
手順:
[1]Xport/WiPortの設定
[2]XPort/WiPortをシリアル接続で、TeraTerm等から操作する。
[3]Proce55ingから、シリアル経由でHTTPリクエストを行う。
[4]マイコンにリクエスト用のコードを書き込む。
こんな手順でいけば大丈夫かと思われます。
[1]Xport/WiPortの設定
このblogでもこちらやこちらでちょこっと書いてあり、もっと詳しく解説しているサイトもあるので、詳しくは書きませんが注意すべき点があります。ActiveConnectionの設定を、Manual Connectionにしておく事です。
「TeraTermでリクエスト文を打っても、一行にCが出てこない」という場合は、ここの設定が原因の場合が多いようです。
[2]XPort/WiPortをシリアル接続で、TeraTerm等から操作する。
railsプロジェクトの場合、以下のようなリクエスト文になると思われます。
C192.168.0.111:3000
GET /main HTTP/1.1<^M^J>
HOST: 192.168.0.111<^M^J><^M^J>
Winでは\を¥に変える場合もあるようです。確かめてください。
TeraTermの設定で変えられるらしいのですが、Cでサーバーに接続した後はCtrl+M/Ctrl+Jが改行/復帰(復帰=キャリッジリターン:CR/改行=ラインフィード:LF)になります。
キャリッジリターン:CR/ラインフィード:LFは、とっても重要です!
どこに使ったか、何回使ったかを必ず確認しましょう。CRのみの場合や、LFのみの場合、CRLF両方の場合があります。1つのリクエストの中で、CRのみを使う箇所と、CRLFを使う箇所がある場合もあります。1つでも違うと、リクエストは通りません。きちんと把握しましょう。
[3]Proce55ingから、シリアル経由でHTTPリクエストを行う。
お世話になりっぱなしのMakingThingsTalkのサイトに載っているプログラム(Lantronix serial-to-ethernet HTTP request tester)を使いましょう。
CRとLFに注意して、
myPort.write("C192.168.0.111:3000\n");//ここはCRのみ
myPort.write("GET /main HTTP/1.1\r\n");//こちらはCRLFを一回
myPort.write("HOST: 192.168.0.111\r\n\r\n");//CRLFを二回
Railsの場合、接続は復帰=CR一回になります。改行=LFを足すと失敗します。接続した後は、CRLFにしないとまた失敗します。
注意しましょう。ここで上手くいかなければ、TeraTermからやり直して、もう一度確認です。
このときCR/LFだけでなく、記号(:や/)にも注意してください。:を/に変えたり、\を¥にしたりなど。
成功したら、いよいよマイコンからHTTPリクエスト文をXPort/WiPortに送ります。
[4]マイコンにリクエスト用のコードを書き込む。
Proce55ingで書いたものに忠実に、リクエスト文を出力するようにする。
これを守りましょう。どこから失敗するようになったか分からなくなってしまいますよ。以前のblogにも書いたので、かんたんに説明します。serialSend("c192.168.0.111:3000" + "\n");
serialSend("GET /main HTTP/1.1\r\n" + "\r\n");
serialSend("HOST: 192.168.0.111"+ "\r\n\r\n");
ほとんどproce55ingで使ったリクエスト文のまんまです。プリント用のメソッド名がそれぞれのマイコンによって違うので合わせてください。未確認ですが、Arduinoだったらこんな感じ?
Serial.print("c192.168.0.111:3000" + "\n");
Serial.print("GET /main HTTP/1.1\r\n" + "\r\n");
Serial.print("HOST: 192.168.0.111"+ "\r\n\r\n");
マイコンによっては、アスキー表のコード番号からCRとLFを引っ張ってくる必要があったりもします。とりあえずは、Proce55ingで上手くいったコードをそのまま流用してからです。
こちらも参考にしながら、Rails + Xport/Wiport + マイコン によるフィジカルコンピューティングライフを楽しんでみてください。
moxaに書き込むコード 09' その[2]
最終的にmoxaに書き込んだコードの全文です。
//for A
serialInit(9600);
pinMode(0, true);
digitalWrite(0,true);
ain1 = analogRead(1);
radioInit(0xDDDD, 0, 11, 2);
var checkb= 1;
var checkc= 1;
var checkd= 1;
var CR = String.fromCharCode(13);
var CRLF = String.fromCharCode(13, 10);
var c = "C192.168.0.111:3000";
var h = "HOST: 192.168.0.111";
var con = "Content-Type: application/x-wwwform-urlencoded";
var p1 = "POST /encounter/ab HTTP/1.1";
var p2 = "POST /encounter/ac HTTP/1.1";
var p3 = "POST /encounter/ad HTTP/1.1";
while(true) {
function onRadioReceive(seq,src,pan,data,rss) {
if (data == 'b' && checkb == 1){
serialSend(c + CR);
serialSend(p1 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checkb = 0;
checkc = 1;
checkd = 1;
}else if(data == 'c' && checkc == 1){
serialSend(c + CRLF);
serialSend(p2 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checkb = 1;
checkc = 0;
checkd = 1;
}else if(data == 'd' && checkd == 1){
serialSend(c + CRLF);
serialSend(p3 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 1;
checkb = 1;
checkd = 0;
}else{
}
}
radioSend(0xFFFF, 'a');
}
//for B
serialInit(9600);
pinMode(0, true);
digitalWrite(0,true);
ain1 = analogRead(1);
radioInit(0xDDDD, 0, 11, 2);
var checka= 1;
var checkc= 1;
var checkd= 1;
var CR = String.fromCharCode(13);
var CRLF = String.fromCharCode(13, 10);
var c = "C192.168.0.111:3000";
var h = "HOST: 192.168.0.111";
var con = "Content-Type: application/x-wwwform-urlencoded";
var p1 = "POST /encounter/ba HTTP/1.1";
var p2 = "POST /encounter/bc HTTP/1.1";
var p3 = "POST /encounter/bd HTTP/1.1";
while(true) {
function onRadioReceive(seq,src,pan,data,rss) {
if (data == 'a' && checka == 1){
serialSend(c + CR);
serialSend(p1 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 0;
checkc = 1;
checkd = 1;
}else if(data == 'c' && checkc == 1){
serialSend(c + CR);
serialSend(p2 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 1;
checkc = 0;
checkd = 1;
}else if(data == 'd' && checkd == 1){
serialSend(c + CR);
serialSend(p3 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 1;
checkc = 1;
checkd = 0;
}else{
}
}
radioSend(0xFFFF, 'b');
}
//for C
serialInit(9600);
pinMode(0, true);
digitalWrite(0,true);
ain1 = analogRead(1);
radioInit(0xDDDD, 0, 11, 2);
var checka= 1;
var checkb= 1;
var checkd= 1;
var CR = String.fromCharCode(13);
var CRLF = String.fromCharCode(13, 10);
var c = "C192.168.0.111:3000";
var h = "HOST: 192.168.0.111";
var con = "Content-Type: application/x-wwwform-urlencoded";
var p1 = "POST /encounter/ca HTTP/1.1";
var p2 = "POST /encounter/cb HTTP/1.1";
var p3 = "POST /encounter/cd HTTP/1.1";
while(true) {
function onRadioReceive(seq,src,pan,data,rss) {
if (data == 'a' && checka == 1){
serialSend(c + CR);
serialSend(p1 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 0;
checkb = 1;
checkd = 1;
}else if(data == 'b' && checkb == 1){
serialSend(c + CR);
serialSend(p2 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 1;
checkb = 0;
checkd = 1;
}else if(data == 'd' && checkd == 1){
serialSend(c + CR);
serialSend(p3 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 1;
checkb = 1;
checkd = 0;
}else{
}
}
radioSend(0xFFFF, 'c');
}
//for D
serialInit(9600);
pinMode(0, true);
digitalWrite(0,true);
ain1 = analogRead(1);
radioInit(0xDDDD, 0, 11, 2);
var checka= 1;
var checkb= 1;
var checkc= 1;
var CRLF = String.fromCharCode(13, 10);
var c = "C192.168.0.111:3000";
var h = "HOST: 192.168.0.111";
var con = "Content-Type: application/x-wwwform-urlencoded";
var p1 = "POST /encounter/da HTTP/1.1";
var p2 = "POST /encounter/db HTTP/1.1";
var p3 = "POST /encounter/dc HTTP/1.1";
while(true) {
function onRadioReceive(seq,src,pan,data,rss) {
if (data == 'a' && checka == 1){
serialSend(c + CR);
serialSend(p1 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 0;
checkb = 1;
checkc = 1;
}else if(data == 'b' && checkb == 1){
serialSend(c + CR);
serialSend(p2 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 1;
checkb = 0;
checkc = 1;
}else if(data == 'c' && checkd == 1){
serialSend(c + CR);
serialSend(p3 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
checka = 1;
checkb = 1;
checkc = 0;
}else{
}
}
radioSend(0xFFFF, 'd');
}
Mulius ver1.0 完成
今朝、ようやくハードも完成し、Mulius ver 1.0が完成しました!!!!!
長かった。。。でも、予定よりも早い完成で、嬉しい限りです。
苦労したのは、WiPort + Rails + マイコン(moxa)が、うまく連携してくれなかったこと。
WiPort + マイコンが上手くいっていないのか、Rails + WiPortが上手くいっていないのか、WiPort + Rails + マイコンを連携させる時に、不具合が起こるのか、どこで失敗するのかもうぐちゃぐちゃに。
そんなとき、Iさんに相談した所、以下のようなアドバイスを頂きました。
>足場を固めながら、論理的に問題を切り分けて行かないと、
>決してゴールにはたどり着けませんよ。
いい言葉です。。。自分の大雑把さを反省しました。コードはたった一文字で動かなかったりするんですよね。
そんなわけで、手順に関してもアドバイスを頂いたので、それをたどる事にしました。
>1 googleサーバから正しい反応が貰えるようなリクエスト文字列をTeratermで確認
>2 Processingでgoogleサーバに「全く同じ」リクエスト文字列を作り、確認
>3 moxaから「全く同じ」リクエスト文字列を送って確認
>4 Railsサーバから正しい反応が貰えるようなリクエスト文字列をTeratermで確認
>5 ProcessingでRailsサーバに「全く同じ」リクエスト文字列を作り、確認
>6 moxaから「全く同じ」リクエスト文字列を送って確認
それでは、手順をひとつずつ見て行きましょう。
[1]SFCサーバから正しい反応が貰えるようなリクエスト文字列をTeratermで確認
googleにリクエストを出すと、上手くいかない時があったので、大学のwebサイトのindexにGET要求を出す事にしました。
まずはSFCのIPアドレスを調べます。
digでIPアドレスを調べることが出来ますよ。調べたら、TeraTermで、HTTPリクエストを出してみます。
MakingThingsTalkという本を参考に、やってみました。
ポート指定の前は、MakingThingsTalkでは/を使っていました。/ではなく:ではないだろうか?という意見を頂いたのですが、/を使っても、:を使っても同じくサーバーと接続できました。なので、ひとまず:で統一することにしました。
少し気になっているのは、サーバーに接続した後は、Enterではなく^M^J(Ctrl-M,Ctrl-J)でCRLFを行っている事。MakingThingsTalkには書かれていたのですが、なぜ^M^Jでなくてはダメなのかは設定の問題と書いてありました。ちょっと気になる所でしたが、ともあれ、上記のリクエスト文で間違いなくGETできていました(200 OKも出ているので)
[2]ProcessingでSFCサーバに「全く同じ」リクエスト文字列を作り、確認
MakingThingTalkではTeraTermからではなく、Proce55ingから、シリアル接続でWiPortにリクエストを出せるプログラムが載っています。Processingのコードの中に大学のサイトのIPアドレスを入れます。
ちなみにこれは、何でもいいので、ボタンを押すと、イベントシーケンスを1つずつ実行してくれるプロジェクトです。
200 OKと出て、処理が行われました。改行は\nで良さそうです。MakingThingsTalkでは、Cの後は\rになっていたのでちょっと気になっていましたが、\nに変えても結果は変わらなかったので、\nで統一することにしました。(TeraTermで入力した文字列に忠実であるため)また、GET以降はTeraTermと合わせるため、\r\nとしましたが、\nでも問題なく動いていました。
myPort.write("GET /index.html HTTP/1.1\n");
myPort.write("HOST: www.sfc.keio.ac.jp\n\n");
ひとまずは\r\nで行く事にします。
[3]moxaから「全く同じ」リクエスト文字列を送って確認
確認の方法が少し面倒だったので、(MakingThingsTalk > Processingでサーバーを作る方法)
後回しにして、railsの方を進めてみました。
[4]Railsサーバから正しい反応が貰えるようなリクエスト文字列をTeratermで確認
mainページだと、かえってくるhtmlが長過ぎるので、loginページにリクエストを出して分かりやすくしました。
200 OKが出て、きちんとかえってきました。
[5]ProcessingでRailsサーバに「全く同じ」リクエスト文字列を作り、確認
Processingのコード・以下の三カ所を変更。
なんと今度は成功!ずっと失敗してたのに、、、、。
200 OKとでて、きちんと返してくれました。こちらはSFCの場合と異なり、\r\nとしなければ失敗するようです。(試しに\nでリクエストを出したところ、同じようなエラーが出ました。)
ひとつずつ確認していった事が功を奏したようです。POSTも同様に確かめてみました。
myPort.write("C192.168.0.111:3000\n");
myPort.write("GET /encounter HTTP/1.1\r\n");
myPort.write("HOST: 192.168.0.111\r\n\r\n");
こちらも成功していました。これは期待できるかも、、、、?!
[6] moxaから「全く同じ」リクエスト文字列を送って確認
長いので、全文は後ほど掲載します。
前回からの変更点のみ抜粋。
変数の宣言で、文字列指定しちゃいます。ポイントはString.fromCharCode。アスキーコードからCR(改行)とLF(復帰)を引っ張ってきます。
あとは、なんらかの信号を受け取った時(Muliusの場合、他のmoxa基盤からZigBeeで値を受け取った時)にserialSendでWiPortに上記の文字列を送るようにします。
いざ、、、moxaに書き込み、WiPortの電源を入れて、通信させてみます。
すると、railsサーバー側では以下の結果が!
ブラウザから見てみると、
出来てた〜!!!!!
ここまで丸三日間、、、本当にがんばりました。あとはガワやサイトのCSSを整えたりって感じです。もうちょっとだけがんばりますが、今日はblogを書いたりしてのんびり過ごします(笑)
長かった。。。でも、予定よりも早い完成で、嬉しい限りです。
苦労したのは、WiPort + Rails + マイコン(moxa)が、うまく連携してくれなかったこと。
WiPort + マイコンが上手くいっていないのか、Rails + WiPortが上手くいっていないのか、WiPort + Rails + マイコンを連携させる時に、不具合が起こるのか、どこで失敗するのかもうぐちゃぐちゃに。
そんなとき、Iさんに相談した所、以下のようなアドバイスを頂きました。
>足場を固めながら、論理的に問題を切り分けて行かないと、
>決してゴールにはたどり着けませんよ。
いい言葉です。。。自分の大雑把さを反省しました。コードはたった一文字で動かなかったりするんですよね。
そんなわけで、手順に関してもアドバイスを頂いたので、それをたどる事にしました。
>1 googleサーバから正しい反応が貰えるようなリクエスト文字列をTeratermで確認
>2 Processingでgoogleサーバに「全く同じ」リクエスト文字列を作り、確認
>3 moxaから「全く同じ」リクエスト文字列を送って確認
>4 Railsサーバから正しい反応が貰えるようなリクエスト文字列をTeratermで確認
>5 ProcessingでRailsサーバに「全く同じ」リクエスト文字列を作り、確認
>6 moxaから「全く同じ」リクエスト文字列を送って確認
それでは、手順をひとつずつ見て行きましょう。
[1]SFCサーバから正しい反応が貰えるようなリクエスト文字列をTeratermで確認
googleにリクエストを出すと、上手くいかない時があったので、大学のwebサイトのindexにGET要求を出す事にしました。
まずはSFCのIPアドレスを調べます。
$ dig www.sfc.keio.ac.jp
digでIPアドレスを調べることが出来ますよ。調べたら、TeraTermで、HTTPリクエストを出してみます。
C133.27.4.221:80
GET /index.html HTTP/1.1<^M^J>
HOST: www.sfc.keio.ac.jp<^M^J><^M^J>
MakingThingsTalkという本を参考に、やってみました。
ポート指定の前は、MakingThingsTalkでは/を使っていました。/ではなく:ではないだろうか?という意見を頂いたのですが、/を使っても、:を使っても同じくサーバーと接続できました。なので、ひとまず:で統一することにしました。
少し気になっているのは、サーバーに接続した後は、Enterではなく^M^J(Ctrl-M,Ctrl-J)でCRLFを行っている事。MakingThingsTalkには書かれていたのですが、なぜ^M^Jでなくてはダメなのかは設定の問題と書いてありました。ちょっと気になる所でしたが、ともあれ、上記のリクエスト文で間違いなくGETできていました(200 OKも出ているので)
[2]ProcessingでSFCサーバに「全く同じ」リクエスト文字列を作り、確認
MakingThingTalkではTeraTermからではなく、Proce55ingから、シリアル接続でWiPortにリクエストを出せるプログラムが載っています。Processingのコードの中に大学のサイトのIPアドレスを入れます。
ちなみにこれは、何でもいいので、ボタンを押すと、イベントシーケンスを1つずつ実行してくれるプロジェクトです。
import processing.serial.*;
Serial myPort; // Serial object
int step = 0; // which step in the process you're on
char linefeed = 10; // ASCII linefeed character
void setup()
{
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);
myPort.bufferUntil(linefeed);
}
void draw()
{
}
void serialEvent(Serial myPort) {
print(myPort.readString());
}
void keyReleased() {
switch (step) {
case 0:
myPort.write("C133.27.4.221:80\n");
step++;
break;
case 1:
myPort.write("GET /index.html HTTP/1.1\r\n");
myPort.write("HOST: www.sfc.keio.ac.jp\r\n\r\n");
step++;
break;
}
}
200 OKと出て、処理が行われました。改行は\nで良さそうです。MakingThingsTalkでは、Cの後は\rになっていたのでちょっと気になっていましたが、\nに変えても結果は変わらなかったので、\nで統一することにしました。(TeraTermで入力した文字列に忠実であるため)また、GET以降はTeraTermと合わせるため、\r\nとしましたが、\nでも問題なく動いていました。
myPort.write("GET /index.html HTTP/1.1\n");
myPort.write("HOST: www.sfc.keio.ac.jp\n\n");
ひとまずは\r\nで行く事にします。
[3]moxaから「全く同じ」リクエスト文字列を送って確認
確認の方法が少し面倒だったので、(MakingThingsTalk > Processingでサーバーを作る方法)
後回しにして、railsの方を進めてみました。
[4]Railsサーバから正しい反応が貰えるようなリクエスト文字列をTeratermで確認
mainページだと、かえってくるhtmlが長過ぎるので、loginページにリクエストを出して分かりやすくしました。
C192.168.0.111:3000
GET /login HTTP/1.1<^M^J>
HOST: 192.168.0.111<^M^J><^M^J>
200 OKが出て、きちんとかえってきました。
[5]ProcessingでRailsサーバに「全く同じ」リクエスト文字列を作り、確認
Processingのコード・以下の三カ所を変更。
myPort.write("C192.168.0.111:3000\n");
myPort.write("GET /encounter HTTP/1.1\r\n");
myPort.write("HOST: 192.168.0.111\r\n\r\n");
なんと今度は成功!ずっと失敗してたのに、、、、。
200 OKとでて、きちんと返してくれました。こちらはSFCの場合と異なり、\r\nとしなければ失敗するようです。(試しに\nでリクエストを出したところ、同じようなエラーが出ました。)
ひとつずつ確認していった事が功を奏したようです。POSTも同様に確かめてみました。
myPort.write("C192.168.0.111:3000\n");
myPort.write("GET /encounter HTTP/1.1\r\n");
myPort.write("HOST: 192.168.0.111\r\n\r\n");
こちらも成功していました。これは期待できるかも、、、、?!
[6] moxaから「全く同じ」リクエスト文字列を送って確認
長いので、全文は後ほど掲載します。
前回からの変更点のみ抜粋。
var CR = String.fromCharCode(13);
var CRLF = String.fromCharCode(13, 10);
var c = "C192.168.0.111:3000";
var h = "HOST: 192.168.0.111";
var con = "Content-Type: application/x-wwwform-urlencoded";
var p1 = "POST /encounter/ab HTTP/1.1";
var p2 = "POST /encounter/ac HTTP/1.1";
var p3 = "POST /encounter/ad HTTP/1.1";
変数の宣言で、文字列指定しちゃいます。ポイントはString.fromCharCode。アスキーコードからCR(改行)とLF(復帰)を引っ張ってきます。
あとは、なんらかの信号を受け取った時(Muliusの場合、他のmoxa基盤からZigBeeで値を受け取った時)にserialSendでWiPortに上記の文字列を送るようにします。
serialSend(c + CR);
serialSend(p1 + CRLF);
serialSend(h + CRLF);
serialSend(con + CRLF + CRLF);
いざ、、、moxaに書き込み、WiPortの電源を入れて、通信させてみます。
すると、railsサーバー側では以下の結果が!
ブラウザから見てみると、
出来てた〜!!!!!
ここまで丸三日間、、、本当にがんばりました。あとはガワやサイトのCSSを整えたりって感じです。もうちょっとだけがんばりますが、今日はblogを書いたりしてのんびり過ごします(笑)
2009年2月9日月曜日
moxaに書き込むコード 09' その[1]
お久しぶりです。
なんだかんだで、Muliusのソフトウェアは完成しました。あとはハードウェアの作成です!(ソフトウェアが最終的にどんなものになったかは後日)
しばらくぶりに、moxaと格闘中。まずは、すれ違った人から、何度も値を受け取らないようにするため、checkというbooleanに使える変数を用意したコード。
これはA用コード
これはB用
これはC用
これはD用
いまはmoxaが2台しかないので、aとbしか受け取っていないのですが、ターミナルから見てみるとこんな感じ。
なんだかんだで、Muliusのソフトウェアは完成しました。あとはハードウェアの作成です!(ソフトウェアが最終的にどんなものになったかは後日)
しばらくぶりに、moxaと格闘中。まずは、すれ違った人から、何度も値を受け取らないようにするため、checkというbooleanに使える変数を用意したコード。
これはA用コード
//for A
serialInit(9600);
pinMode(0, true);
digitalWrite(0,true);
ain1 = analogRead(1);
radioInit(0xDDDD, 0, 11, 3);
var checkb= 1;
var checkc= 1;
var checkd= 1;
while(true) {
function onRadioReceive(seq,src,pan,data,rss) {
if (data == 'b' && checka == 1){
serialSend("a"+"\r\n");
checkb = 0;
checkc = 1;
checkd = 1;
}else if(data == 'c' && checkb == 1){
serialSend("c"+"\r\n");
checkb = 1;
checkc = 0;
checkd = 1;
}else if(data == 'd' && checkd == 1){
serialSend("d"+"\r\n");
checka = 1;
checkb = 1;
checkd = 0;
}else{
}
}
radioSend(0xFFFF, 'a');
}
これはB用
//for B
serialInit(9600);
pinMode(0, true);
digitalWrite(0,true);
ain1 = analogRead(1);
radioInit(0xDDDD, 0, 11, 3);
var checka= 1;
var checkc= 1;
var checkd= 1;
while(true) {
function onRadioReceive(seq,src,pan,data,rss) {
if (data == 'a' && checka == 1){
serialSend("a"+"\r\n");
checka = 0;
checkc = 1;
checkd = 1;
}else if(data == 'c' && checkb == 1){
serialSend("c"+"\r\n");
checka = 1;
checkc = 0;
checkd = 1;
}else if(data == 'd' && checkd == 1){
serialSend("d"+"\r\n");
checka = 1;
checkc = 1;
checkd = 0;
}else{
}
}
radioSend(0xFFFF, 'b');
}
serialInit(9600);
pinMode(0, true);
digitalWrite(0,true);
ain1 = analogRead(1);
radioInit(0xDDDD, 0, 11, 3);
var checka= 1;
var checkc= 1;
var checkd= 1;
while(true) {
function onRadioReceive(seq,src,pan,data,rss) {
if (data == 'a' && checka == 1){
serialSend("a"+"\r\n");
checka = 0;
checkc = 1;
checkd = 1;
}else if(data == 'c' && checkb == 1){
serialSend("c"+"\r\n");
checka = 1;
checkc = 0;
checkd = 1;
}else if(data == 'd' && checkd == 1){
serialSend("d"+"\r\n");
checka = 1;
checkc = 1;
checkd = 0;
}else{
}
}
radioSend(0xFFFF, 'b');
}
これはC用
//for C
serialInit(9600);
pinMode(0, true);
digitalWrite(0,true);
ain1 = analogRead(1);
radioInit(0xDDDD, 0, 11, 3);
var checka= 1;
var checkb= 1;
var checkd= 1;
while(true) {
function onRadioReceive(seq,src,pan,data,rss) {
if (data == 'a' && checka == 1){
serialSend("a"+"\r\n");
checka = 0;
checkb = 1;
checkd = 1;
}else if(data == 'b' && checkb == 1){
serialSend("b"+"\r\n");
checka = 1;
checkb = 0;
checkd = 1;
}else if(data == 'd' && checkd == 1){
serialSend("d"+"\r\n");
checka = 1;
checkb = 1;
checkd = 0;
}else{
}
}
radioSend(0xFFFF, 'c');
}
これはD用
//for D
serialInit(9600);
pinMode(0, true);
digitalWrite(0,true);
ain1 = analogRead(1);
radioInit(0xDDDD, 0, 11, 3);
var checka= 1;
var checkb= 1;
var checkc= 1;
while(true) {
function onRadioReceive(seq,src,pan,data,rss) {
if (data == 'a' && checka == 1){
serialSend("a"+"\r\n");
checka = 0;
checkb = 1;
checkc = 1;
}else if(data == 'b' && checkb == 1){
serialSend("b"+"\r\n");
checka = 1;
checkb = 0;
checkc = 1;
}else if(data == 'c' && checkd == 1){
serialSend("c"+"\r\n");
checka = 1;
checkb = 1;
checkc = 0;
}else{
}
}
radioSend(0xFFFF, 'd');
}
いまはmoxaが2台しかないので、aとbしか受け取っていないのですが、ターミナルから見てみるとこんな感じ。
2009年2月3日火曜日
Wi-portからHTTP POST
Wi-portからHTTP POSTすることを、ずいぶん試しているのですが出来ません。
作ったプロジェクトはこんなもの。
プロジェクトを作った後は、modelを作ってstring型のnameとtext型のmessageというカラムを追加しました。
migrationファイル:XXXXXXXXX_create_users.rb
userというコントローラーを作り、index、new、destroy、createを追加。フォームも作って投稿出来るようにしました。
user_controller
index.rhtml
new.rhtml
ソースをのぞいてみると、
ここと
id="user_name" name="user[name]"
ここが
id="user_message" name="user[message]"
キモのようです。これを返せばいいんですよね、きっと。
wi-portでhttp postしてみましょう。
シリアル変換をしてtera termで
※Enterの代わりにCntrl + M, CntrlJ を打ちます。= [^M^J]
※Making Things Talk参照
しかし途中でdisconnectになってしまいます。
試しにコマンドプロンプトから
成功しません。サーバー側のステータスコードを見てみると、
なぜか[GET]メソッドになっている。。。もうこればっかりやっていて、気が狂いそうになっていた所で、キョンちゃんがやってくれました。
最後のContent-Typeを指定する文章を書き足すと、POSTが成功するようです。
しかし、
ここは送れないようです。[ ]を変換する必要があるのかな?
作ったプロジェクトはこんなもの。
rails -d mysql posttest
プロジェクトを作った後は、modelを作ってstring型のnameとtext型のmessageというカラムを追加しました。
ruby script/generate model user
migrationファイル:XXXXXXXXX_create_users.rb
t.column :name, :string
t.column :message, :text
userというコントローラーを作り、index、new、destroy、createを追加。フォームも作って投稿出来るようにしました。
ruby script/generate controller user index new show create
user_controller
def index
@users = User.find(:all)
end
def create
@user = User.new(params[:user])#上のnewでの値を受け取っています。
if@user.save
redirect_to :action => 'index'
else
render :action => 'new'
end
end
def new
end
def destroy
@user = User.find(params[:id])
@user.destroy
flash[:notice] = '削除しました'
redirect_t
index.rhtml
<h1>Users#index</h1>
<div class ="notice"><%= h(flash[:notice])%></div>
<p><%= link_to('新規ユーザー作成', :action => 'new')%></p>
<% @users.each do |user| -%>
<li>
<%= link_to(h(user.name), :action => 'show', :id => user.id)%>
<%= link_to('削除', {:action => 'destroy', :id => user.id},
{:method => :post, :confirm => '本当に削除しますか?'})%>
</li>
<% end -%>
new.rhtml
<h1>Users#new#新しいユーザーを作る</h1>
<% form_for :user, @user,
:url=>{:action => 'create'} do |form| %>
<p>名前: <%=form.text_field :name, :size => 16 %> </p>
<p>メッセージ:<br /><%=form.text_area :message, :colse =>40, :rows => 3%> </p>
<p>
<%= form.submit 'Create' %>
</p>
<% end %>
<p><%= link_to('一覧へ戻る', :action => 'index') %></p>
ソースをのぞいてみると、
<h1>Users#new#新しいユーザーを作る</h1>
<form action="/user/create" method="post"><div style="margin:0;padding:
0"><input name="authenticity_token" type="hidden"
value="3459c27ed8923e8483d23bd0b4a8a870f248bc56" /></div>
<p>名前: <input id="user_name" name="user[name]" size="16"
type="text" /> </p>
<p>メッセージ:<br /><textarea cols="40" colse="40"
id="user_message" name="user[message]" rows="3"></textarea> </p>
<p>
<input id="user_submit" name="commit" type="submit" value="Create" />
</p>
</form>
<p><a href="/user">一覧へ戻る</a></p>
ここと
id="user_name" name="user[name]"
ここが
id="user_message" name="user[message]"
キモのようです。これを返せばいいんですよね、きっと。
wi-portでhttp postしてみましょう。
シリアル変換をしてtera termで
C192.168.0.111:3000
POST /user/create HTTP/1.1 ^M^J
HOST: 192.168.0.111:3000 ^M^J
user[name]=hoge&user[message]=hoge ^M^J
※Enterの代わりにCntrl + M, CntrlJ を打ちます。= [^M^J]
※Making Things Talk参照
しかし途中でdisconnectになってしまいます。
試しにコマンドプロンプトから
telnet 192.168.0.111 3000
POST /user/create HTTP/1.1
HOST: 192.168.0.111 3000
user[name]=hoge&user[message]=hoge
成功しません。サーバー側のステータスコードを見てみると、
Processing UserController#index (for 192.168.0.111 at 2009-02-03 20:38:01) [GET]
SQL (0.1ms) SET NAMES 'utf8'
SQL (0.1ms) SET SQL_AUTO_IS_NULL=0
User Load (0.7ms) SELECT * FROM `users`
Rendering user/index
User Columns (3.0ms) SHOW FIELDS FROM `users`
Completed in 69ms (View: 63, DB: 1) | 200 OK [http://192.168.0.111/user]
なぜか[GET]メソッドになっている。。。もうこればっかりやっていて、気が狂いそうになっていた所で、キョンちゃんがやってくれました。
POST /user/create HTTP/1.1 ^M^J
HOST: 192.168.0.111 ^M^J
Content-Type: application/x-wwwform-urlencoded
最後のContent-Typeを指定する文章を書き足すと、POSTが成功するようです。
しかし、
user[name]=hoge&user[message]=hoge
ここは送れないようです。[ ]を変換する必要があるのかな?
2009年1月27日火曜日
Ruby on Rails チュートリアル(3) 補足:ログアウト機能とeditとnew
チュートリアル(3)ではログアウトメソッドはあったものの、viewに出力していなかったためログアウト出来ない状態でした。また、editとnewも、ログイン名とパスワードを追加して、使えるようにしなくてはなりません。
まずはログアウトを、user/indexから出来るようにします。
view>users>index.rhtml.erbに以下のコードを追加。
新しいユーザーを追加出来るようにnew.rhtml.erbとedit.rhtml.erbの編集。それぞれに以下のコードを追加します。
これだけではまだ使えません。models>user.rbを編集。以下のコードを追加。
これで完成!
おまけ:
プロジェクト全体のindexページを変えたい場合、つまり「Welcome aboard」ページ以外をトップにしたい場合の話。
まずpublic>index.htmlを削除して、
config>routes.rbに以下のコード追加。
これで、http://localhost:3000にアクセスした時、user indexがトップになります。
まずはログアウトを、user/indexから出来るようにします。
view>users>index.rhtml.erbに以下のコードを追加。
<% if @current_user -%>
<%= @current_user.user_name %> さんのアカウント |
<%= link_to 'ログアウト',
{ :controller => '/login', :action => 'logout' },
{ :method => 'post',
:confirm => '本当にログアウトしますか?' } -%>
<% end -%>
新しいユーザーを追加出来るようにnew.rhtml.erbとedit.rhtml.erbの編集。それぞれに以下のコードを追加します。
<p>ログイン名: <%=form.text_field :login_name, :size => 16 %></p>
<p>パスワード: <%=form.password_field :password, :size => 16%></p>
これだけではまだ使えません。models>user.rbを編集。以下のコードを追加。
attr_accessor :password, :password_confirmation
attr_protected :salt, :hashed_password
# パスワードが送られたとき
def password=(pw)
@password = pw
if pw and pw.size > 0
self.salt = rand(100000000)
self.hashed_password = User.hashed_password(pw, self.salt)
end
end
これで完成!
おまけ:
プロジェクト全体のindexページを変えたい場合、つまり「Welcome aboard」ページ以外をトップにしたい場合の話。
まずpublic>index.htmlを削除して、
config>routes.rbに以下のコード追加。
map.root :controller => "users"
これで、http://localhost:3000にアクセスした時、user indexがトップになります。
Ruby on Rails (4) ~テーブル同士の連携、1対多編~
今回は複数のテーブルを連携させてみましょう。
前に作ったtest003(チュートリアル(2))を使います。
songというテーブルを作って、userテーブルで読み込みます。
まずはmodelの作成
XXXXXX_create_songsを編集します。
次はymlの編集。フィクスチャファイルsongs.ymlをdb>fixtures>decelopmentに作ります。
完成したら
では、連携させましょう。
app>modelsの中のuser.rbとsong.rbをそれぞれ編集します。
user.rb
song.rb
belopgs_toで、そのデータベースからは1つのデータとしか対応していないことを表し、has_manyで複数のデータと対応していることを示します。
song対userが1対多の関係になっています。1対1ではないのは、同じ曲を聴いている人もいるからです。
しかし、これだけではまだまだ。外部キーというものをテーブルの中につくって、ようやくテーブルからテーブルへデータを引き渡せるのです。
マイグレーション用のモデル、XXXXXXXX_create_users.rbを編集して、外部キーを新しく設けます。
ここを消して、
これを代入します。
これでuserを通してsongのデータベースを引っ張って来れるようになりました。
最後にviewの編集です。
といってもこれまで
テーブル名.テーブル名.フィールド名でデータを持って来れるという簡単さ!!!!
前に作ったtest003(チュートリアル(2))を使います。
songというテーブルを作って、userテーブルで読み込みます。
まずはmodelの作成
ruby script/generate model song
XXXXXX_create_songsを編集します。
class CreateSongs < ActiveRecord::Migration
def self.up
create_table :songs do |t|
t.column :song_name, :string # 曲名
t.column :artist_name, :string # アーティスト
t.column :song_url, :string # URL
t.timestamps
end
end
def self.down
drop_table :songs
end
end
次はymlの編集。フィクスチャファイルsongs.ymlをdb>fixtures>decelopmentに作ります。
# 開発環境のためのフィクスチャ: songs
one:
id: 1
song_name: test1
artist_name: さとう # アーティスト
song_url: http://google.co.jp # URL
created_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
updated_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
two:
id: 2
song_name: test2
artist_name: やまだ # アーティスト
song_url: http://google.co.jp # URL
created_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
updated_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
three:
id: 3
song_name: test3
artist_name: すずき # アーティスト
song_url: http://google.co.jp # URL
created_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
updated_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
完成したら
rake db:initialize
では、連携させましょう。
app>modelsの中のuser.rbとsong.rbをそれぞれ編集します。
user.rb
class User < ActiveRecord::Base
belongs_to :song
end
song.rb
class Song < ActiveRecord::Base
has_many :users
end
belopgs_toで、そのデータベースからは1つのデータとしか対応していないことを表し、has_manyで複数のデータと対応していることを示します。
song対userが1対多の関係になっています。1対1ではないのは、同じ曲を聴いている人もいるからです。
しかし、これだけではまだまだ。外部キーというものをテーブルの中につくって、ようやくテーブルからテーブルへデータを引き渡せるのです。
マイグレーション用のモデル、XXXXXXXX_create_users.rbを編集して、外部キーを新しく設けます。
t.column :listening_song, :string
ここを消して、
t.column :song_id, :integer # 外部キー
これを代入します。
これでuserを通してsongのデータベースを引っ張って来れるようになりました。
最後にviewの編集です。
といってもこれまで
@user.listening_song
と記述していた所を、@user.song.song_name
と変えるだけです!テーブル名.テーブル名.フィールド名でデータを持って来れるという簡単さ!!!!
2009年1月26日月曜日
Ruby on Rails チュートリアル(3) ~pluginを使わずにログイン機能を作ってみよう~
ちょこっとやってみたらものの数分でログイン/セッション機能が完成して、とても嬉しくなりました。プラグインのおかげです。railsって本当に素晴らしい。
が、これではいつまでたってもRailsでのログイン設計を理解できるようになりません。悩みましたが、プラグインを使わずにログイン機能を作るチュートリアルにします!長くなりますが、頑張りましょう!!!このブログの順番がごちゃごちゃですがtest003(チュートリアル(4))を使います。失敗する恐れもありますので、同じ手順でtest004を今回新たに作り直しました。
ログインしないと、ユーザーデータが見れないようにします。
ログイン機能を作るための手順です。
(1) テーブルにフィールドを追加する(ログイン名とパスワード)
(2) user.rb modelの編集
(3) ymlの編集
(4) login controllerとview(ログインのindexページ)を作る
(5) application.rbの編集
(6) users_controllerの編集
さあ張り切って行きましょう。
(1) テーブルにフィールドを追加する(ログイン名とパスワード)
ログイン名とパスワード追加用のマイグレーションファイルを作ります。
中身はこんな感じです。パスワードは暗号化します。
db>migrate>XXXXXXXX_alter_users.rb
(2) user.rb modelの編集
入力されるパスワードを暗号化する=ハッシュ値を作るため、modelを編集します。
app>models>user.rb
(3) ymlの編集
フィクスチャデータを編集。
この三行を追加してください。
user.ymlに追加
ここまで来たら、データの投入です。
(4) login controllerとview(ログインのindexページ)を作る
それでは、ログイン用のフォームを作りましょう。
login_controller.rb
login>index.rhtml.erb
(5) application.rbの編集
ログイン状態の確認を、すべてのコントローラーで使うため、application.rbを編集します。
controller>application.rb
(6) users_controllerの編集
class UsersController < ApplicationControllerの下に以下のコードを追加します。
これで完成!serverを立ち上げて、usersに接続しようとすると、ログインページに飛ばされるはずです。
が、これではいつまでたってもRailsでのログイン設計を理解できるようになりません。悩みましたが、プラグインを使わずにログイン機能を作るチュートリアルにします!長くなりますが、頑張りましょう!!!このブログの順番がごちゃごちゃですがtest003(チュートリアル(4))を使います。失敗する恐れもありますので、同じ手順でtest004を今回新たに作り直しました。
ログインしないと、ユーザーデータが見れないようにします。
ログイン機能を作るための手順です。
(1) テーブルにフィールドを追加する(ログイン名とパスワード)
(2) user.rb modelの編集
(3) ymlの編集
(4) login controllerとview(ログインのindexページ)を作る
(5) application.rbの編集
(6) users_controllerの編集
さあ張り切って行きましょう。
(1) テーブルにフィールドを追加する(ログイン名とパスワード)
ログイン名とパスワード追加用のマイグレーションファイルを作ります。
$ ruby script/generate migration alter_users
中身はこんな感じです。パスワードは暗号化します。
db>migrate>XXXXXXXX_alter_users.rb
class AlterUsers < ActiveRecord::Migration
def self.up
add_column :users, :login_name, :string, # ログイン名
:null => false
add_column :users, :hashed_password, :string
# 暗号化されたパスワード
add_column :users, :salt, :string # パスワードソルト
end
def self.down
remove_column :users, :login_name
remove_column :users, :hashed_password
remove_column :users, :salt
end
end
(2) user.rb modelの編集
入力されるパスワードを暗号化する=ハッシュ値を作るため、modelを編集します。
app>models>user.rb
class User < ActiveRecord::Base
belongs_to :song
attr_accessor :password, :password_confirmation
attr_protected :salt, :hashed_password
def self.authenticate(login_name, password)
user = find_by_login_name(login_name)
if user and user.hashed_password ==
hashed_password(password, user.salt)
user
else
nil
end
end
# ハッシュ値の生成
def self.hashed_password(password, salt)
Digest::SHA1.hexdigest(sprintf("%s%08d", password, salt))
end
end
(3) ymlの編集
フィクスチャデータを編集。
この三行を追加してください。
user.ymlに追加
login_name: user1(userごとに、ここは変える必要があります。)
hashed_password: <%= User.hashed_password('password', 12345678) %>
salt: 12345678
ここまで来たら、データの投入です。
rake db:migrate
(4) login controllerとview(ログインのindexページ)を作る
それでは、ログイン用のフォームを作りましょう。
$ ruby script/generate controller login index
login_controller.rb
class LoginController < ApplicationController
# ログイン
def login
login_name = params[:login_name]
password = params[:password]
user = User.authenticate(login_name, password)
if user
session[:user_id] = user.id
redirect_to :controller => 'users', :action => 'index'
flash[:notice] = "Logged in successfully"
else
session[:user_id] = nil
redirect_to :controller => 'login', :action => 'index'
flash[:warning] = 'ログイン失敗'
flash[:login_name] = login_name
end
end
# ログアウト
def logout
session[:user_id] = nil
redirect_to :controller => 'login', :action => 'index'
end
end
login>index.rhtml.erb
<% unless @current_user -%>
<div>
<h1>ログイン</h1>
<% form_tag '/login/login', :method => 'post' do %>
<%= hidden_field_tag 'from', request.request_uri %>
<table border="0">
<tr><td align="right">ユーザー名:</td>
<td><%= text_field_tag 'login_name', flash[:login_name],
:size => 16 %></td></tr>
<tr><td align="right">パスワード:</td>
<td><%= password_field_tag 'password', '',
:size => 16 %></td></tr>
<tr><td colspan="2" align="center">
<%= submit_tag 'ログイン' %>
</td></tr>
</table>
<% end %>
</div>
<% end -%>
<% if flash[:warning] -%>
<div id="warning">
<%= flash[:warning] %>
</div>
<% end -%>
(5) application.rbの編集
ログイン状態の確認を、すべてのコントローラーで使うため、application.rbを編集します。
controller>application.rb
class ApplicationController < ActionController::Base
helper :all
protect_from_forgery # :secret => 'b9df6040833a6d4befdb3d8b5fa52082'
before_filter :resume_session
private
# セッションの再開
def resume_session
return unless session[:user_id]
begin
@current_user = User.find(session[:user_id])
rescue ActiveRecord::RecordNotFound
session[:user_id] = nil
end
end
# ログインしていないユーザーをはじく
def block_non_users
unless @current_user
flash[:warning] = 'ログインが必要です。'
redirect_to :controller => 'login', :action => 'index'
return false
end
end
end
(6) users_controllerの編集
class UsersController < ApplicationControllerの下に以下のコードを追加します。
before_filter :block_non_users
これで完成!serverを立ち上げて、usersに接続しようとすると、ログインページに飛ばされるはずです。
2009年1月23日金曜日
Ruby on Rails チュートリアル(2) 〜投稿、編集、削除まで〜
前回作ったものを元に、新しいユーザーを追加したり、情報を編集したり、削除したりできるようにします。
さっそく作ろう、という前にちょっとお話。
データベースの基本操作はCRUD/Create, Read, Update, Deleteの4つから成り立っているそうです。この4つをRailsで実現するには7つのアクションを用意するのが一般的。
7つ・・・・・index, show, new, edit, create, update, destroy
なんとなく名前から、それぞれがどんな役割を担うか分かると思います。
それでは「user_controller.rb」の編集から。
7つのアクションを編集しました。
次はそれぞれのViewを編集していきます。
まずはindex.rhtml.erb
次に、edit.rhtml.erb
次はnew.rhtml.erb
これで完成。
私がつまずいていたのは
の記述方法。URL => 'アクション名'は、editはupdate/newはcreateになります。
さっそく作ろう、という前にちょっとお話。
データベースの基本操作はCRUD/Create, Read, Update, Deleteの4つから成り立っているそうです。この4つをRailsで実現するには7つのアクションを用意するのが一般的。
7つ・・・・・index, show, new, edit, create, update, destroy
なんとなく名前から、それぞれがどんな役割を担うか分かると思います。
それでは「user_controller.rb」の編集から。
class UsersController < ApplicationController
def index
@users = User.find(:all)
end
def show
@user = User.find(params[:id])
end
#indexとshowは前回と同じです。
def new
@user = User.new
end
#モデルクラス名.newで新しいレコード作成
def edit
@user = User.find(params[:id])
end
#showと同じ
#新規作成用フォーム
def create
@user = User.new(params[:user])#上のnewでの値を受け取っています。
if@user.save
flash[:notice] = '新しいユーザーが追加されました!'
redirect_to :action => 'show' , :id => @user #処理が終わったら新規作成したユーザーのshow/(id)へ
else
render :action => 'new'
end
end
#flashで、画面に処理表示の結果を出力することができます。
def update
@user = User.find(params[:id])
@user.attributes = params[:user]
@user.save
if@user.save
flash[:notice] = '情報が更新されました'
redirect_to :action => 'show' , :id => @user#処理が終わったら,更新したページ=show/(id)へ
else
render :action => 'edit'
end
end
#editの値をうけとってupdateしています。
def destroy
@user = User.find(params[:id])
@user.destroy
flash[:notice] = '削除しました'
redirect_to :action => 'index'#処理が終わったらindexへ
end
end
7つのアクションを編集しました。
次はそれぞれのViewを編集していきます。
まずはindex.rhtml.erb
<h1>Test003: Users : indexページ</h1>
<div class ="notice"><%= h(flash[:notice])%></div>#Flashによる、処理結果の表示
<p><%= link_to('新規ユーザー作成', :action => 'new')%></p>
<% @users.each do |user| -%>
<li>
<%= link_to(h(user.user_name), :action => 'show', :id => user.id)%>
<%= link_to('編集', :action => 'edit', :id => user.id)%>
<%= link_to('削除', {:action => 'destroy', :id => user.id},
{:method => :post, :confirm => '本当に削除しますか?'})%>
</li>
<% end -%>
次に、edit.rhtml.erb
<h1>Members#edit#ユーザーデータを編集する</h1>
<% form_for :user, @user,
:url=>{:action => 'update', :id => @user} do |form| %>
<p>名前: <%=form.text_field :user_name, :size => 16 %> </p>
<p>曲: <%=form.text_field :listening_song, :size => 16 %> </p>
<p>メッセージ:<br /><%=form.text_area :message, :colse =>40, :rows => 3%> </p>
<p>
<%= form.submit '更新' %>
</p>
<% end %>
<p><%= link_to('一覧へ戻る', :action => 'index') %></p>
次はnew.rhtml.erb
<h1>Users#new#新しいユーザーを作る</h1>
<% form_for :user, @user,
:url=>{:action => 'create'} do |form| %>
<p>名前: <%=form.text_field :user_name, :size => 16 %> </p>
<p>曲: <%=form.text_field :listening_song, :size => 16 %> </p>
<p>メッセージ:<br /><%=form.text_area :message, :colse =>40, :rows => 3%> </p>
<p>
<%= form.submit 'Create' %>
</p>
<% end %>
<p><%= link_to('一覧へ戻る', :action => 'index') %></p>
これで完成。
私がつまずいていたのは
form_for
の記述方法。URL => 'アクション名'は、editはupdate/newはcreateになります。
補足:チュートリアル(1) もう一回フィールドを作り直したい場合
前回のblogが大変長くなりましたので、マイグレーション関係の補足。
一度、migrateしてしまうと、簡単にはやりなおせません。
方法は3つ
1,DBを一から作り直す
2,バージョンを増やしてマイグレーションスクリプトを作り直した後、マイグレーションを行う。
3,initializing.rakeという初期化用ファイルを使う
1,の場合
mysqlでデータベースを削除(drop データベース名;)した後、もう一度データベースを作り、マイグレーションし直す。めんどくさい(笑)
2,の場合
002_テーブル名.rbと名前をつけてマイグレーションするというもの。しかし、rails2.0以降、この仕様は変更されたので、上手くいくか不明。未確認です、ごめんなさい(苦笑)
3,の場合
これも本にのっていたスクリプトを使ってちょいっとやっちゃいます。1,を自動でやってくれるrakeタスクです。一番簡単ですが、これをするとフィクスチャファイル以外の、これまで蓄積されたデータがパァになってしまうので注意。
lib>taskフォルダの下に以下のソースを「initializing.rake」という名前で保存しましょう。
ファイルを準備した後は、
これでOK!
一度、migrateしてしまうと、簡単にはやりなおせません。
方法は3つ
1,DBを一から作り直す
2,バージョンを増やしてマイグレーションスクリプトを作り直した後、マイグレーションを行う。
3,initializing.rakeという初期化用ファイルを使う
1,の場合
mysqlでデータベースを削除(drop データベース名;)した後、もう一度データベースを作り、マイグレーションし直す。めんどくさい(笑)
2,の場合
002_テーブル名.rbと名前をつけてマイグレーションするというもの。しかし、rails2.0以降、この仕様は変更されたので、上手くいくか不明。未確認です、ごめんなさい(苦笑)
3,の場合
これも本にのっていたスクリプトを使ってちょいっとやっちゃいます。1,を自動でやってくれるrakeタスクです。一番簡単ですが、これをするとフィクスチャファイル以外の、これまで蓄積されたデータがパァになってしまうので注意。
lib>taskフォルダの下に以下のソースを「initializing.rake」という名前で保存しましょう。
namespace :db do
desc "Create the development and test databases."
task :create do
require 'yaml'
path = File.dirname(__FILE__) + "/../../config/database.yml"
configurations = YAML.load_file(path)
%w(development test).each do |env|
config = configurations[env]
if config['adapter'] == 'mysql'
command = sprintf(%{mysql --user %s}, config['username'])
command += " --password=#{config['password']}" if config['password'] and !config['password'].empty?
command += " --host #{config['host']}" if config['host'] and !config['host'].empty?
command += " --port #{config['port']}" if config['port'] and !config['port'].empty?
sh command + %( --execute="drop database if exists #{config['database']}")
if config['encoding'] and !config['encoding'].empty?
sh command + %( --execute="create database #{config['database']} default character set #{config['encoding']}")
else
sh command + %( --execute="create database #{config['database']}")
end
elsif config['adapter'] == 'postgresql'
# 未実装
else
raise "Unsupported database adapter #{config['adapter']}"
end
end
end
desc "Create and initialize the development and test databases."
task :initialize => ["db:create", "db:migrate", "db:import:development", "db:test:prepare"]
end
ファイルを準備した後は、
rake db:initialize
これでOK!
Ruby on Rails チュートリアル(1) ~Scaffoled未使用!DB作成からViewまで~
今まで本を見ながらやっていた事のおさらいもかねて、チュートリアルを書いてみようと思います。Rails2.0以降、scaffoldが便利すぎて、自分で一からデータベースを作って呼び出すということを詳細に書いてあるチュートリアルがない!
と苦悩しました。
いろいろなblogを参考にしながら私もひとつ書いてみようじゃないか、と思った次第であります。
今回作るのはこんなもの。
メンバーの一覧が出て来て、名前をクリックすると詳細ページに飛べるってものです。デザインもへったくれもありませんが、これを作って行きましょう。
test002というプロジェクトを作って、対応するDBもつくって、、、、って感じですね。
<1>プロジェクトを作る。
いつもと同じく、です。-d mysqlはrails 2.0以上からはデフォルトDBがsqliteになってしまっているため、忘れずに行いましょう。mysqlで作っている理由は「慣れ」です(笑)
<2>DBを作る。
DB完成。
mysqlパートは終了です。
<3>モデルを作る。(Userモデルを作ります)
<1>で作ったプロジェクトのディレクトリに移動。
これでdb>migrateの中にXXXXXXXX(作成日)_create_users.rbというファイルが出来ます。
usersと複数形になるのは仕様です。このusersというのがテーブルの名前になります。
<4>マイグレーション
テーブルの中身"フィールド"というものを作ります。
先ほど作ったモデル「XXXXXXXX(作成日)_create_users.rb」をエディタでOPEN。
今回は私が作っているMuliusの仕様に合わせて、名前と聴いている曲などのフィールドを足しました。お好みで!
これが書いてあるフィールドは、そのフィールドが埋まっていないとエラーが出ます。注意!
<5>マイグレーション
では作ったフィールドをmysqlのDBに取り込みましょう。
下の結果が出れば、成功。
エラーが出ないのに、この結果がでない場合、すでに一度マイグレーションしていると思われます。もう一回フィールドを作り直したい場合については次回のblogでまとめておきます。どうしてもって、いう場合は、mysqlでDBを破棄して、<5>をやり直してください。
成功しているか気になる人は、mysqlで
こんな風に表示されれば大丈夫!
<6>フィクスチャファイルを作る
テーブルと、その中身フィールドを作ってもデータが入っていないのでからっぽです。
フィクスチャファイルを使って、仮のデータを入れてみましょう。
テストを開始するためのソフトウェアの初期状態=フィクスチャらしいです。
まあ、テストのための仮のデータとでも思ってください。
dbフォルダの下にfixturesフォルダを作りましょう。この中に、さらにdevelopmentというフォルダと、productionというフォルダを作ります。developmentフォルダの中に「users.yml」(テーブル名.yml)というファイルを作ります。
先ほど作ったテーブルの中身と違いの内容に注意。とくにnull =>falseの指定をしたものは、忘れずに書きましょう。
<7>データ投入
ここでちょっと飛び道具。rakeタスクを使って、データを取り込んじゃいましょう。
lib>tasksフォルダの中に、data_loading.rakeというタスクファイルを作ります。本に乗っていたものをそのまま作っちゃいます。
完成したら
これでようやくDBにデータが投入出来ました。
<8>ビューとコントローラーを作る
これでcontrokkerフォルダの中にはusers_controller.rbが出来ます。
viewフォルダの中にindex.rhtml.erbとshow.rhtml.erbも出来ています。
まずはusers_controller.rbの編集。
次にindex.rhtml.erb
さらに、show.rhtml.erb
これで完成!
さっそくブラウザで見てみましょう。
このチュートリアルが終わった後、もう一度こんどは
テーブルの名前やフィールドを自分で考えたもの、Viewで表示するフィールドを変えてみるなど、一から自分で作ってみると、Railsへの理解を深めることが出来ると思います。
大変おつかれさまでした!
と苦悩しました。
いろいろなblogを参考にしながら私もひとつ書いてみようじゃないか、と思った次第であります。
今回作るのはこんなもの。
メンバーの一覧が出て来て、名前をクリックすると詳細ページに飛べるってものです。デザインもへったくれもありませんが、これを作って行きましょう。
test002というプロジェクトを作って、対応するDBもつくって、、、、って感じですね。
<1>プロジェクトを作る。
$ rails -d mysql test002
いつもと同じく、です。-d mysqlはrails 2.0以上からはデフォルトDBがsqliteになってしまっているため、忘れずに行いましょう。mysqlで作っている理由は「慣れ」です(笑)
<2>DBを作る。
$ mysql -u root
mysql> create database test002_development;
mysql> create database test002_test;
DB完成。
mysql> exit
mysqlパートは終了です。
<3>モデルを作る。(Userモデルを作ります)
<1>で作ったプロジェクトのディレクトリに移動。
$ cd test002
$ ruby script/generate model user
これでdb>migrateの中にXXXXXXXX(作成日)_create_users.rbというファイルが出来ます。
usersと複数形になるのは仕様です。このusersというのがテーブルの名前になります。
<4>マイグレーション
テーブルの中身"フィールド"というものを作ります。
先ほど作ったモデル「XXXXXXXX(作成日)_create_users.rb」をエディタでOPEN。
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.column :user_name, :string, # 名前(姓)
:null => false
t.column :listening_song, :string # 聴いている曲
t.column :message, :text # 備考
t.column :created_at, :datetime # 登録日時
t.column :updated_at, :datetime # 更新日時
t.timestamps
end
end
def self.down
drop_table :users
end
end
今回は私が作っているMuliusの仕様に合わせて、名前と聴いている曲などのフィールドを足しました。お好みで!
:null => false
これが書いてあるフィールドは、そのフィールドが埋まっていないとエラーが出ます。注意!
<5>マイグレーション
では作ったフィールドをmysqlのDBに取り込みましょう。
$ rake db:migrate
下の結果が出れば、成功。
(in /Users/suzukiyasuko/rails/test002)
== CreateUsers: migrating ====================================================
-- create_table(:users)
-> 0.0048s
== CreateUsers: migrated (0.0053s) ===========================================
エラーが出ないのに、この結果がでない場合、すでに一度マイグレーションしていると思われます。もう一回フィールドを作り直したい場合については次回のblogでまとめておきます。どうしてもって、いう場合は、mysqlでDBを破棄して、<5>をやり直してください。
成功しているか気になる人は、mysqlで
mysql> use test002_development;
mysql> desc users;
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_name | varchar(255) | NO | | NULL | |
| listening_song | varchar(255) | YES | | NULL | |
| message | text | YES | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
+----------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
こんな風に表示されれば大丈夫!
<6>フィクスチャファイルを作る
テーブルと、その中身フィールドを作ってもデータが入っていないのでからっぽです。
フィクスチャファイルを使って、仮のデータを入れてみましょう。
テストを開始するためのソフトウェアの初期状態=フィクスチャらしいです。
まあ、テストのための仮のデータとでも思ってください。
dbフォルダの下にfixturesフォルダを作りましょう。この中に、さらにdevelopmentというフォルダと、productionというフォルダを作ります。developmentフォルダの中に「users.yml」(テーブル名.yml)というファイルを作ります。
# 開発環境のためのフィクスチャ: users
John:
id: 1
user_name: ジョンレノン
listening_song: 赤いスイートピー
message: 松田聖子イイ!!
created_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
updated_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
Yauko:
id: 2
user_name: 鈴木泰子
listening_song: 木綿のハンカチーフ
message: 古い曲ばっかりだな
created_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
updated_at: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %>
先ほど作ったテーブルの中身と違いの内容に注意。とくにnull =>falseの指定をしたものは、忘れずに書きましょう。
<7>データ投入
ここでちょっと飛び道具。rakeタスクを使って、データを取り込んじゃいましょう。
lib>tasksフォルダの中に、data_loading.rakeというタスクファイルを作ります。本に乗っていたものをそのまま作っちゃいます。
require 'active_record'
require 'active_record/fixtures'
namespace :db do
def load_data(env)
ActiveRecord::Base.establish_connection(env)
pattern = File.join(RAILS_ROOT, 'db', 'fixtures',
env.to_s, '*.{yml,csv}')
Dir.glob(pattern).each do |fixture_file|
table_name = File.basename(fixture_file, '.*')
Fixtures.create_fixtures('db/fixtures/' + env.to_s, table_name)
end
end
namespace :import do
desc "Load fixture data into the development database."
task :development => :environment do
load_data :development
end
desc "Load fixture data into the production database."
task :production => :environment do
load_data :production
end
end
end
完成したら
$ rake db:import:development
これでようやくDBにデータが投入出来ました。
<8>ビューとコントローラーを作る
$ ruby script/generate controller users index show
これでcontrokkerフォルダの中にはusers_controller.rbが出来ます。
viewフォルダの中にindex.rhtml.erbとshow.rhtml.erbも出来ています。
まずはusers_controller.rbの編集。
class UsersController < ApplicationController
def index
@users = User.find(:all)
end
def show
@user = User.find(params[:id])
end
end
次にindex.rhtml.erb
<% @users.each do |user| -%>
<li>
<%= link_to(h(user.user_name), :action => 'show', :id => user.id)%>
</li>
<% end -%>
さらに、show.rhtml.erb
<p>名前は:<%=@user.user_name%></p>
<p>聴いている曲は:<%=@user.listening_song %></p>
<p>メッセージ:<%=@user.message%></p>
<%= link_to '一覧表示に戻る', :action => 'index'%>
これで完成!
$ ruby script/server
さっそくブラウザで見てみましょう。
このチュートリアルが終わった後、もう一度こんどは
テーブルの名前やフィールドを自分で考えたもの、Viewで表示するフィールドを変えてみるなど、一から自分で作ってみると、Railsへの理解を深めることが出来ると思います。
大変おつかれさまでした!
2009年1月16日金曜日
Mulius WebApp ver1.0 作成
2009年1月15日木曜日
TextMate ~日本語入力編〜
utf-8で全て保存するということを統一するのと、もっと使いやすいエディタはないのかと悩んでいた所、OくんからTextMateを教えてもらいました。
なるほど、使いやすい。てか凄いね。コレ。
見づらいんだけど、htmlコードがすいすい書ける事が分かると思います。
DWは重すぎだし、aptenaは良いと思うけど私にはボリューミーで嫌でした。TextMateはメモ帳みたいに使えます。“めも”が好きな私にぴったりです。
興奮したのもつかの間、
日本語打てないよ......
しかし、ここでも先駆者はおりました。日本語化プラグインCJK-Input.tmpluginを作ってくれた素晴らしい人がいました。
さっそくダウンロード。ホームディレクトリで解凍したら、ターミナル
ちゃんと入ったか確認
よしよし。入ってますね。
専用フォントも入れておくと良いとのことだったので落としておきました。
参照:Railsに最適なテキストエディター「TextMate」を入れて日本語化してみた
さて、TextMateを再起動。
できてますね。よし!
なるほど、使いやすい。てか凄いね。コレ。
見づらいんだけど、htmlコードがすいすい書ける事が分かると思います。
DWは重すぎだし、aptenaは良いと思うけど私にはボリューミーで嫌でした。TextMateはメモ帳みたいに使えます。“めも”が好きな私にぴったりです。
興奮したのもつかの間、
日本語打てないよ......
しかし、ここでも先駆者はおりました。日本語化プラグインCJK-Input.tmpluginを作ってくれた素晴らしい人がいました。
さっそくダウンロード。ホームディレクトリで解凍したら、ターミナル
$ mv CJK-Input.tmplugin /Applications/TextMate.app/Contents/PlugIns/
ちゃんと入ったか確認
$ cd /Applications/TextMate.app/Contents/PlugIns/
$ ls
CJK-Input.tmplugin Dialog.tmplugin
よしよし。入ってますね。
専用フォントも入れておくと良いとのことだったので落としておきました。
参照:Railsに最適なテキストエディター「TextMate」を入れて日本語化してみた
さて、TextMateを再起動。
できてますね。よし!
MySQL ~ターミナルで文字化けする問題~
RORをやっていると、必ずといっていいほど環境系でつまずきます。今日もMySQLでつまずきました。
ターミナルでmysqlを立ち上げ、
すると
フィールドの一覧が表示されます。
私は今回、membersというテーブルを作ってあったので、それを読み出しました。
ターミナルでmysqlを立ち上げ、
my sql> use (DBの名前)
mysql> desc (テーブルの名前);
すると
フィールドの一覧が表示されます。
私は今回、membersというテーブルを作ってあったので、それを読み出しました。
mysql> desc members;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| member_number | int(11) | NO | | NULL | |
| player | tinyint(1) | NO | | 0 | |
| family_name | varchar(255) | NO | | NULL | |
| given_name | varchar(255) | NO | | NULL | |
| furigana | varchar(255) | NO | | NULL | |
| email | varchar(255) | YES | | NULL | |
| phone | varchar(255) | YES | | NULL | |
| sex | int(11) | YES | | NULL | |
| birthday | date | YES | | NULL | |
| remarks | text | YES | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
13 rows in set (0.01 sec)
ここからレコードを抜き出してみよう。まずは名字から
mysql> select family_name from members;
+-------------+
| family_name |
+-------------+
| ???? |
| ???? |
| ???? |
| ???? |
| ???? |
| ???? |
| ???? |
| ???? |
| ???? |
| ???? |
+-------------+
ばっちり文字化けです!
mysql>set character set sjis;
本に書いてある通りに打ってみます。これで表示してくれるだろう。。。
と思ったけど、やっぱり同じ結果。
う〜ん、、、と悩みをtwittしたところ、心優しい人たちが解決方法を伝授してくれました。
(1)そもそもsjisでファイルを作っちゃダメ!
私はmacユーザー。本はwin向け。よってファイルがsjisで作られてるわ、characterもsjisになってるわで全然これじゃ表示出来ないって話です。
(2)ターミナルの環境設定をもう一度見よう。
こんな初歩的なところで、、、、恥ずかしくなりました。
ここがutf-8になっていなかった。恥ずかしい!
これでもう一度
mysql> select family_name from members;
+-------------+
| family_name |
+-------------+
| 佐藤 |
| 鈴木 |
| 高橋 |
| 田中 |
| 渡辺 |
| 伊藤 |
| 山本 |
| 佐藤 |
| 鈴木 |
| 高橋 |
+-------------+
10 rows in set (0.00 sec)
うん、できました!
2009年1月14日水曜日
(続) ROR データベース作成のエラー
昨日の続きです。
どうやら、rake db:migrateは失敗に終わっていたようです。
引き続きOくんの協力の元、MySQLと格闘しました。
前回に引き続き、mysql gemをインストールした後
すると
確認すると、ちゃんと入ってる事が分かります。
もう一回rake db
すると
やっぱり出来ない、、、。
ここが問題みたい。
Oくんに聞いてみた所、シンボリックリンクを張ることになった。
すると
こんな結果がかえってくる。
これでrake db:migrateすると、、、、
できました〜〜〜〜〜!!!!!!!
Oくん、本当にありがとうございました。
それから、Oくんと私のやり取りの中で、MySqlで役立つコマンドが出て来たので、抜粋します。自分のためのメモ書き。
select * from (テーブル名);
意味は
テーブルから * (全てのレコード)を表示する
あとはよく使うのは
desc (テーブル名)
これはテーブルの型を確認するコマンド
どうやら、rake db:migrateは失敗に終わっていたようです。
引き続きOくんの協力の元、MySQLと格闘しました。
前回に引き続き、mysql gemをインストールした後
$ cd /Library/Ruby/Gems/1.8/gems/mysql-2.7
$ ls
すると
COPYING README.html lib mysql.c mysql.o
COPYING.ja README_ja.html mkmf.log mysql.c.in test.rb
Makefile extconf.rb mysql.bundle mysql.gemspec tommy.css
確認すると、ちゃんと入ってる事が分かります。
もう一回rake db
すると
rake aborted!
dlopen(/opt/local/lib/ruby/site_ruby/1.8/i686-darwin9/mysql.bundle, 9): Library not loaded: /usr/local/mysql/lib/mysql/libmysqlclient.15.dylib
Referenced from: /opt/local/lib/ruby/site_ruby/1.8/i686-darwin9/mysql.bundle
Reason: image not found - /opt/local/lib/ruby/site_ruby/1.8/i686-darwin9/mysql.bundle
やっぱり出来ない、、、。
Library not loaded: /usr/local/mysql/lib/mysql/libmysqlclient.15.dylib
ここが問題みたい。
Oくんに聞いてみた所、シンボリックリンクを張ることになった。
$ cd /Library/Ruby/Gems/1.8/gems/mysql-2.7
$ sudo ruby extconf.rb --with-mysql-config=/usr/local/mysql/bin/mysql_config
すると
Password:
checking for mysql_ssl_set()... no
checking for mysql.h... yes
creating Makefile
こんな結果がかえってくる。
$ sudo make
gcc -I. -I. -I/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0 -I. -DHAVE_MYSQL_H -I/usr/local/mysql/include -g -Os -arch i386 -fno-common -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT -DDONT_DECLARE_CXA_PURE_VIRTUAL -fno-common -arch ppc -arch i386 -Os -pipe -fno-common -c mysql.c
cc -arch ppc -arch i386 -pipe -bundle -undefined dynamic_lookup -o mysql.bundle mysql.o -L"." -L"/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib" -L. -arch ppc -arch i386 -lruby -L/usr/local/mysql/lib -lmysqlclient -lz -lm -lmygcc -lpthread -ldl -lm
ld warning: in /usr/local/mysql/lib/libmysqlclient.dylib, file is not of required architecture
ld warning: in /usr/local/mysql/lib/libmygcc.a, file is not of required architecture
dhcp11:mysql-2.7 suzukiyasuko$ sudo make install
/usr/bin/install -c -m 0755 mysql.bundle /Library/Ruby/Site/1.8/universal-darwin9.0
これでrake db:migrateすると、、、、
できました〜〜〜〜〜!!!!!!!
Oくん、本当にありがとうございました。
それから、Oくんと私のやり取りの中で、MySqlで役立つコマンドが出て来たので、抜粋します。自分のためのメモ書き。
select * from (テーブル名);
意味は
テーブルから * (全てのレコード)を表示する
あとはよく使うのは
desc (テーブル名)
これはテーブルの型を確認するコマンド
2009年1月13日火曜日
ROR データベース作成のエラー rake aborted!
ROR DBのお勉強をしております。
基礎 Ruby on Railsという本をみてやってるのですが、Rubyのバージョンがだいぶ古いため、上手くいかない状態でした。というのもRailsのバージョンがあがったために、いままでバンドルされていたドライバーがなくなっていたりして(MySQLからSQLiteに変わったのがあるだろうけど)
こんな感じでエラーが、、、、、、。
ymlからdatabaseがつくれない?!
エラーの通りに
上手くいったのか、、な?
もう一度、ymlからdbを作ろう、と
そうすると
これは、、、、どうなんだろう。成功してるのか、してないのか、、、、。
もうちょっと進めてみます!
基礎 Ruby on Railsという本をみてやってるのですが、Rubyのバージョンがだいぶ古いため、上手くいかない状態でした。というのもRailsのバージョンがあがったために、いままでバンドルされていたドライバーがなくなっていたりして(MySQLからSQLiteに変わったのがあるだろうけど)
rake db:migrate
と打つと
!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.
rake aborted!
no such file to load -- mysql
こんな感じでエラーが、、、、、、。
ymlからdatabaseがつくれない?!
エラーの通りに
gem install mysql
と打ってもエラーが出ます。ここはgoogle!するとsudoでインストールするとよいらしということが分かりました。sudo gem install mysql -- --with-mysql-config
上手くいったのか、、な?
もう一度、ymlからdbを作ろう、と
rake db:migrate
そうすると
dyld: lazy symbol binding failed: Symbol not found: _mysql_init
Referenced from: /Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle
Expected in: dynamic lookup
dyld: Symbol not found: _mysql_init
Referenced from: /Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle
Expected in: dynamic lookup
Trace/BPT trap
これは、、、、どうなんだろう。成功してるのか、してないのか、、、、。
もうちょっと進めてみます!
2009年1月12日月曜日
HTTPリクエスト test用 ソース
今日はもう少しだけ、いろいろ試してみました。
httpリクエストを受け取るための、テスト用railsを作ってみました。
blogでrailsの話をいままで書いてなかったことに気づき、おさらいも含めて、まずはrailsプロジェクトを作るためのコマンドプロンプトパートから。
Macの人はterminalを立ち上げて、
※rails2.0からデフォルトDBがSQLiteになりました。MySQLで作りたい場合は
これでいったんターミナルは置いておいて、次は出来たファイルを見て行きましょう。
出来たフォルダ「sample001」の中にある「app」>「controllers」フォルダの中にはmain_controller.rbが入っています。この中にメソッドを書いて行きます。
今回は簡単にこんな感じ。
showというメソッドを作ってみました。
paramsっていうのは、その名の通り、パロメーターを取得するものです。
もうちょっと蛇足して書くと、
http://アドレス/controller名/method名/パロメーター(コレのこと!)
次は、「app」>「view」>「main」フォルダへ。
ここはまだからっぽのはず。先ほどmain_controller.rbで書いた、"show"メソッドの先、「show.rhtml」を作ります。
適当なテキストエディタで、
これだけ書いて「app」>「view」>「main」フォルダへ保存。
これでテストの準備は完了しました。
ターミナルで
後は、前に書いたblogの内容と同様。
Windowsにシリアルでつないだ、Wi-Portから
tera termを使って、
WEBrick側のターミナルを見ていると、上手くいっていることが確認出来ます。
httpリクエストを受け取るための、テスト用railsを作ってみました。
blogでrailsの話をいままで書いてなかったことに気づき、おさらいも含めて、まずはrailsプロジェクトを作るためのコマンドプロンプトパートから。
Macの人はterminalを立ち上げて、
$ rails sample001
と打ちますと、プロジェクトが自動で作られます。※rails2.0からデフォルトDBがSQLiteになりました。MySQLで作りたい場合は
rails -d mysql (プロジェクト名)
$ cd sample001
ディレクトリを移動。$ ruby script/generate contoroller main
controllerを今度は自動で作ってくれます。一番最後のmainが名前。これでいったんターミナルは置いておいて、次は出来たファイルを見て行きましょう。
出来たフォルダ「sample001」の中にある「app」>「controllers」フォルダの中にはmain_controller.rbが入っています。この中にメソッドを書いて行きます。
今回は簡単にこんな感じ。
class MainController < ApplicationController
def show
@sample_id = params['id']
end
end
showというメソッドを作ってみました。
paramsっていうのは、その名の通り、パロメーターを取得するものです。
もうちょっと蛇足して書くと、
http://アドレス/controller名/method名/パロメーター(コレのこと!)
次は、「app」>「view」>「main」フォルダへ。
ここはまだからっぽのはず。先ほどmain_controller.rbで書いた、"show"メソッドの先、「show.rhtml」を作ります。
適当なテキストエディタで、
<%= @sample_id %>
これだけ書いて「app」>「view」>「main」フォルダへ保存。
これでテストの準備は完了しました。
ターミナルで
ruby script/server
と打って、WEBrick立ち上げ。後は、前に書いたblogの内容と同様。
Windowsにシリアルでつないだ、Wi-Portから
tera termを使って、
C192.168.0.111:3000
GET /main/show/12345 HTTP/1.0
(ENTERキー)WEBrick側のターミナルを見ていると、上手くいっていることが確認出来ます。
WEBrickサーバーにWi-PortからHTTPリクエスト
ここ一週間、RailsでTCPSocket通信をしようと格闘しつづけていたのですが、橋本商会さんに詳解してもらい、出来ない、ということが判明しました。
いっしょに手伝ってくれたOくん、本当にありがとう、そしてごめんなさい。
というわけで、HTTPリクエストをrailsに出して、うんぬんかんぬん、、、、ということに取り組むことになりました。
まずは、Wi-Portの設定を。Making Things Talkという本で、X-portでhttpリクエストを行うための設定が書かれているので、参考にしてみました。
Network Settings
注目はSubnet MaskとDefault Gateway。Default GatewayはMacの場合、「ネットワーク環境設定」>「詳細」で見る事が出来ますので、それで。
それ以外の設定は前回と同様です。こちらを参照。
できましたらば、
まずはシリアル変換ケーブルとWi-Portをつないで、WinからWi-Portを操作しましょうか。
この辺は、Wi-Portの一番最初の設定と同じ感じ。
Tera Termを立ち上げましょう。
※IPアドレスは、MACの場合、「インターネット環境設定」からご確認ください。
Enterキーを押します。上手くいくと
がかえってきます。
これで、ステータス/htmlがどばーっとかえってくると成功です。
この後はEnterキーを押すだけで、上手くいく場合と、Enterキーの代わりに、「Cntrl + M, Cntrl + J 」と入力しないとダメな場合があるので注意。最後のEnterキー2回のところで、「Cntrl + M, Cntrl + J 」も2回入力することになります。
いっしょに手伝ってくれたOくん、本当にありがとう、そしてごめんなさい。
というわけで、HTTPリクエストをrailsに出して、うんぬんかんぬん、、、、ということに取り組むことになりました。
まずは、Wi-Portの設定を。Making Things Talkという本で、X-portでhttpリクエストを行うための設定が書かれているので、参考にしてみました。
Network Settings
注目はSubnet MaskとDefault Gateway。Default GatewayはMacの場合、「ネットワーク環境設定」>「詳細」で見る事が出来ますので、それで。
それ以外の設定は前回と同様です。こちらを参照。
できましたらば、
まずはシリアル変換ケーブルとWi-Portをつないで、WinからWi-Portを操作しましょうか。
この辺は、Wi-Portの一番最初の設定と同じ感じ。
Tera Termを立ち上げましょう。
C192.168.0.111:3000
※IPアドレスは、MACの場合、「インターネット環境設定」からご確認ください。
Enterキーを押します。上手くいくと
C
がかえってきます。
GET /index.html HTTP/1.0
(ENTERキー)HOST: 192.168.0.111:3000
(ENTERキー2回押す)これで、ステータス/htmlがどばーっとかえってくると成功です。
この後はEnterキーを押すだけで、上手くいく場合と、Enterキーの代わりに、「Cntrl + M, Cntrl + J 」と入力しないとダメな場合があるので注意。最後のEnterキー2回のところで、「Cntrl + M, Cntrl + J 」も2回入力することになります。
登録:
投稿 (Atom)