たこぼんげブログ

大学院博士課程から脱落してWEB業界に就職しました。

Chromeの拡張機能MultiLoginが使えない。→使えた。

f:id:takobonge:20160428230444j:plain

ある日、突然、MultiLogin使えなくなりました。
なんとか使えるようになったので、その方法をメモ。

MultiLoginはsessionをタブごとに切り替えてくれます。
同じサイトで別アカウントでログインしたい時にシークレットウィンドウとか別ブラウザとか使わなくてOKな超便利な拡張機能でした。

使えなくて果てしなく困ってたのですが、以下の方法で使えました。

  1. 以下のページからcrxファイルをダウンロード
    https://mega.nz/#!iYUCURjZ!67quw6aQ2RYEOEW9pX_f1A1hSwc48QV8Z9-X5OUKmYo

  2. cromeの拡張機能のページに反映
    chrome://extensions/
    を開いてページにcrxファイルをドラッグアンドドロップ

  3. 勝ちました。

【追記 2016/05/10】
openMultiLoginというのが新しく出ているようです。

chrome.google.com

PushCrew(プッシュクルー)の使い方

f:id:takobonge:20160227093915p:plain:w200

プッシュ通知をブラウザに遅れるサービスが最近リリースされたみたいです。
PushCrew(プッシュクルー)
今作ってるサービスはスマホアプリにして通知をできるようにしたいと思っていたのですが、
スキルがないのでまずwebアプリを作りました。
このサービスを使えば、ブラウザを通してプッシュ通知することが可能ということで、
早速使ってみみました。

PushCrew(プッシュクルー)

PushCrewはサイトを訪れたことがあり、通知を許可してもらったユーザーに対して、
サイトにアクセスしていない状態でもブラウザを通してプッシュ通知を遅れるサービスです。
使い方は非常に簡単です。

使い方

1. サイトにアカウントを登録する

f:id:takobonge:20160227091136p:plain:w400
your-website.comには通知を送りたいあなたのwebサービスのURLを入力します。
これが異なるところで通知を許可しても、通知は行われません。

2. サイトにjavascriptタグを埋め込む

アカウントを作成してログインすると、トップページに埋め込み用のjavascriptタグがあるので、コピーしてサイトのテンプレートファイルに貼り付けます。 f:id:takobonge:20160227091807p:plain

3. ユーザーがサイトにアクセスしたら通知を許可してもらう

この時点で、サイトにアクセスすると通知許可を求めるポップアップが出ると思います。
許可をしてもらうと、PushCrewの管理画面から許可をしてもらったユーザーの数がインクリメントされます。
f:id:takobonge:20160227092407p:plain:w300

4. 通知を送ってみる

管理画面の「Send New Notification」ボタンを使って通知を送ってみましょう。
ブラウザが開いていれば、あなたのサイトを閉じていても通知が届くはず! f:id:takobonge:20160227092715p:plain:w300

5. スマホに通知する

元々これをやりたかった!
と思ったらこれは有料プラン。。 断念。

他にもいくつか同じようなサービスがあるようです。
今後、このプッシュ通知サービスが流行るかもしれません。
プッシュ通知をブラウザに送るサービスが複数登場、今年の流行になるか? | インターネット関連ニュース | はじめてWEB

pushcrew.com

【FuelPHP】simpleauthをカスタマイズして拡張する

FuelPHPのsimpleauthは便利でよく使います。
ただ、決まったフィールド以外のパラメータはprofile_fieldsにシリアライズしてぶち込む仕様となっています。
カスタマイズしてちゃんとカラムとして追加できるようにしました。
まず、以下のファイルを用意します。

fuel/app/config/auth.php

<?php

return array(
    'driver'                 => 'Myauth',
    'verify_multiple_logins' => false,
    'salt'                   => 'random_string',
);

driverをこれから作成するclass名に設定します。ここでは「Myauth」としました。
saltにはランダムな文字列を入れてください。

次に、

fuel/app/classes/auth/acl/myacl.php  
fuel/app/classes/auth/group/mygroup.php  
fuel/app/classes/auth/login/myauth.php  

の3つのファイルを作成します。
これらのファイルの中身をそれぞれ

fuel/packages/auth/classes/auth/acl/simpleacl.php  
fuel/packages/auth/classes/auth/group/simplegroup.php  
fuel/packages/auth/classes/auth/login/simpleauth.php  

からコピーします。

この時、classを

class Auth_Login_Myauth extends \Auth_Login_Simpleauth

のように元のsimpleauthのクラスを継承し、configに描いたdriverの名前でclass名を定義します。

