digifacture

Railsとかデジモノとか色々勉強した事とか作った事とか気になった事とか

ajaxでrender partialとtableとauthenticity_token

partialで送信フォームをrenderする際に、tableタグを親にformを.html()で描画するとauthenticity_tokenが認識されず送信フォームが機能しなくなる。

色々試すうちにrender partialを実行された際にtableタグ周りの挙動がどうにも不信だった。

たとえば送信フォームをtableタグ内の指定のdivタグ内に設置しようと下記のようなコードをテンプレートhtml.erb書く

<table id="apptable">
<div id="hoge">
<%= render :partial=>"app_list", :locals=>{:apps=>@apps} %>
</div>
</table>

 

 すると実際に生成された.htmlには、本来tableタグに入れ子になっていたdivタグがなぜかtableタグの外に出されていた。

<div id="hoge"></div>
<div style="margin:0;padding:0;display:inline”>…</div>
<table id="apptable">
<tbody>…
</tbody></table>

 もしやと思ってテンプレート内の表の描画をやめてdivタグだけにしたらpartialとjsによって設置された送信フォームでも機能するようになった。

authenticity_tokenは記載されていたにも関わらず、tableタグにjsで動的にフォームを設置すると送信フォームが機能しなくなるのかわからずじまい

railsがどのようにしてauthenticity_tokenを認識してるのか学ぶ必要がある

ぐぬぬ

でもrails4だとまた違うのかも

Railsの送信フォームタグとform_forとauthenticity_token

色々試すうちに独自に送信フォームを作ろうと思って/viewのhtml.erbにhtmlタグを直接

<form accept-charset="UTF-8" action="/apps" class="new_app" data-remote="false" id="new_app" method="post"></form>
<input id="app_name" name="app[name]" size="30" type="text">

<input name="commit" type="submit" value="Create App">

って書いても機能しないけどform_for使って

<%= form_for(@apps[0]) do |f| %>

送信フォームをRailsに作ってもらうとちゃんと機能する。

 

formタグにpostって書けばパラメータをRailsに渡してくれるんちゃうかー

html手打ちとRails生成で何が違うのか色々調べるとform_forを使うと生成されるhtmlに

<div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓"><input name="_method" type="hidden" value="put"><input name="authenticity_token" type="hidden" value="UpkYcXXIEfG5D3aVZ48Ick9iRRg+iroZ9YO21EgC+SM="></div>

っていう身に覚えのないのないタグが書かれている。

authenticity_token?認証か何か?と思ってsafariのwebインスペクタでコードを削ってみるとform_forで生成された送信フォームも機能しなくなった。

それで調べてみると


CSRFの対応について、rails使いが知っておくべきこと - おもしろWEBサービス開発日記

先ほども書きましたが、get以外の動詞(POST, PUT, DELETE)を使う時は、authenticity_tokenをセットする必要があります。なのでrailsajax用のヘルパを使わずに、独自にjavascriptを書いてdbをいじる時は手動でauthenticity_tokenをいれてあげないといけません。

なるほどねー不正防止なのね

致せり尽くせりだけど仕組みを理解してないとこゆとき困るね

冷却台改造

前にZalmanの冷却台を買ったのはいいものの、Macbook Pro17"に高負荷な処理をさせるとアッチッチになるので、余ったパーツでファンを新しく組み込んだ。

f:id:digifacture:20140918163131j:plain

一番熱くなるのは左下のハードドライブあたり。

しかし冷却台は手前に傾斜をつける構造になっている為、FANが風を取り込むのに十分な空間がない。

ので穴を開けてFANをはめ込む。

f:id:digifacture:20140918164644j:plain

これでAEで映像書き出したりFPSやっても大丈夫!

教訓:冷却台は風を吹き付けてナンボ

Phantom2 地面に激突

地面に衝突した瞬間

f:id:digifacture:20140914182700p:plain

 

状況:

操作中機体のバッテリー残量が減り、ゴーホーム機能により自動運転により帰還中、下降速度が早すぎそのまま地面と衝突。

 

被害程度:

ジンバルに接続されている8pinコネクタ損傷。

f:id:digifacture:20140914181602j:plain

