@techs.empty?

2月 06

ssh-copy-idをmacosxで使えるようにする

ssh-copy-id というsshの公開鍵をリモートサーバーに登録する ちょっと便利なコマンドがあるんですが、macでbrewでインストールできなかったので、メモです。 下記のふぁいるを、/usr/local/binなどに作成します。

$ vi /usr/local/bin/ssh-copy-id
    #=> 下記のファイルを貼付け
$ chmod +x /usr/local/bin/ssh-copy-id
$ ssh-copy-id -i ~/.ssh/id_rsa.pub user@host #=> ~/.ssh/id_rsa.pub を指定したサーバーに設定
(ssh-copy-id)

#!/bin/sh



# Shell script to install your identity.pub on a remote machine

# Takes the remote machine name as an argument.

# Obviously, the remote machine must accept password authentication,

# or one of the other keys in your ssh-agent, for this to work.



ID_FILE="${HOME}/.ssh/id_rsa.pub"



if [ "-i" = "$1" ]; then

  shift

  # check if we have 2 parameters left, if so the first is the new ID file

  if [ -n "$2" ]; then

    if expr "$1" : ".*\.pub" ; then

      ID_FILE="$1"

    else

      ID_FILE="$1.pub"

    fi

    shift         # and this should leave $1 as the target name

  fi

else

  if [ x$SSH_AUTH_SOCK != x ] ; then

    GET_ID="$GET_ID ssh-add -L"

  fi

fi



if [ -z "`eval $GET_ID`" ] && [ -r "${ID_FILE}" ] ; then

  GET_ID="cat ${ID_FILE}"

fi



if [ -z "`eval $GET_ID`" ]; then

  echo "$0: ERROR: No identities found" >&2

  exit 1

fi



if [ "$#" -lt 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then

  echo "Usage: $0 [-i [identity_file]] [user@]machine" >&2

  exit 1

fi



{ eval "$GET_ID" ; } | ssh $1 "umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys" || exit 1



cat 

1月 25

Bundleではまった最悪なこと

状況

sporkを走らせようとしたが、なぜかrequire ‘spork’ができずこまった。rspec/railsもロードされていないし。 もう少し調べてみると、どうもGemfileのdevelop & test groupにいれたgemがロードできない。 なんじゃこりゃ〜

原因

サーバ側でbundle installした時に下記のコードで実行した。

 bundle install --without development test  

これ自体は問題はない。が、 ここから誰かがサーバ側で作業して、リポジトリにpushした。それを自分がpullした。 そうすると、.bundle/configというファイルが勝手にできていて、下記のようになっている。

1 --- 
2 BUNDLE_WITHOUT: development:test  

これによって、developmentとtestのgroup中のgemは無視されるらしい。。。

対処

上記の2行目を消す事は当然で、 予防策として、.hgignoreで必ず.bundleを無視しておく必要があると思う。 vim .hgignore

+ ^\.bundle  

参照

一応ここらへんに書いてあったが、もっとわかりやすくしておいてくれ〜 http://gembundler.com/groups.html

7月 13

rails2.3.9 -> 2.3.14にアップしたときの注意点

いまさらこんなレガシーなのを使っているのは、よろしくないが、 現実は3系にあげられないでいる。 そうすると、似たような問題を検索しても引っかかってこない。

現象

何かしらのオブジェクトに対して、ネストしたパラメータがあると、以前は行けたのに、アップ後はエラーとなる。

問題点

以前のバージョンでは、start_attributesのidからオブジェクトを取得しているようだが、アップ後はエラーを出している。

https://github.com/rails/rails/blob/v2.3.9/activerecord/lib/active_record/nested_attributes.rb
https://github.com/rails/rails/blob/v2.3.14/activerecord/lib/active_record/nested_attributes.rb

対処

おそらく、なんらかの理由があって、変更しているのだろうが、 これを使っている箇所全体を新しい書き方に変更するのはかなりのコストなので、 以前の書き方に戻すようにパッチを当てることにした。

config/initializers/active_record.rbとか適当にファイルを作成して

module ActiveRecord  
  module NestedAttributes #:nodoc:
    def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
      options = nested_attributes_options[association_name]
      attributes = attributes.with_indifferent_access
      check_existing_record = (options[:update_only] || !attributes['id'].blank?)

      if check_existing_record && (record = send(association_name)) &&
          (options[:update_only] || record.id.to_s == attributes['id'].to_s)
        assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy])

      elsif attributes['id']
        existing_record = self.class.reflect_on_association(association_name).klass.find(attributes['id'])
        assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
        self.send(association_name.to_s+'=', existing_record)

      elsif !reject_new_record?(association_name, attributes)
        method = "build_#{association_name}"
        if respond_to?(method)
          send(method, attributes.except(*UNASSIGNABLE_KEYS))
        else
          raise ArgumentError, "Cannot build association #{association_name}. Are you trying to build a polymorphic one-to-one association?"
        end
      end
    end
  end