あとは、カスタマイズしたいメソッド以外は削除して、カスタマイズするメソッドをこちらのMyauthに記述すればカスタマイズできます。

冒頭で書いた任意のカラムを追加できるようにカスタマイズする場合は、
ユーザー作成とユーザー編集のメソッドをカスタマイズします。

fuel/app/classes/auth/login/myauth.php

<?php

class Auth_Login_Myauth extends \Auth_Login_Simpleauth
{
    /**
    * @var  array  value for guest login
    */
    protected static $guest_login = array(
        'id'         => 0,
        'username'   => 'guest',
        'group'      => '0',
        'login_hash' => false,
    );

    /**
    * Create new user
    *
    * @param   string
    * @param   string
    * @param   string  must contain valid email address
    * @param   int     group id
    * @param   Array
    * @return  bool
    */
    public function create_user($username, $password, $email, $group = 1, Array $user = [])
    {
        $password = trim($password);
        $email = filter_var(trim($email), FILTER_VALIDATE_EMAIL);

        if (empty($username) or empty($password) or empty($email))
        {
            throw new \SimpleUserUpdateException('Username, password or email address is not given, or email address is invalid', 1);
        }

        $same_users = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
            ->where('username', '=', $username)
            ->or_where('email', '=', $email)
            ->from(\Config::get('simpleauth.table_name'))
            ->execute(\Config::get('simpleauth.db_connection'));

        if ($same_users->count() > 0)
        {
            if (in_array(strtolower($email), array_map('strtolower', $same_users->current())))
            {
                throw new \SimpleUserUpdateException('Email address already exists', 2);
            }
            else
            {
                throw new \SimpleUserUpdateException('Username already exists', 3);
            }
        }

        $user['username']   = (string) $username;
        $user['password']   = $this->hash_password((string) $password);
        $user['email']      = $email;
        $user['group']      = $group;
        $user['created_at'] = \Date::forge()->get_timestamp();

        $result = \DB::insert(\Config::get('simpleauth.table_name'))
            ->set($user)
            ->execute(\Config::get('simpleauth.db_connection'));

        return ($result[1] > 0) ? $result[0] : false;
    }

    /**
    * Update a user's properties
    * Note: Username cannot be updated, to update password the old password must be passed as old_password
    *
    * @param   Array  properties to be updated including profile fields
    * @param   string
    * @return  bool
    */
    public function update_user($values, $username = null)
    {
        $username = $username ?: $this->user['username'];
        $current_values = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
            ->where('username', '=', $username)
            ->from(\Config::get('simpleauth.table_name'))
            ->execute(\Config::get('simpleauth.db_connection'));

        if (empty($current_values))
        {
            throw new \SimpleUserUpdateException('Username not found', 4);
        }

        $update = [];
        if (array_key_exists('username', $values))
        {
            throw new \SimpleUserUpdateException('Username cannot be changed.', 5);
        }
        if (array_key_exists('password', $values))
        {
            if (empty($values['old_password'])
                or $current_values->get('password') != $this->hash_password(trim($values['old_password'])))
            {
                throw new \SimpleUserWrongPassword('Old password is invalid');
            }

            $password = trim(strval($values['password']));
            if ($password === '')
            {
                throw new \SimpleUserUpdateException('Password can\'t be empty.', 6);
            }
            $update['password'] = $this->hash_password($password);
            unset($values['password']);
        }
        if (array_key_exists('old_password', $values))
        {
            unset($values['old_password']);
        }
        if (array_key_exists('email', $values))
        {
            $email = filter_var(trim($values['email']), FILTER_VALIDATE_EMAIL);
            if ( ! $email)
            {
                throw new \SimpleUserUpdateException('Email address is not valid', 7);
            }
            $matches = \DB::select()
                ->where('email', '=', $email)
                ->where('id', '!=', $current_values[0]['id'])
                ->from(\Config::get('simpleauth.table_name'))
                ->execute(\Config::get('simpleauth.db_connection'));
            if (count($matches))
            {
                throw new \SimpleUserUpdateException('Email address is already in use', 11);
            }
            $update['email'] = $email;
            unset($values['email']);
        }
        if (array_key_exists('group', $values))
        {
            if (is_numeric($values['group']))
            {
                $update['group'] = (int) $values['group'];
            }
            unset($values['group']);
        }

        $update = $update + $values;

        $update['updated_at'] = \Date::forge()->get_timestamp();

        $affected_rows = \DB::update(\Config::get('simpleauth.table_name'))
            ->set($update)
            ->where('username', '=', $username)
            ->execute(\Config::get('simpleauth.db_connection'));

        // Refresh user
        if ($this->user['username'] == $username)
        {
            $this->user = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
                ->where('username', '=', $username)
                ->from(\Config::get('simpleauth.table_name'))
                ->execute(\Config::get('simpleauth.db_connection'))->current();
        }

        return $affected_rows > 0;
    }

}