トランスミッター用のマウント脱落。

GoProの筐体に若干傷。

f:id:digifacture:20140914182330j:plain

 

ケガ人:

なし。

 

対策:

1.機体重量の軽減。プロペラガードを取り外し、トランスミッターのカバーを外す(技適的に問題ある可能性あり)

2.下降速度の調整。最大下降速度の調整ができないか調べる。

3.バッテリー残量の把握。iOSDを搭載する事で手元のモニターにてバッテリー残量を表示する。運転時間を計り、10分を超える飛行を避ける。

4.フライト開始地点から操作者は移動しない。またはすぐに戻れる状況に居る。

5.ジンバルの保護のために脚回りの強化。機体の代わりに破損してくれるような。

6.なんか一定の加速度以上がかかるとパラシュート開けばいいのに。

 

処置:

千切れかけたコネクタを接着剤で補修し、ピンを差したら直った

f:id:digifacture:20140914181550j:plain

H3-3Dつよいこ

f:id:digifacture:20140914181543j:plain

 

空撮は周囲の安全を良く確認して楽しみましょう!

f:id:digifacture:20140914183012p:plain

DJI Phantom2 クアッドコプターFPV空撮に挑戦したメモなど

 DJI Phantom2という台湾メーカーのラジコンクアッドコプターにGoProアクションカメラを付け、FPV(First Person View:上空のカメラを手元のモニターで見る)を実装してみた。

退職してからやってみたかったことに色々手をアレコレ手を出してる訳だけど、今回はRailsの勉強を頑張ってる自分へのご褒美。

 

はじめに

ラジコンどころか電子工作すら初めて手を出す初心者です。

購入したのはちょうど一週間前の記事を書き終えたすぐ後です。

今後初めてラジコンヘリに手を出す人の参考になれば幸いです。

でも参考にする際はあくまで自己責任で!

+-の極性を間違えたりしたらいっぺんにショートして故障しうるので気をつけて!

あとフライトの際には周囲の安全を確認して無理のない操作に気をつけて!

ちなみに自分は2回目の飛行の際に、降下速度が早すぎてそのまま地面に衝突しました...orz

 

用意するもの

DJI Phantom2

ラジコンヘリ本体。こいつはスゴイ機体だ。機体が自動的に姿勢の制御をしてくれるので、操作は単純に動かしたい進行方向へレバーを倒せばいい。つまり機体を空中でホバリングするためにモーターの回転数やそれぞれのプロペラのバランスなど一切意識する必要がない。スゴイカンタン。実際スゴイ。

DJI JAPAN直販 新型Phantom 2(H3-3D対応)

DJI JAPAN直販 新型Phantom 2(H3-3D対応)

 

 

H3-3D

ジンバル ラジコンからカメラに伝わる振動を抑え、カメラを水平に保ち安定した映像を撮る為のスタビライザー的な機械。ちなみにこれがあると、手元のコントローラー(プロポ)のレバーでカメラの角度を上下に操作する事ができる。便利!

DJI Zenmuse H3-3D (新Phantom 2専用)

DJI Zenmuse H3-3D (新Phantom 2専用)

 

 

GoPro hero3

アクションカメラ。H3-3Dはこのカメラ専用で作られてる。空撮以外にも色々使える優れもの。 自転車やラフティングとかアウトドアレジャーのお供に体につけて撮影すると面白い。

 

AT-2630

トランスミッター 上空に飛んでる機体のカメラの映像を地上に送りFPVを実現する機械。これの何が良いかというと

・国内メーカーなので技適を通っている。

・2.4Ghz帯の周波数なので電波法内で個人利用出来る。

キャロットシステムズ オルタプラス 無線送受信機30FPS AT-2630AVS

キャロットシステムズ オルタプラス 無線送受信機30FPS AT-2630AVS

 

 

MTC-350

上空の映像を受信したトランスミッターからの映像の出力先。コンポジット映像を表示出来るならなんでも。ちなみに自分が買った下記のモニターはGoProの映像の端が切れちゃうけど、上空の実機とモニタの両方を見ながら操作したかったので小ささを優先。

 

Anker Astro Pro2