end

6月 21

Basic認証がかかったHTTPサイトのresponse headerをtelnetで見る方法

続けて、HTTPのサイトをtelnetで見ることになったので同じようなネタでもう一つ

HTTPSと同じように、hogehoge.com:80をにアクセスしようとするとこんな感じです。 まずは、Basic認証がない場合から、

$ telnet hogehoge.com 80
> GET /index.html HTTP/1.1
> Host: hogehoge.com
> [returnを2回]

で、さらに、Basic認証がかかっているばあいは、

$ telnet hogehoge.com 80
> GET /index.html HTTP/1.1
> Host: hogehoge.com
> Authorization: Basic aG9nZWhvZ2U6aG9nZWhvZ2U=
> [returnを2回]

と、Authorizationも含めておくってあげればOKです。 Basicの後の文字列は、Basic認証なので、”ID:PW”をbase64化したものを送ればOKです。

 $ echo -n ‘hogehoge:hogehoge’ | openssl enc -e -base64 #=> aG9nZWhvZ2U6aG9nZWhvZ2U=

上記は、IDとPWがhogehogeの場合です。

HTTPSのサイトのレスポンスヘッダをTerminalだけで調べる方法

最初は、SafariやらChromeでやっていたのですが、面倒になったのでTerminalでやってみました。 ちょっとググったらあったのでメモしておきます。

例として、hogehoge.com の /index.html を調べることにします。

まずは、以下のコマンドで、接続します。

$ openssl s_client -connect hogehoge.com:443

この際、SSLの情報も見れます。 つづけて、

GET /index.html HTTP/1.1
Host: hogehoge.com
[さらにreturn]

と打ちましょう。returnを2回打たないといけないので注意です。 これで、気軽にレスポンスヘッダとSSLの情報がみれました。

6月 18

iOS6のpassbookのAPIを眺めてみた

passbook

WWDCで個人的に一番気になったのが、passbookでした。 passbookは、iOS6から乗るクーポンや映画チケットなどの管理アプリってところです。 NFCへの布石にもなっていそうな本アプリ。 web serverとどうやって連動するのか調べておこうという趣旨で、ざっとSDKを見てみました。

何となく分かったこと

所感

結論

ということで、盛り上がってくればなかなか面白いサービスなんじゃないかなと。 また、オリジナルのクープン等も発行できそうなので、状況を見てサービスに取り込んでいければなと思いました。

6月 07

node.jsでhttpのreq.headersから必要な情報を集めるメモ

メモ的に書いておきます。

console.log req.url
console.log new Date()
console.log req.headers['x-forwarded-for'] || req.connection.remoteAddress #=> 
console.log req.headers.referer
console.log req.headers["user-agent"]
console.log req.headers.cookie

以上。

6月 04

Android4系の標準ブラウザではbackbone.jsのRouterが無限ループする件

起こったバグ

Android4の標準ブラウザにて、構築したサイトを開いたら、なんとリダイレクトの無限ループ。

設定内容

backbone.jsのrouterを使用して、開かれたURLによって、実行するjsを切り替えていた。

原因

Android2系までは対応していたのに、3系以降対応しなくなったらしい。

http://d.hatena.ne.jp/zentoo/touch/20111130/1322667152