以上です。
うまくいってない部分あったら教えて下さい。

2015年に読んだ本

2015年に僕が読んだ本27冊をまとめました。
挫折したり面白くなくて途中でやめたやつも含みます。
内容を覚えてない本が多いけど、
サーっと読んで自然と頭に残ったものを大事にする作戦で読んでるので、
覚えてない内容=今は必要ない内容
ってことかな。タイミングが悪いとこうなる。
もしくは完全に咀嚼して自分の中に落とし込んだ内容。
考え方が当たり前になってるとどこから仕入れたかは関係ない。

それではどうぞ。

エリック・エヴァンスのドメイン駆動設計

第二部まで読みました。
十分に理解はできなかったけど、かなり勉強になった。
来年も引き続き噛み砕きながら読み進める。
エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

アジャイル開発とスクラム

タイトル通りアジャイル開発の本。
ちゃんとした1つのやり方を学べました。
まだマネージメントする機会はあんまりないけど、 機会があれば実践したい。
内容の一部分でも使えそう。 在庫を抱えてはだめ。
考え方はどこかで役に立つ気がする。
アジャイル開発とスクラム 顧客・技術・経営をつなぐ協調的ソフトウェア開発マネジメント

0ベース思考

途中で止まりました。
面白さの片鱗は感じた。
先入観なく物事考える的な本。
0ベース思考---どんな難問もシンプルに解決できる

エッセンシャル思考

シンプルに物事を考える。
めっちゃ良かった!
みなさん読みましょう。
エッセンシャル思考 最少の時間で成果を最大にする

なぜ、この人と話をすると楽になるのか

途中でやめました。
良さが全然分からんかった。
なぜ、この人と話をすると楽になるのか

デキる人の敬語の正しい使い方

あんま内容覚えてない。
普通の敬語の教科書やったな。
読んでて面白くはなかった。
デキる人の敬語の正しい使い方: ――――「あなたは、何のために敬語を使うの?」

道をひらく

途中までしか読んでない。
教訓集的な奴。
道をひらく

強運を引き寄せる! 魔法の「口ぐせ」リスト

良かった気がするが、あまり覚えてない。
強運を引き寄せる! 魔法の「口ぐせ」リスト

未来記憶

かなり良かった!
目標は行動のスピード感を決めるためのもの。
達成できなくてOK。
未来記憶

決断力

これも良かった!
ただあんま覚えてない。もう1回読も。
決断力 (角川oneテーマ21)

嫌われる勇気

流行ってたので読みました。
全ての悩みは人間関係に由来するもの。
トラウマなんてない!思い込み!
とりあえず、みんな読めばいいと思います。
嫌われる勇気―――自己啓発の源流「アドラー」の教え

お茶でも飲みながら会計入門41のきほん

読みやすかった。
ちゃんと入門できた。
どこかで役に立つかな。
お茶でも飲みながら会計入門41のきほん もとSE、いま公認会計士がやさしく解説[ほのぼの図解] impress QuickBooks

生き方

「手の切れるような」という形容詞は気に入りました。
他の内容はあまり共感できない。
生き方―人間として一番大切なこと

資本論 (まんがで読破)

労働者を使ってどうやって利益を出すかって話。
かなり勉強になった!
簡単に読めるのもまたいい。
資本論 (まんがで読破)

続・資本論 (まんがで読破)

上記の続編。こちらも面白かったです。
続・資本論 (まんがで読破)

ザ・ゴール コミック版

ボトルネックをつぶせ。
在庫を抱えてはだめ。
考え方はどこかで役に立つ気がする。
ザ・ゴール コミック版

金持ち父さん貧乏父さん

薦められて読みました。
こういう世界があることを知っておくのはいいと思います。
金持ち父さん貧乏父さん

金持ち父さんのキャッシュフロー・クワドラント

金持ち父さん貧乏父さんの続編。
より具体的な話。
これも一読の価値あり。
改訂版 金持ち父さんのキャッシュフロー・クワドラント:経済的自由があなたのものになる (単行本)

金持ち父さんの若くして豊かに引退する方法

内容あんま覚えてない。
改訂版 金持ち父さんの若くして豊かに引退する方法 (単行本)

夢をかなえるゾウ

自己啓発の入門書にいい。
ストーリーは面白かった。
自己啓発本としては自分には物足りない。
夢をかなえるゾウ 文庫版