モバイルバッテリー モニターと受信側トランスミッターの電源。12Vと5V(USB)が出力できればなんでもいい。

 

DC DC コンバーター

本体のPhantom2から送信側トランスミッターへ電源を供給する際に、本体からは12Vが供給されているので、トランスミッターの要求する5Vへ電圧を降圧する為の部品。

別によくあるカーアクセサリのシガーからスマホ充電用にUSBの口が付いてる充電器を分解してもいい。下記のを買ったのは良いけど、結局分解した部品の方がコンパクトになったのでそちらを使った。

 

 

 

 

あると良さそうなの

BEC コネクタ

本体とトランスミッタを接続するのにコネクタがあると、+-の極性をいちいち意識しなくて便利。

 

RCA コンポジット

・3.5mm 4極 ミニプラグ

昔のファミコンする時にテレビで赤、白、黄色のケーブルあったじゃん?あれのテレビに差し込むオス側の方。トランスミッタに付属してくるケーブルを分解してもいい。秋葉原の秋月電商なのでコネクタだけ買えるので、それを半田でつけるのが一番スマート。 

フジパーツ AVケーブル 3ピン-1(4極)ミニプラグ 1.5m FVC-129A

フジパーツ AVケーブル 3ピン-1(4極)ミニプラグ 1.5m FVC-129A

 

プラ板

・圧着ペンチ

・半田ごて

・テスター

 

 

FPV用トランスミッターの取り付け

ジンバルなどの取り付け方は既に色んな所で解説されてるので、ここではFPV用のトランスミッターの取り付けについて。

 まず全体図f:id:digifacture:20140914044237j:plain

機体の左後ろ脚の付け根にH3-3Dジンバルに繋げる8pinケーブルと一緒に4色のケーブルが平たく伸びてる

これは端から茶赤が12V電源用のコードで、茶黄が映像信号用のケーブルでGoProの映像がジンバル経由でここまでくる。

このコードを必要に応じてトランスミッターに接続すれば映像を地上に送ることが出来る。

電源は本体から伸びてるトランスを経由して赤いケーブル(+)を電源端子のセンターにくるように繋ぎ、茶色いケーブルを外面側に接続する。

f:id:digifacture:20140914043330j:plain

 

映像信号は本体から伸びてるケーブルの黄色側を4極ピンの先端から2番目、茶色側のケーブルを4極ピンの先端から4番目に繋げる。

f:id:digifacture:20140914043345j:plain

 

あとはトランスミッターを本体に付ければ終わり。

取り付け位置が難しいが、自分は写真のようにプラ板でマウントレールを付けた。

レールが後ろに出過ぎるとバッテリーの取り外しのツメと干渉するので注意。

あとレールのあるあたりにシリアル番号があるので取り付ける際には要注意。

f:id:digifacture:20140914045747j:plain

以上トランスミッターの取り付けでした。 

 

諸注意点など

DJI Phantom2があれば誰でもカンタンに空撮できます。

しかし一方で屋外で機械を操作するという事は公共の空間で活動する為、電波法や航空法を尊守しなければなりません。

航空法違反になることも!? ラジコンヘリで注意したいこと|タブロイド

とりあえず気をつけるべきは、

・空港から半径9km以内には近づかない、150m以上上に飛ばさない。

・FPVに5.8Ghz帯は使わない、技適の通った機械を使うか無線の資格を取る。

の2点でしょう。

 

またラジコン保険に入るのも良いと思います。

RCK(財)日本ラジコン電波安全協会

実際に飛ばしてみると、急に操作を受け付けなる事が多々あります。

失速して墜落死先に人が居て怪我をさせてしまったり、車を傷つけたり・・・

想像したくありませんが、起こりうる事です。

 

Phantom2によって素人が誰でも簡単に空撮ができることは素晴らしいことです。

またAmazonが小型ヘリによる宅配を研究するなど、ドローンの発展は我々に様々な恩恵を与えてくれます。

一方でリスクは付き物です。慣れてない初心者が安易に飛行させたあげく何かを損傷する事は想像に容易く、それが引き金になってラジコンヘリへの規制に繋がりかねません。

この記事は積極的に情報を発信し共有することによりリスクを軽減する狙いもあります。 

