DTI@VPS 上のRailsからSendGridを使うとタイムアウトする問題の解決策
Railsからのメール送信にSendGridを使う様に変更してたら起きた問題。誰かの役に立つかもしれないので、メモ。
遭遇した現象とか雑多気味なメモ
SendGridの通例通りsmtpの設定をしてみた、けれどうまく送信されないという現象に遭遇。 同じコードをローカルで立ち上げるとちゃんとメールが送られる。なんじゃこりゃ。と。
動作を見る限りでは、タイムアウトの気配なので、おもむろに以下の様に確認した。
$ telnet smtp.gmail.com 465
まずビンゴで、telnetが通っていない事が判明。
試しにufw disable
すると、上記のtelnetが通った。
→ 原因がファイヤーウォールに搾られた
次に iptables -L
してやると、ESTABLISHED,RELATEDが読まれていない事が確認できる。何か変だぞ、と。 他の似たような設定を為ている環境でiptables -Lした結果と全然ちがう。
ここで、試しに以下の様にしてみる。
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
すると、きちんと繋がる。
(しかしここではufw経由で設定出来ないと困るなーと思っていたら、うっかりiptables -F
しちゃってサーバーからSSHがBANされたので、一回VPSの管理コンソールから再起動。)
その他の途中で見てた不穏なエラーメッセージ
検索でだれかが行き着くように、遭遇した不穏なエラーメッセージを書いておく。
problem running ufw-init # とか… iptables: Bad rule (does a matching rule exist in that chain?). # とか…
結論
どうやら OpenVZ環境でufw を使っていると起きるらしい。 (DTIはOpenVZ、らしい)
そういうわけで、以下のサイトの内容の通りにしたら上手く動作してくれました。
Angular.js と Rails の form_for を良い感じに連携する
最近とある案件で Angular.js を使い始めたのですが。
どうにもRailsと相性がそこまで良くないというか、2つの世界をCoCで繋ぐ決定的なgemなどが出てきていないからか、不便さを感じます。
そんな中で、特に不便に感じたのが、form_for がロクに使えないことでした。
$ rails g model post title:string
みたいなモデルを想定してください。
愚直にやると、Angualr.jsで非同期にPOSTする時のformは、こんな感じになってしまいます。
# slim記法の例 div 'ng-controller'=>'PostCtrl' = form_for(@post, html:{ 'ng-submit'=>'submit()' }) do |f| = text_field :title, 'ng-model' => 'post.title' = button :submit end
うーん、何かこう、いけ好かないですよね。 同じ様な事を何回も書いてるし…
ということで、こんなのを作ってみた。
# /app/helpers/angular_form_builder.rb # http://uzuki05.hateblo.jp/entry/2013/04/05/114356 class AngularFormBuilder < ActionView::Helpers::FormBuilder def ng_text_field(method, options = {}) options[:html] ||= {} @template.text_field(@object_name, method, objectify_options(options[:html].reverse_merge!(ng_options(method)))) end # TODO: text_field 以外の互換メソッドも用意しましょう private def ng_options(method) { 'ng-model' => "#{@object_name}.#{method}", } end end
# /app/helpers/application_helper.rb module ApplicationHelper def ng_form_for(*args, &proc) args << {} unless args.last.is_a?(Hash) options = args.last if args.first.is_a?(Symbol) options.merge!(as: args.shift) end options.reverse_merge!( builder: AngularFormBuilder, format: :json, html: { 'ng-submit' => 'submit()' } ) form_for(*args, &proc) end end
これを使うと、フォーム部分は以下の様に書けます。
# slim記法の例 div 'ng-controller'=>'PostCtrl' = ng_form_for(@post) do |f| = ng_text_field :title = button :submit end
あとは、Angular.jsのControllerをこれに準拠して書いていけば、それなりに柔軟さを保ちつつ、RailsのFormBuilderだけで概ね記述できて良いんじゃないかな、と思います。
ちなみに、CSRF対策については以下のStackoverflowでの議論に準拠すると良いと思います。
Angular.js触って2日目ぐらいなので、もっと良い方法あったらおしえてください!
AFNetworking 2.2あたりから中間証明書が必須になった
今作っているiPhoneアプリで、 pod update をしただけで、一切のAPI呼び出しが出来なくなった。
curlコマンドを打っても、GETで叩ける部分をChromeで呼んでも、何も問題ないので、サーバーは正常?に思える。
多少は分かりやすいエラーが出てるかと思ってエラーメッセージを見てみても、-999ステータスで、TaskがCancelされたみたいなことしか出てこない。 cancelなんかしてねーよ??
結局、SSLの設定状況をチェックしてくれるサイトでAPIサーバーをチェックしてみたら、中間証明書がサーバーから提供されてないよってエラーが… これかーーーー!
サーバー側を直したら問題なく通信出来るようになりましたとさ。
新規案件を請ける時に気をつけていること
今回は、フリーランス専業になって数ヶ月経過した僕が、新しく案件を請ける時に気をつけた方が良いな、と思っている事を書いてみます。
おそらく、フリーランスに限らず、社内プロジェクトに新しく参加した場合とかでも一緒なんだと思います。 普通の会社に在籍したことがないから良く知らないけど。
よくこの手の記事では、契約の範囲や賃金などについて語られますが、ここではそういった事には殆ど触れていません。(僕も詳しくないんだ、すまない。)
ちなみに、請け負うプロジェクトが以下のことに当てはまる場合、特に顕著に効いてくると思います。
- 在宅/リモートワークである
- 今まで一緒に仕事をしたことのある人が少ない
- 緊急の案件である
1. プロジェクトの状況を把握する
プロジェクトが完全に初期の空白状態、という事は稀です。どんなにまっさらなプロジェクトでも、以下の様な事が決まっているはずです。
- ターゲットとなる顧客
- 与えたいベネフィット
- 大まかな規模感
もし、これら決まっていない場合、まずはそこから決めないとプロジェクトが失敗するのは明白なので、促しましょう。
また、もう少し詳しいものだと、他の人がプロトタイプを作ったことがあったり、既にデザイナーへの発注などによって画面の基本構成が決まっていたり、まぁ多種多様です。
とにかく、現状把握には多少の時間がかかります。
必要以上に情報を隠したがる方とは仕事をしない、というのも視野に入れて良いと思います。 仕事しにく過ぎるので。
1.1. 人的な現状を把握する
既に参加している人に、プロジェクトに関係する人と担当範囲を列挙してもらいましょう。
スキルセットや契約の形態まで聞けるとベターです。 他にやっていることがあって片手間の人かもしれません。 あなたより経験の浅いエンジニアかもしれません。
ちなみに、発注者がプロジェクトに関する全容を知らなかったりするケースは、嫌な予感がぷんぷんするので、慎重に掘り下げて聞いていく必要があります。
1.2. 技術的な現状を把握する
プログラムやサーバー構成について、なるべく広い範囲にわたって把握しておいた方が良いです。
後から聞くのは面倒臭いので、一気に構成図とかを書けるぐらいまで聞いてしまうのがベターです。
2. これからの動きを明確化する
監査にきたのではなく仕事をしにきたのだから、現状が分かったら、これからの動きについて計画を立てていく必要があります。
2.1. 連絡手段・頻度を明確化する
Skypeが良いのかメールが良いのか、定例で事務所に行くのか、常駐なのか。
常駐だとしても、ミーティング頻度はどうなのか。 他のメンバーも常駐なのか。
そういった事もハッキリさせておくと良いです。
2.2. 担当する作業の範囲・期間を明確化する
ここまで出来てやっと、自分が担当する作業の範囲や納期を見積もることが可能になります。ここの順序を間違えないでください。おそらくは金額的な見積もりが出来るのもこの段階まで来てからです。
また、だいたいプログラマーは自分の能力を過信するので、自分の作業量はほどほどにしておきましょう。 1日のうち集中して作業出来る時間は3〜4時間程度だと思っておくと良いです。(実際そうだろ?えっ、そうじゃない?お前みたいなデキる奴のことは、知らん!)
2.2+. 周りと協調して動けるか想像する
担当作業をやっていればプロジェクトは完遂するでしょうか?以下の様な類いの落とし穴に気をつけてください。
- モバイルアプリを作っているなら、サーバーサイドのAPIはどうするのか。
- 追加機能開発なら、以前の機能や設計に問題があった場合にどうするのか。
- 完全に新規の開発だとして、仕様の変更はどの程度、出てきそうか。
- 現時点での不明瞭な仕様は誰が明確にするのか。自分?発注側?
- 今後、自分が抜けた後で誰がメンテナンスするのか
- ドキュメントをどのくらい整備すべきなのか
プロジェクトを完遂する
あとはプロジェクトを完遂しましょう。
3.1. プロジェクトが動き出したら、積極的に動く
自分の動く範囲は確かに明確化した通りなのですが、多少は「おまけ」しても良いでしょう。
自分が参画したプロジェクトが失敗に終わるよりは、成功した方が箔がつきます。
ついつい自分の作業範囲を小さく見積もりたくなりますが、先方の期待とはズレている可能性がありますから、動かしながら意識の摺り合わせをするのが良いでしょう。
おわりに
駆け足でしたが、数年間、いろいろなプロジェクトをやってきて思う所をざっとまとめてみました。
おかげさまで9月末までは、ほとんどイッパイイッパイですが、何かお仕事の相談などありましたら、お気軽にどうぞ。
MiddlemanでBootstrap-sassを使うとGlyphiconsが出ないことへの対処法
最近Middlemanにハマってます。
ここのページには、Bootstrap-sassを使うには単に
# Gemfile gem "bootstrap-sass", :require => false
で良いように書いていますが、これだけだとGlyphiconsが表示されません。
これに対処するには、config.rb中で以下のように読み込む必要があります。
# config.rb require "bootstrap-sass/sass_functions.rb"
尚、自分のブログでぶつくさ言ってるだけでContributeしないのは良くないので、Pull Request として送っておきました。
最近のWeb開発技術フロントエンド周りのまとめ(2014年)
主に知人向けに、最近のWeb開発技術について、私が最近知る限りの事をまとめておきます。
VagrantとかChefみたいに、おおまかに知っているだけで使ってないものも紹介しています。間違いがあったらコメントを頂ければ訂正しますので、ご指摘下さい。
また、フロントエンドよりの記述が多く、インフラやバックエンドのことには触れていません。
大前提
パッケージマネジメントシステムの有用性
Linuxのサーバーサイドでは当然、パッケージマネジメントシステムが存在しますが、ソフトウェア開発においてもこれは非常に重要になります。
- Java: sbt (Simple-Build-Tool)
- ruby: rubygems (gem)
- JavaScript: bower
などなど。
こういったシステムを使うことの利点として以下があります。
- ライブラリの公式の入手場所が辿りやすい
- どこからどこまでがライブラリか分かりやすい
- プロダクト特有のコードと、ライブラリのコードが分離される
- ライブラリのバージョンアップがしやすい
相互に重複気味な表現もありますがご容赦。
コンパイルする簡易言語たち
アセンブリ、C言語の歴史をWebが同じように辿っているだけなのですが。
Webブラウザはその基盤となる言語を変更しにくいです。(CPUの命令セットが変更しにくいのと同様) HTML、CSS、JavaScriptといったマークアップ言語およびプログラミング言語がそれにあたります。
Sass(SCSS) および LESS
SassとLESSは、CSSを書き出すための言語です。
私は数年前はLESSを使っていたのですが、 @extend が使える点などから、今ではSassに乗り換えています。
簡単にCSSが書けるだけであれば、大きな利便性はないのですが、@extend、@mixinなどの機能と、後述するCSSフレームワークとの相性が抜群です。
CoffeeScript
JSはプロトタイプベースだったり、this問題が起きたり、そもそも言語を問わず非同期処理は難しかったり、DOMが難しかったり、身につけるのが大変な言語ですが、CoffeeScriptは、それを少しだけ楽にしてくれます。少しだけです。
minifyとの相性
css,jsはminifyすることがありますが、セミコロンがないJSとかだと、minifyしたときにバグを生んでしまうことがあります。 上記の言語を使っていると、そういった問題が起きにくいように思います。
リソースをコンパイルするSprockets
Rails3.1に導入されたAsset pipeline(及びベースとなるSprockets)では、js,cssを簡単にコンパイルすることが出来る上、ハッシュ値を利用してキャッシュが有効にならないようにするなどの機能も有していて便利です。
また、上記のパッケージマネジャとの相性も考えられていて、パッケージマネジャで追加されたライブラリをJSやCSSの先頭で指定することで、それらを読み込むようにできます。(require, require_tree)
読み込んだファイルはSprocketsの設定にも依りますが、小規模なサイトであれば1つのJS,CSSに統合してしまうのが良いです。 そうすることで、コストの高い無駄なHTTPリクエストを減らすことができて、サイトの表示が非常に高速になります。
自動リロード
少し前から、自動リロードがアツいように思います。
検証する端末を全てデスクに広げておいて、コードを変更すると全てでリロードされる、なんてのも可能です。
livereload (guard-livereload)とか、Yeomanとか。
特に、HTML/CSSを記述するときはかなり手軽になって良いです。 マルチディスプレイとの相性が良いです。 表示を確認する画面、コードを書く画面、デザインファイルを参照する画面で3画面欲しいですね。 表示の確認はiPadとかのタブレットデバイスでも良いですけど。
ローカル環境の構築とデプロイ
デプロイ
デプロイは一般に面倒です。 ミスったときのロールバックはどうするのとか、変更されたファイルを選んでそれだけアップロードしたいなーとか、上記のコンパイルする言語を先にコンパイルしなきゃなーとか・・・。 で、その状況を放置して行くと、プロジェクトリーダーしかデプロイ方法が分からないといったことになって、リーダーが疲れているときに酷いミスをやらかして大変なことになるわけです。
これを防ぐために、デプロイの一連の処理はスクリプトとして記述するのが最近のトレンドです。
先のパッケージマネジャでライブラリをインストールするような処理もサーバー側で出来るので、直接転送する量が少なくて済む、なんてメリットもあります。
Rails界隈でのデプロイツールはCapistranoがデファクトスタンダードです。普通はgitと併用します。
CSSフレームワーク、JSフレームワーク
CSSもJSも、毎回似たようなことばかり書くのに辟易した偉い人達が、さまざまな知見を集約してくれました。昔とは大違いなので、CSSを1から書くとか、もうやめましょう。
CSSフレームワーク
特に有名なのがTwitter Bootstrapでしょう。 バージョン3ではHTML5対応、レスポンシブデザイン対応が行われ、クラス名も以前のrow-fluidといった面倒なのが減って、デザインも含めて以前より洗練されました。
バージョン3になってからは「これBootstrap臭がするな・・・」といった、特有の画面になることが減ったように思います。 トレンドがシンプルな(いわゆるフラット)デザインになっているのも大きいでしょうね。
にわかCSS原理主義者は、Bootstrapを使うとHTMLに直接classを定義するからセマンティックではないといったことを言うかもしれませんが、上記のsassを使うとそういった事はなくせます。自分が独自に定義したclassでextendすれば良いのですね。 尚「にわかCSS原理主義者」というのは過去の私です。。。
短いファイルでもsassのコンパイルに10秒以上かかるのがネックでしょうか。 でも、1から書くよりはやいことが多いと思います。
Middlemanでグローバルナビゲーションの今見ているページへのリンクにcurrentクラスをつける
Middleman便利ですね。
Webサイトといえばナビゲーションとかメニューが普通だとありますよね。 もちろんpartialなりlayoutなりに書いていると思うのですが、こうやって共通化してしまうと、一個だけ困る事があります。
まぁ、タイトルから推測がつくでしょう。 今みているページを示すナビゲーション要素を装飾したいときに困るんですよね。
こんな感じ。今Homeにいるから下にバーが出てる、という例。
ここで「しょうがない、メニューぜんぶ個別のページに書くか・・・」なんて考えるのはちょっと早い! 何とかするのが技術者、と思うわけです。
というわけで以下ハウツー。
本題
ヘルパーを追加する
まず、以下のヘルパーを追加しておきます。
"current_page?" はRailsなんかだとUrlHelperに含まれているのですが、Middlemanにはないので、適当に作ってしまいます。
# config.rb require "lib/helpers" helpers Helpers # lib/helpers.rb module Helpers def current_page?(path) current_page.url == path end def nav_link(link_text, link_path) class_name = current_page?(link_path) ? 'current' : '' content_tag(:li, :class => class_name) do link_to link_text, link_path end end end
directory_indexes をオンに
以下のコードも適当な位置に追加しておいてください。
#config.rb activate :directory_indexes
ナビゲーションのパーシャルを定義
僕はslim派ですが、別に何でも良いと思います。
/_nav.slim ul = nav_link "Home", '/' = nav_link "Profile", '/profile/' = nav_link "Works", '/works/' = nav_link "Links", '/links/' = nav_link "Contact", '/contact/'
ここで、先のcurrent_page? の実装が甘いので、最後のスラッシュが必要になります。
directory_indexes がオフな環境でどうするかは調べていないのですが、適当にcurrent_page.url なり current_page.path なりを見て検査すれば何とかなると思います。