ちなみにこのサイト(http://fmbip.com/)で対応しているかどうかチェックできる。

で、backboneではpushStateに対応していないと、URLのパス部分をfragmentとして、

hashタグに変換して、リダイレクトする仕様になっているが、
そのあたりでどうも無限ループに陥っていた。

対処

Backbone.Historyの引数とかnavigateでなんとか設定できないか探してみたが、わからなかったので、外部からstartの関数を書き換えることにした。

今回の制約事項として、スマホのみ。なのでIEの行は不要


// Start the hash change handling, returning `true` if the current URL matches
// an existing route, and `false` otherwise.
Backbone.History.prototype.start = function(options) {

      if (Backbone.History.started) throw new Error("Backbone.history has already been started");
      Backbone.History.started = true;

      // Figure out the initial configuration. Do we need an iframe?
      // Is pushState desired ... is it available?
      this.options          = _.extend({}, {root: '/'}, this.options, options);
      this._wantsHashChange = this.options.hashChange !== false;
      this._wantsPushState  = !!this.options.pushState;
      // 20120603  mod for Android4.0
      //this._hasPushState    = !!(this.options.pushState && window.history && window.history.pushState);
      this._hasPushState    = !!(this.options.pushState && window.history);
      var fragment          = this.getFragment();
      var docMode           = document.documentMode;
      //var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode ').hide().appendTo('body')[0].contentWindow;
        //this.navigate(fragment);
      //}

      // Depending on whether we're using pushState or hashes, and whether
      // 'onhashchange' is supported, determine how we check the URL state.
      if (this._hasPushState) {
        $(window).bind('popstate', this.checkUrl);
      } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
        $(window).bind('hashchange', this.checkUrl);
      } else if (this._wantsHashChange) {
        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
      }

      // Determine if we need to change the base url, for a pushState link
      // opened by a non-pushState browser.
      this.fragment = fragment;
      var loc = window.location;
      var atRoot  = loc.pathname == this.options.root;

      // If we've started off with a route from a `pushState`-enabled browser,
      // but we're currently in a browser that doesn't support it...
      //if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
        //this.fragment = this.getFragment(null, true);
        //window.location.replace(this.options.root + '#' + this.fragment);
        //// Return immediately as browser will do redirect to new url
        //return true;

      //// Or if we've started out with a hash-based route, but we're currently
      //// in a browser where it could be `pushState`-based instead...
      //} else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
        //this.fragment = this.getHash().replace(routeStripper, '');
        //window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment);
      //}

      if (!this.options.silent) {
        return this.loadUrl();
      }
}

その他

そもそも、pushStateが使えなくても動くような、別なプラグインを入れるべきかもしれない。

スマホでアプリっぽいサイト作成

スマホでアプリっぽいWebシステムを作ろうとした時の設計について書いておきます。

基本情報


要点

  1. JqueryMobile(v1.1.0)を使って、さくっと構築しようとしたが、Androidでまともに動かず断念。。。
  2. jQueryのanimationでスライドイン、スライドアウトさせて、アプリっぽい動きをさせたが、結局、Androidでselect問題(=>前の記事参照)があり、断念。。。
  3. JQMを使っていた部分はそのままhtml描画して、その後にjsを動かしたが、それだけでカバーできない部分があったので、一部backbone.jsを使用した。

Androidのみ対応している部分


今後開発する際に確認しておくべき事

  1. JQMがもっとバージョンアップしたとしても、Androidで確実に動くか始めにチェックすべき
  2. Androidで動いているものはIphoneでほぼ動くので、基本Androidで確認していくべき。
  3. サーバのAPIを用意してから、backbone.jsで全て作るべき。

Opera miniについて

AndroidでシェアがそれなりにあるOpera miniは画面が崩れまくって、 リンクがおかしくなって、対応に相当かかるのでとりあえず対応から外した。 


6月 01

Fluentd: Log Everything in JSON -

Fluentd is a log collector daemon written in Ruby. Fluentd receives log as JSON streams, buffers them, and storeds or forwards to other systems like MongoDB, or even other instances of Fluentd.