リスク顕在化によりドローンの可能性を閉ざさない為にも、各自が危険予知と安全対策を心がけリスクの最小化につとめましょう!

 

それでは良きフライトを!

ご安全に!

f:id:digifacture:20140914053834j:plain

Head First Railsで詰まったとこ:Rails3でAjax更新(remote_form_forの代替)

現在Head First Railsで勉強中にAjaxでの更新で詰まったのでメモ。

手元の開発環境はRails3.2.9だけど教本はRails2を前提に書かれているので、所々コードを自分で修正しなければならない。

その中でも7章p285の新規予約登録フォームの送信から、登録一覧の表示を非同期で更新する処理の実装は苦労したので書き記したい。

それもRails2ではremote_form_forとpartialだけで実装出来るが、Rails3ではremote_form_forが廃止されているので、画面の更新をjavascriptで呼び出す必要がある。

 

Head First Rails Cap.7 p287 (Rails2)での書き方

本では下記の2点を変更するだけで良かった。

/flights/_new_seat.html.erb

<% remote_form_for(seat, :update=>'seats')> do |f| %>

/controllers/seats_controller.rb

def create
@seat = Seat.new(params[:seat])
@seat.save
render :partial => "flights/seat_list", :locals=>{:seats=>@seat.flight.seats}
end 

Rails3での書き方

まず_new_seatからform_seatにオプションを渡せるように:seat=>seat追記する。

/views/flights/_new_seat.html.erb

<h1>New seat</h1>

<%= render 'form_seat', :seat=>seat %>

<%= link_to 'Back', seats_path %> 

 form_forのsubmitをAjax(XHR)で送信するように :remote=>trueを追記する。

 /views/flights/_form_seat.html.erb

<%= form_for(seat, :remote=>true) do |f| %>

Ajaxでリクエストが来た場合に、jsでレスポンスを返すためにformat.jsを加筆する。 

/controllers/seats_controller.rb

def create
  @seat = Seat.new(params[:seat])
  respond_to do |format|
    if @seat.save
      format.html { render :partial => "flights/seat_list", :locals=>{:seats=>@seat.flight.seats} }
      format.json { render json: @seat, status: :created, location: @seat }
      format.js

    else
      format.html { render action: "new" }
      format.json { render json: @seat.errors, status: :unprocessable_entity }
    end
  end
end

 コントローラからcreateアクションを実行する際に、create.js.erbを新たに作成する。ここで新しく登録された予約のあるデータを<%= "/flights/#{@seat.flight.id}/seats" %>を参照して、jQueryにてページの一覧を書き換える。

/views/seats/create.js.erb

$.ajax(
  {
    type: 'GET',
    url: '<%= "/flights/#{@seat.flight.id}/seats" %>',
    dataType: 'html',
    success: function(data) {
      $('#seats').html(data);
    },
    error:function() {
      alert('Ajax Error');
    }
  }

);

 上記のように書けばフォームを入力し、submitボタンを押すと新しく登録したデータが予約の一覧に非同期で追加されるのをみることができる。

 

ポイントはform_forにremote=>trueすることでXMRによる送信になり、controllerはXMRでは.jsで返す仕組みがある、ということなのだろう。

ちゃんとcontrollerの動きや、HTTPの仕組みを把握しなければ理解できないことが多そう。

ツギハギだらけで不十分なことだらけだけど、Head First Railsで同じようにハマった人の助けになれば幸いです。

O'Reilly Japan - Head First Rails

参考:(他にもたくさんあるけど抜粋)

Rails3のAjaxでHTMLを返してjQueryで処理する - #詰んでる日記

Rails3で特定のid要素の中身をAjaxで書き換える - (゚∀゚)o彡 sasata299's blog

Sebastián González : Rails 4: How to partials & AJAX, dead easy

Rails3の form_for で Ajax をやってみた - KodaNote

Rails 3 で remote_form_for みたいなことをやる - RunoLog

Ruby Learning Notes: Replacement for remote_form_for in Rails 3 ←ここのやり方が1番

uu59のメモ | RailsとJS(vue.js)の連携

教訓:コピペしてもコードの意味がわからないとダメダメね