廃墟

本ブログは更新を終了しました。 技術的な記事のみ、有用性を鑑みて残しておきます。

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での議論に準拠すると良いと思います。

angularjs - Rails CSRF Protection + Angular.js: protect_from_forgery makes me to log out on POST - Stack Overflow


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はどうするのか。
  • 追加機能開発なら、以前の機能や設計に問題があった場合にどうするのか。
  • 完全に新規の開発だとして、仕様の変更はどの程度、出てきそうか。
    • 現時点での不明瞭な仕様は誰が明確にするのか。自分?発注側?
  • 今後、自分が抜けた後で誰がメンテナンスするのか
    • ドキュメントをどのくらい整備すべきなのか

2.3. 計画を立てる

マイルストーン設定、ガントチャート、まぁそういうもので開発のスケジュールを立てましょう。
発注元のマネージャーが優秀でやってくれるなら任せても良いですが、大抵そんなことはないので、諦めて自分の方で明確化しちゃった方が楽です。(※個人差があります)

プロジェクトを完遂する

あとはプロジェクトを完遂しましょう。

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のサーバーサイドでは当然、パッケージマネジメントシステムが存在しますが、ソフトウェア開発においてもこれは非常に重要になります。

などなど。

こういったシステムを使うことの利点として以下があります。

  • ライブラリの公式の入手場所が辿りやすい
  • どこからどこまでがライブラリか分かりやすい
  • プロダクト特有のコードと、ライブラリのコードが分離される
  • ライブラリのバージョンアップがしやすい

相互に重複気味な表現もありますがご容赦。

Rails界隈の知識です

もしかするとTomcatなどから進化した界隈ではまた別の最適化があるかもしれません。 .NET界隈もVSでBootstrapが使える様になったりしてるらしいので、色々あるようです。 node界隈にも僕は詳しくないです。 PHPは知りませんが、Ruby界隈と割と業界が近いのでそれほど差異がないかRubyより劣る事が多いように思います。

ローカルで開発してリモートにデプロイ

基本的に、近年はローカルで開発して、リモートにデプロイするのが普通だと思います。 その方がGUIベースのIDEも使えるし、本番環境を壊す恐れが少ないからです。

但し、デプロイはセキュリティの観点や、考慮すべき事項の多さから往々にして属人的になりやすいです。詳しくは後述します。

コンパイルする簡易言語たち

アセンブリC言語の歴史をWebが同じように辿っているだけなのですが。
Webブラウザはその基盤となる言語を変更しにくいです。(CPUの命令セットが変更しにくいのと同様) HTML、CSSJavaScriptといったマークアップ言語およびプログラミング言語がそれにあたります。

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リクエストを減らすことができて、サイトの表示が非常に高速になります。

類似: hamlとslim

railsではhtmlコードを吐き出すためにerbという、PHPと似たような形式の、HTMLのRubyのコードを埋め込む仕組みが使われてきましたが、htmlの閉じタグってムダですよね。 ...ということで、最近はhamlやslimといった記法が使われます。

自動リロード

少し前から、自動リロードがアツいように思います。

検証する端末を全てデスクに広げておいて、コードを変更すると全てでリロードされる、なんてのも可能です。

livereload (guard-livereload)とか、Yeomanとか。

特に、HTML/CSSを記述するときはかなり手軽になって良いです。 マルチディスプレイとの相性が良いです。 表示を確認する画面、コードを書く画面、デザインファイルを参照する画面で3画面欲しいですね。 表示の確認はiPadとかのタブレットデバイスでも良いですけど。

ローカル環境の構築とデプロイ

デプロイ

デプロイは一般に面倒です。 ミスったときのロールバックはどうするのとか、変更されたファイルを選んでそれだけアップロードしたいなーとか、上記のコンパイルする言語を先にコンパイルしなきゃなーとか・・・。 で、その状況を放置して行くと、プロジェクトリーダーしかデプロイ方法が分からないといったことになって、リーダーが疲れているときに酷いミスをやらかして大変なことになるわけです。

これを防ぐために、デプロイの一連の処理はスクリプトとして記述するのが最近のトレンドです。
先のパッケージマネジャでライブラリをインストールするような処理もサーバー側で出来るので、直接転送する量が少なくて済む、なんてメリットもあります。

Rails界隈でのデプロイツールはCapistranoデファクトスタンダードです。普通はgitと併用します。

ローカル環境の構築

でもさ、複数人で開発してるときってローカル環境を構築するのが面倒じゃん。だから本番環境でそのまま開発すれば、よくね?

・・・という声が聞こえてきそうですが、一発殴って良いですかね?
面倒なのは事実なんですが、ChefとかVagrantとかで解決するようです。 基本的にはローカルにプロジェクト固有の開発用の仮想マシンを立ち上げて、開発者全員が同じ設定の開発環境を自動セットアップ出来るような仕組みです。 Chefに関しては本番環境で使うことの方が多いかも知れません。

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から書くよりはやいことが多いと思います。

JSフレームワーク

以前からjQueryデファクトスタンダードとなっていますが、より動的なシステムでは、JSフレームワークが流行っているようです。
特に、変数のバインディングの面倒を減らしてくれる、MVVMアーキテクチャを採用したものが主流です。 Angular.jsとかBackbone.js とかそのへん。

よく動くサイトを作るときに重宝するでしょうね。

bowerを使おう

JS、CSSフレームワークを導入するとき、ついついダウンロードして所定のフォルダに入れて満足してしまいがちですが、冒頭で述べたメリットの裏返しがデメリットとなってしまうわけですね。
なので、bowerを使ってパッケージ管理をしましょう。

rails界隈では、Sprockets周りのサポートなども自動でやってくれるrails-jqueryとかbootstrap-sassとかいうgemが数多く用意されてるんですが、若干ブラックボックスが多くて、一長一短だったり。 Railsアプリを書いてる時はgemベースのものでも良いですが、bowerは他の環境でも使えるので良いです。

IDEもご検討下さい

ぼくはRubyMineちゃん!

vimとかemacsとかで出来るのは分かるのですが、個人的にはGUIによる開発の方が好みです。 環境構築に時間をかける必要が少ない気がします。 まぁ、お金払ってるし。。

おわりに

珍しく早起きしたので、脳内にあったWeb知識を一気に解放してみました。

7年ぐらい前はYahooのYUIが強かったと思うんですが、最近はGoogle,Twitterあたりが便利なものを出してるみたいです。
加えて、Web自体がここ数年で経済的にもかなり発達したので、上記のようなWeb開発をサポートすること自体をビジネスにしている会社も増えた様に思います。 herokuとかその辺ですね。

これからも、Web業界は発展を続けるでしょう。 どんな風になってるか、楽しみですね。

Middlemanでグローバルナビゲーションの今見ているページへのリンクにcurrentクラスをつける

Middleman便利ですね。

Webサイトといえばナビゲーションとかメニューが普通だとありますよね。 もちろんpartialなりlayoutなりに書いていると思うのですが、こうやって共通化してしまうと、一個だけ困る事があります。
まぁ、タイトルから推測がつくでしょう。 今みているページを示すナビゲーション要素を装飾したいときに困るんですよね。

f:id:akn_ep:20140409171205p:plain

こんな感じ。今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 なりを見て検査すれば何とかなると思います。