ゼミナール ゲーム理論入門

昔から興味があったので読んでみた。
理論としては面白いよね。
ジョン・ナッシュ。映画ビューティフル・マインドのモデルの人ね。
ゼミナール ゲーム理論入門

道具としてのベイズ統計

こちらも興味があったので読みました。
考え方は面白い。
実際に使えるかといえば、どうやろ。
道具としてのベイズ統計

地道力

ビジネスをしたい人向け。
体力のある若いうちに張り切って働こう。
地道力[新版] 目先の追求だけでは、成功も幸せも得られない!

俺のフィロソフィ

内容あんま覚えてない。
俺のフィロソフィ  仕組みで勝って、人で圧勝する俺のイタリアンの成功哲学

たった一人の30年戦争

たった一人の30年戦争

素数の音楽

リーマン予想の本。量子力学とも絡むのね。
面白かった!
ゲーム理論にも出てくるジョン・ナッシュもリーマン予想に取り憑かれました。 素数の音楽 (新潮文庫)

21世紀の資本

すみません。
半分で挫折しました。
21世紀の資本

今年もまだあと2時間半ある。
あと1冊くらい読めるな。

リアクション大事

小2の甥っ子に掛け算のひっ算教えました。
学校では九九を習っているようです。

まず12 x 3を教えます。

1の位、2 x 3 = 6
10の位、1 x 3 = 3

36。

甥っ子「すげぇ!」

思った以上に良い反応。

次に1324 x 2 を紙に書いたところ、

「まさか・・」と甥っ子。

2648。

口に手を抑えながら「うそやろ・・すげえ!!!」
とニヤニヤが止まらない様子。

リアクションは大事です。

FireFoxでもjQueryUIのSortableを使う。

jQueryUIのSortable

お馴染みのjqueryUIプラグインのsortable。 ドラッグ&ドロップで要素を並び替えできます。
古い記事だけを参考にするとFireFoxでうまく動作しない部分があったのでメモ。

サンプル

jqueryjquery-uiのscriptは読み込んだ状態で、

<ul id="jquery-ui-sortable">
    <li>項目1</li>
    <li>項目2</li>
    <li>項目3</li>
    <li>項目4</li>
    <li>項目5</li>
</ul>
<script>
$(function() {
    $('#jquery-ui-sortable').sortable().bind('click.sortable mousedown.sortable',function(ev){
        ev.target.focus();
    });
});
</script>

と書きます。 もしかしたら.bind以降は不要かも。

失敗パターン1

<script>
$(function() {
    $('#jquery-ui-sortable').sortable();
    $('#jquery-ui-sortable').disableSelection();
});
</script>

disableSelectionはjquery-uiのv1.9で非推奨となっています。 FireFoxでうまく動作しませんでした。 中にFormがあると、inputとかtextareaにFocusできなくなります。

失敗パターン2

<script>
$(function() {
    $('#jquery-ui-sortable').sortable();
    $('#jquery-ui-sortable').disableSelection().delegate('input,textarea','click',function(ev){
        ev.target.focus();
    });
});
</script>

MacFireFoxではいけましたが、WindowsFireFoxでうまく動作しませんでした。

参考

上の2つは参考にしましたが、記事が古いですね。

RailsでSB-Adminを使う

Rails4に管理画面用テンプレートのSB-Admin2を入れました。
bootstrapとかfontはgemで入れるようにしたので、必要なgemとかをまとめます。

startbootstrap.com

SBAdminのファイル群をダウンロードしてきたら、必要なcssやjsファイルは vendor/assets/の中のstylesheetsとjavascriptsにそれぞれ入れます。

bootstrapとfontはgemで入れます。

  • bootstrap-sass
  • font-awesome-rails

Gemfileには

gem 'bootstrap-sass'
gem 'font-awesome-rails'

と記述します。

application.jsは

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap
//= require sb-admin/metisMenu.min
//= require sb-admin/raphael-2.1.0.min
//= require sb-admin/morris
//= require sb-admin/morris-data
//= require sb-admin/sb-admin

appication.scssは

@import "bootstrap";
@import "metisMenu.min";
@import "timeline";
@import "sb-admin-2";
@import "morris-0.4.3.min";
@import "font-awesome";


.form-signin {
  max-width: 330px;
  padding: 15px;
  margin: 0 auto;
}

を追加すると動きます。

できるだけgemで入れたかったので、こんな感じにしました。

RailsにSB-Admin2を入れてくれてるのソースもありました。
larcara/sb-admin-base · GitHub

参考 SB Admin 2 - Free Bootstrap Admin Theme - Start Bootstrap bokmann/font-awesome-rails