ホーム ブログ ページ 39

自作スケジュールシートで時間管理タスク管理

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

自分の仕事や予定を管理する上で、以下のようなニーズを満たすツールを探してきました。

  • 数日〜数週間の単位で取り組むタスクの予定と実績を管理したい
  • 数週間先までの予定を見通し良く管理したい
  • 1日の中の時間の使い方を見える化したい

なかなかぴったりとするものが見つからなかったので、ガントチャートとバーチカルダイアリーを合体させたような感じのA4スケジュールシートを自作しました。
マイナーチェンジをしながら、すでに3年以上使い続けています。

使い方としては、上半分に自分のタスクやプロジェクトの日程などを書き、下半分に日々のアポイントや時間の使い方などを書いていきます。

フォーマットはこちらに公開しますので、自由に使ってください。

ビット演算でフラグを管理する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

業務上、フラグを用いて制御が必要な場面があると思いますが
1つのテーブルに複数フラグ管理が必要でDBに○○フラグ、▢▢フラグ、△△フラグと
複数のフラグのカラムが追加が必要なケースがあると思いますが、
今回は上記の様な複数フラグのカラムを一つのビット演算で管理するケースになります。

ビット演算とは


ビット演算とは2進数で表された数値(ビットパターン)を操作する演算のことです。 主にAND、OR、NOTという演算から成り立ちます。

& (AND)


AND演算は2つのビットパターンを取り、1つのビットパターンを返す演算子です。 各ビットにおいて双方が1の場合は1を、それ以外の場合は0を返します。

1 & 1 = 1
0 & 1 = 0
1 & 1 = 1
0 & 0 = 0

| (OR)


OR演算も2つのビットパターンを取り、1つのビットパターンを返す演算子です。 各ビットにおいてどちらかが1の場合は1を、どちらも0の場合は0を返します。

1 | 1 = 1
0 | 1 = 1
1 | 0 = 1
0 | 0 = 0

~ (NOT)


NOT演算は1つのビットパターンを取り、1つのビットパターンを返す演算子です。 各ビットにおいて1の場合は0を、0の場合は1を返します。

~1 = 0
~0 = 1

ビット演算を使ったフラグ管理


数値をビットパターンで表すと、各桁が 0 か 1 で表されます。 したがって 0 を OFF、1 を ON と定義すると大量の状態(フラグ)を一つの数字として 管理することができます。

例えば記事を管理する画面があり1つの記事に対して画像を4つ設定出来る場合

article_image1 = false
article_image2 = false
article_image3 = false
article_image4 = false

この例では設定可能画像が4つだけなので何とかなりますが、数が増えると面倒です。
そんな時はビットパターンを使って状態を管理することを考えます。 以下のようなイメージです。

            image1  image2   image3  image4
article =   0       0        0       0

フラグを立てる

# 状態を初期化
article = 0000
# 画像1を設定
article = article | 1000
# 画像3を設定(画像2は未設定)
article = article | 0010

フラグを下げる

# 状態を初期化(画像1,3設定)
article = 1010
# 画像1を削除
article = article & (~1000)
# 画像3を削除
article = article & (~0010)

フラグを判定する

# 状態を初期化(画像1,3設定)
article = 1010

if ((article & 1000) > 0) 
  puts '画像1はtrueです'
else
  puts '画像1はfalseです'
end

if ((article & 0100) > 0) 
  puts '画像2はtrueです'
else
  puts '画像2はfalseです'
end

if ((article & 0010) > 0) 
  puts '画像3はtrueです'
else
  puts '画像3はfalseです'
end

if ((article & 0001) > 0) 
  puts '画像4はtrueです'
else
  puts '画像4はfalseです'
end

出力結果

画像1はtrueです
画像2はfalseです
画像3はtrueです
画像4はfalseです

仕組み

2進数のどの桁が1になっているかを見て、flagがtrueかfalseかを判定します。
元となるフラグの2進数と、現在のステータスの2進数を「&」演算子でビット演算を行うことで、両方が1の時だけtrueになります。

まとめ

このようにビット演算を使うことで簡単に大量のフラグを管理することができます。
フラグを増やしたい時は、定数を増やすだけで判定できるので、管理が簡単になります。

枠全体をクリック可能な縦幅可変のリンクを並べる

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

枠全体をクリック可能な縦幅可変のリンクを並べる対応を、アンカーのposition設定、inline-boxで実施する。

「記事のタイトル・画像・内容の一部を●●文字まで表示するリンクを作成して欲しい、もちろん枠全体をクリック可能で!」
上記のような要望がユーザーからされることが良くあります。調べてみると、個々の問題については対応方法があったりしますが、毎回調べるのも…ということで、全部対応したサンプルを作成してみました。

目次

今回の対応について、2つに分けて解説します。

  • アンカーをdivタグ全体に広げる
  • 縦幅可変の枠を並べる

アンカーをdivタグ全体に広げる

下記対応で実施可能です。
css

      div.box {
    position: relative;
  }
  div.box a {
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 100%;
  }

html

      <div class="box">
    <a href="hospital-base.html"></a>
    <img src="./sample.jpg" alt="">
    <div class="text">
      <p>テキスト</p>
    </div>
  </div>

「position: absolute」は絶対位置指定。親以外の要素から縁を切り、絶対的な位置に配置します。上記例では親要素の左上端から縦横100%分を範囲として表示しています。
また、親にしたいボックスに「position:static」以外のposition指定(上記例ではrelative)をします。指定をしない場合、親が「ブラウザウィンドウ」になるため、注意です。
 

縦幅可変の枠を並べる

要素の左上からの並び替えはfloat:leftを使用することが多いですが、縦幅が異なる要素を並べた場合に崩れが発生する可能性があります。
そのため、今回はdisplay: inline-blockで実施します。
css

      div.box-inner {
    width: 610px;
    letter-spacing: -.40em;
    background: #EEEEEE;
    padding: 3px 0px 0px 0px;
    border: 1px solid #333333;
  }
  div.box {
    display: -moz-inline-box;/* firefox */
    display: inline-block;
    /display: inline;/* ie */
    /zoom: 1;/* ie */
    vertical-align: top;
    letter-spacing: normal;
    width: 276px;
    background: #f2f9fe;
    border: 1px solid #35559d;
    overflow: hidden;
    font-size: 12px;
    padding: 10px;
    margin: 2px;
    position: relative;
  }

html

    <div class="box-inner">
  <div class="box">
    <div class="text">
      <h4>テキスト</h4>
      <p>ああああああああああああああああああああ</p>
    </div>
  </div>
  ...
</div>

対象の要素にdisplay: inline-blockを追加するだけです。
あとは行ごとに上寄せをするvertical-align: top;、inline-blockを使用した際に発生するスペースを除去するletter-spacing: -.40em; / letter-spacing: normal;を追加して表示を整えます。
 
以上が「枠全体をクリック可能な縦幅可変のリンクを並べる」対応になります。
 

サンプル:

css

      div.box-inner {
    width: 610px;
    background: #EEEEEE;
    padding: 3px 0px 0px 0px;
    border: 1px solid #333333;
    letter-spacing: -.40em;
  }

  div.box {
    display: -moz-inline-box;
    display: inline-block;
    /display: inline;
    /zoom: 1;
    vertical-align: top;
    letter-spacing: normal;
    width: 276px;
    background: #f2f9fe;
    border: 1px solid #35559d;
    overflow: hidden;
    font-size: 12px;
    padding: 10px;
    margin: 2px;
    position: relative;
  }

  div.box a {
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 100%;
    text-indent:-999px;
  }

  .box a:hover{
    background-color:#FFF;
    filter:alpha(opacity=50);
    -moz-opacity: 0.5;
    opacity: 0.5;
  }

  .box img {
    float: left;
  }

  .box div.text {
    float: right;
    width: 160px;
  }

html

<div class="box-inner">
  <div class="box">
    <a href="hospital-base.html"></a>
    <img src="./sample.jpg" alt="">
    <div class="text">
      <h4>テキスト</h4>
      <p>ああああああああああああああああああああああああああああああああああああああああああああああああああああああ</p>
    </div>
  </div>
  <div class="box">
    <a href="hospital-base.html"></a>
    <img src="./sample.jpg" alt="">
    <div class="text">
      <h4>テキスト</h4>
      <p>あああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああ</p>
    </div>
  </div>
  <div class="box">
    <a href="hospital-base.html"></a>
    <img src="./sample.jpg" alt="">
    <div class="text">
      <h4>テキスト</h4>
      <p>あああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああ</p>
    </div>
  </div>
  <div class="box">
    <a href="hospital-base.html"></a>
    <img src="./sample.jpg" alt="">
    <div class="text">
      <h4>テキスト</h4>
      <p>ああああああああああああああああああああああああああああああああああああああああああああああああああああ</p>
    </div>
  </div>
</div>

 
表示例:
enter image description here

瞬間寝落ち-マイクロスリープの危険性と活用法

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

一瞬寝る睡眠方法、マイクロスリープ。その危険性と付き合い方、可能性についてまとめました。

日中、仕事をしているのにウトウト…気がついたら寝落ちしていた…。そんな体験をした人は多いかと思います。重大な病気が隠されている可能性もありますが、多くは睡眠不足を指摘されるでしょう。
ただ、仕事に追われる現代人としては、なかなか改善するのが難しいもの。そこで、今回取り上げるのが「マイクロスリープ」です。
 

1. マイクロスリープとは

急に睡眠状態に移行してしまうことで、1秒未満から30秒弱の睡眠に陥ります。
睡眠状態の間は動作を停止してしまうので、前触れもなく起こるこの症状は大きな危険性を孕んでいます。
 

2. 睡眠との違いは

睡眠は一般的に下記の過程を経て、睡眠状態へ移行します。
 1. 眠気を感じる
 2. 睡眠のための動作をする(横になる、目を瞑る、等)
 3. 睡眠状態に入る
マイクロスリープでは1と2、特に2の動作をすることなく3に移行することを指します。
そのため、「急に動作を停止した」ようになるのです。
 

3. マイクロスリープの危険性

マイクロスリープは、車の運転中やパソコンを用いた単純な作業を行っている際に起こりやすいといわれています。一瞬とはいえ外界からの情報を遮断し、動作を取れない状況に陥るわけですから、車の運転等危険な動作をする場合は注意が必要です。
 

4. マイクロスリープとの付き合い方

上記のような生活に与える影響、そして睡眠不足や精神疾患が原因といわれるマイナスイメージのため、悪いものと捉える人も少なくありません。ただ、そもそもマイクロスリープは、「脳の疲労が限界まで達した場合に、短時間だけ脳全体を休ませる防衛機能」であるため、体が発信する危険信号であるとも言えるのです。
また、一瞬のうちに脳を休めることが出来る、優れた睡眠法でもあるとも言われ、うまく利用することで短時間での疲労回復をすることが可能なのです。
 

5. マイクロスリープの実施方法とは?

マイクロスリープを実践する上で、下記注意点に気をつけることで効率の良い睡眠が取れると言われています。

  1. 眠るのに適した場所を確保する  意識を失っても安全な場所を選びましょう。
  2. ネクタイやベルトなど、体を締め付けるものをゆるめる  締め付けは不快な睡眠の原因となります。
  3. 体に力の入らない楽な姿勢をとる  2同様快適な睡眠のためには必要です。
  4. アイマスクや耳栓など、外部からの刺激を遮断する  睡眠の妨げを排除することはもちろん、顔の一部を隠すことで安心した眠りにつくことができます。
  5. 起きる時間を強く意識する  寝る前に意識していたことは、潜在意識として残りやすいといわれています。
  6. 眠くなる前に実施する  眠くなった後だと、そのまま眠ってしまう危険性が高いです。  

マイクロスリープを実践しようとしてそのまま熟睡してしまった…!電車を乗り過ごしてしまった…!という人もいるかと思います。
短時間での覚醒がどうしても難しい場合、仕事を調整して睡眠時間を増やすなどの生活改善からはじめる必要があります。マイクロスリープはあくまで補助機能である、という意識を忘れないでください。
また、昼休み等休憩時間を使って15分~20分程度睡眠をとるのも大きな効果があるといわれています。
 

まとめ

以上のように、使い方に注意が必要ですが、うまくコントロールすれば有効活用できそうな睡眠方法であるといえます。昼寝が疲労回復を促し、生産性を向上したという話もあるように、この効率的な睡眠が仕事のクオリティを変えていく可能性は大いにあると思います。
「居眠りは悪いもの」 そんな意識を変え、睡眠という生理現象とうまく付き合っていくのが疲労を抱えた社会の中で求められているのではないでしょうか。

BOXでBoxEditから、メモ帳以外のエディタで開いて編集するには(Windows)

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

BOXとは

「Box」は、米国Fortune500社の99%が利用する、ビジネスユース実績No.1のコンテンツシェア(ファイル共有)とコラボレーションのためのクラウドサービスです。場所やデバイスを問わず、様々なコンテンツへのセキュアなアクセスと情報の共有・活用を可能にします。また、ユーザとIT管理者の双方に支持される、使いやすくて安全性の高いファイル共有クラウドクラウドサービスでもあり、社内外の人々とこれまでにない新しい形でのビジネスコラボレーションによって、業務生産性の飛躍的な向上やストレージコストの削減により、企業の競争力強化を支援します。2014年5月時点で世界22万社以上の企業が「Box」を採用しています。

enter image description here

通常

Windows 上に、テキストエディタをインストールして、「.txt」をインストールしたエディタに関連付けしていても、Box上で開こうとすると、「メモ帳で開く」と表示されてしまいます。
enter image description here

これを解決するには、レジストリを修正することで対応することが可能です。

変更内容

[HKEY_CLASSES_ROOT\SystemFileAssociations\text\shell]
>”Edit”
>”Command” にて
(規定)のデータを「C:\Program Files (x86)\editer\editer.exe %1」に変更してください。

   ※「editer\editer.exe」部分は、使用したいエディタのパスに変更して下さい。

enter image description here

上記は、サクラエディタに変更した場合の表示例です。

注意点

レジストリキーの変更には危険が伴う場合がございます。
レジストリキーの変更を行う前にレジストリのバックアップを取得することを強く推奨いたします。

Deviseを使用したパスワードのみによる認証

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Railsに認証機能を実装するgem「Devise」を使用して、パスワードのみで認証させる方法。

今回やりたかったのは、Rails で用いる認証機能 gem のDeviseを用いてパスワードのみで認証させるといったケースです。

Deviseの導入に関しましてはネットに様々記載がありますので今回は割愛させてもらいます。

認証ユーザー用のModelを作成

  • 認証ユーザー用のModel名は任意
  • 今回は、Userとする
    app/models/user.rb
    • confirmableを追加

ソース記述例

class User < ActiveRecord::Basedevice
  :database_authenticatable,  :rememberable,  :authentication_keys[];
  ### 以下省略 ###  
end

Deviceの認証が通常メールアドレスとパスワード認証がデフォルトですので
authentication_keys[]の記述がメールアドレスを使わないという意味になるようです。

上記の記載によりDeviceの認証時にパスワードのみで認証が可能となります。

余談ですがDeviseでメールアドレス以外のカラムをログイン認証に利用する場合は
例えばユーザー名(usernameカラム)で認証を行いたい場合は以下を追加すると良いようです。
authentication_keys => [ :username]

プログラミングで挫折した人に!日本語で書けるプログラミング言語3選

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

プログラミングを始めたい、でも参考書を読んでも全く意味がわからない。そんな人向けに、初心者でもわかりやすい日本語で記述できるプログラミング言語をご紹介します。

春からSE始めました。しかし参考書を開いても、意味の解らない言葉ばかり……
そんな私に救世主が。

日本語で記述できるプログラミング言語があるんです。

これならカタカナ・英語アレルギーの人でもなんとかなりそうですね。早速3つ、ご紹介します。

■なでしこ

なでしこ
起動時に現れるなでしこのデモページ

起動するとまず、「なでしこのはじめに」という画面が現れ、なでしこの解説やどんなものが作れるのかの例などが実際に見られます。なでしこを使って作られたゲームで遊ぶこともでき、イメージをつかみやすいですね。

nade

プログラムを記述するエディタのデザインも、なでしこ色(?)で統一されていて可愛らしいです。さっそくなでしこのマニュアルに従ってプログラムを書いてみます。
クジラが「こんにちは」と言う。
こう書いて実行ボタンを押すだけで、クジラの絵が出てきて「こんにちは」と言ってくれました。楽しい!

■プロデル

プロデル
プロデルのデザイナ
デザイナ(プログラムを書いたり設定したりする画面)が見やすい!
ファイルサイズが小さいので、実行が早いのも魅力の一つです。

■ 言霊

言霊

文系の学生がプログラミングに対して拒絶感を持たないよう開発されたとのこと。Javaの仮想環境で動くので、Macユーザーも使えるのが嬉しいですね。

■まとめ

3つの言語に触ってみて、私の個人的な感触としてはなでしこが一番初心者に優しく使いやすいと感じました。(記事の文章量にもそれが如実に表れていますね。)
プログラミングに慣れてきたら、プロデルや言霊の方が使いやすいと感じるのかもしれません。それぞれの嗜好や開発環境の違いによって、自分にあった日本語プログラミング言語を選んでみてください!

carrierwaveとfogでRiak CSへの画像アップロードを実装する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Amazon S3互換のストレージサーバーRiak CSに、Railsの画面からファイルをアップロードする機能を実装します。

Riak CSについて

Riak CSは、 Basho Technologies, Inc. がオープンソースで開発しているAmason S3互換のストレージサーバーです。Railsアプリケーションでは、carrierwavefog-awsという二つのGemを使うと、ファイルのアップロード処理を簡単に実装することができます。

APIが互換なので、Railsから見るとAmazon S3とほとんど同じです。

確認画面について

日本の業務系アプリでは、編集画面から保存するとき「確認画面」をはさむように要求されることが多いです。これはRailsのレールから外れてしまうため、特に画像系のファイルアップロードがからむと非常に面倒です。

しかし、carrierwaveでは《キャッシュ》というアップロードされたファイルを一時的なディレクトリに保存する機能があるので、確認画面のプレビューに画像を表示させることができます。

複数サーバー環境

複数のアプリケーションサーバーで負荷分散している場合、アップロードするファイルを共通のストレージに保存する必要があります。

carrierwaveの標準の機能では、アップロードされたファイルをサーバーのディスクに直接保存するため、そのままでは使えません。

fogという各種クラウドサービスに対応するGemを使えば、carrierwaveと連携してアップロードされたファイルをクラウドに保存することができます。

fog-awsはAmazon S3やプロトコル互換のネットワークストレージに対応するGemです。

今回はこのfog-awsを使用して、Riak CSにファイルをアップロードします。

環境

Riak CSの環境として、IDCFクラウドのオブジェクトストレージというサービスを利用させていただきました。

Railsで作成したサンプルアプリケーションは、下記のような構成になっています。

  • Ruby 2.3.1
  • Rails 5.0.0
  • carrierwave HEAD版
  • fog-aws 0.10.0

2016年7月の執筆時点のcarrierwaveでは、《キャッシュ》の一時保存先にfogのストレージを指定する機能がまだ正式リリースされていないため、GitHubのHEAD版を使用します。

実装

完成したソースコードを https://github.com/kkismd/cloud-sample に公開しています。
以下、ポイントとなる箇所を抜粋しながら説明します。

アプリケーションの概要

Userというモデルが、名前(name), メールアドレス(email) という属性のほかに、avatarという名前で画像ファイルを持ち、画面からアップロードすることができる、という機能を実装しました。
carrierwaveを使う場合、カラムとしてファイル名を表す文字列のカラムを用意します。

create_table :users do |t|
  t.string :name
  t.string :email
  t.string :avatar

  t.timestamps
end

Gemfile

前述のライブラリをGemfileに記述します。以下は抜粋です。

ruby '~> 2.3.1'
gem 'rails', '~> 5.0.0'
gem 'carrierwave',
  github: 'carrierwaveuploader/carrierwave',
  ref: 'b31f7ce006bade550be0ad946d0b993b799358e3'
gem 'fog-aws'

イニシャライザ

config/initializers/carrierwave.rbというファイルを作成してcarrierwaveとfog-awsの設定を記述します。

CarrierWave.configure do |config|
  config.fog_provider = 'fog/aws'
  config.fog_credentials = {
    provider: 'AWS',
    aws_signature_version: 2,  # ☆1
    aws_access_key_id: ENV['fog_api_key'],
    aws_secret_access_key: ENV['fog_api_secret'],
    region: ENV['fog_region'],
    host: ENV['fog_host'],
  }
  config.cache_storage = :fog # ☆2
  config.cache_dir = 'tmp/image-cache'
  config.fog_directory = ENV['fog_directory']
  config.asset_host = ENV['fog_asset_host']
end

個別に設定しなければならない値は、環境変数(ENV)から読み取るようにしています。
今回は環境変数の割り当てにfigaro というGemを使っています。

注意しなければならないポイントとして、Riak CSではファイルアップロード時に送信する電子署名のバージョンがAmazonのものより古いため、コメント ☆1 の設定を入れなければファイルをアップロードしようとしても失敗します。この事象はエラーメッセージが分かりにくくて特定に時間がかかってしまいました。

また前述の通り、《キャッシュ》の保存先をRiak CSに設定する ☆2 は、執筆時点でのcarrierwaveリリース版ではまだサポートされていません。

アップローダー

carrierwaveではまず app/uploadersディレクトリに「アップローダー」と呼ばれるクラスを定義します。ジェネレータが用意されているのでそれを利用します。

% rails generate uploader Avatar

生成したあと、保存先をfogに設定します。

class AvatarUploader < CarrierWave::Uploader::Base
  storage :fog

モデル

つぎに、UserモデルにAvatarUploaderを《マウント》します。

class User < ApplicationRecord
  mount_uploader :avatar, AvatarUploader

コントローラ

scaffoldでusersテーブルのCRUDを実装したあと、新規作成と保存について確認画面を追加します。
ここでは名前を create_confirmupdate_confirm としました。
コントローラにメソッドを記述し、routesファイルに定義を追加しました。

  resources :users do
    collection do
      post :confirm_create
    end
    member do
      patch :confirm_update
    end
  end

ビュー

確認画面でアップロードした画像をプレビューすることができますが、保存画面にデータを持ち回るために hidden フィールドにデータを保持します。

   <div class="field">
    <%= image_tag @user.avatar_url if @user.avatar? %>
    <%= f.hidden_field :avatar_cache %>
   </div>

ここでイメージタグで表示される画像は、Riak CSのキャッシュ用に設定したディレクトリに保存されています。このファイルはモデルがDBに保存するタイミングで実際の保存用ディレクトリにアップロードし直され、自動的に削除されます。

まとめ

carrierwavefog-awsを使うことにより、Amazon S3だけでなく互換性のあるストレージシステムに対しても簡単にファイルをアップロードする機能を実装することができます。

ただし、使用されているソフトウェアによって若干の差異があるため、実際に動かして確認する必要があります。

キーボードだけで生きて行く

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

なぜキーボードに操作を集約させるのか

 今回は作業を出来る限りキーボードだけで完結させるためのtipsについて紹介していく。まず、その前に自分が何故キーボードで操作したがるのかを説明しておきたい。

手元/視線の移動が少ない
 マウスを使う場合、どうしても手が大きく移動する。おまけにデュアルモニターで画面が広いとカーソルがしばしば迷子になる。マウスを使う度に画面上からカーソルを探すゲームを強要されるのは面倒だ。マウス探しやカーソル探しで視線が大きく移動すると注意が途切れ、時間も微妙にかかる。

マウス操作自体が面倒
 そもそもマウスでカーソルを移動させて特定地点まで運びクリックするという作業自体が面倒で遅い。マウスによるUIは誰でも直感的に扱えるが最速ではない。最速といえばキーボード。少なくとも人体に直接接続できる入力デバイスが開発されるまでは。

全体的な話

 次に汎用的な話について少し。キーボードに操作を集約させる上で自分が気にする点がいくつかある。

1.ホームポジションから離れない
 方向キーはこの理由でキーバインドにあまり使わない。確かに直感的だが、方向キーを使おうとするとホームポジションから右手が大きく移動するので割り当てたくない。

2.同じような操作は同じキーバインドで
 例えばタブを前後に移動するような操作は同じキーバインドを割り当てる。アプリによって操作が変わるのは誤操作しやすいし、そもそも覚えていられない。

3.アプリケーションごとのキーバインド設定(mac)
 アプリケーション自体でショートカットキーの設定をサポートしていない場合がある。そういった場合には「システム環境設定」>「キーボード」>「ショートカット」>「アプリケーション」で追加出来る。例えば自分はChrome、Skypeなど使用頻度の高いアプリに対してタブ移動をControl+W/Qで登録している。

Webブラウザを操作する

 特に頻繁に使うのにキーボードで操作しにくいのがWebブラウザ。ここではブラウザ操作をキーボードで操作するプラグインとして「vimium」を紹介する。名前の通り、みんなが大好きなvimのキーバインドで操作ができる。対応ブラウザはchrome/firefox。
http://vimium.github.io/

 これによってWebブラウザを利用する上で必要な操作の9割ぐらいはキーボードで行うことが出来る。数十の機能があるが主だったものを数点だけ挙げれば以下の通り。

  • 画面のスクロール
  • タブを移動・作成・閉じる
  • リンクを開く
  • ページ内検索
  • ブックマーク検索

これを使う上で覚えるべきキーバインドはそれほど多くないため、百歩譲って何らかの理由で不幸なことにvimに馴染みがない人もvimiumは十分に使える。

 特に便利なのが「リンクを開く」「ブックマーク検索」といったブラウザが元々サポートしていない機能。この辺の機能を押さえておくだけでもブラウザ操作のほとんどをキーボードで行うことが出来るはず。

まとめ

 日常的に業務で使うものと言えば、コンソールとSkypeとWebブラウザ、メールクライアントの四点ぐらい。今回の記事でその四点はキーボードで操作がほぼ完結するようになるはず。他に使う必要があるExcelなどもショートカットキーを多用することでマウスの必要性をかなり小さく出来る。もはやマウスは机の上で置物となるだろう。

 ところで職場用のマウスにKensingtonのExpert Mouseを買いました。ボールをコロコロして操作するの楽しいのでお勧めです。みんな買おう。╭( ・ㅂ・)و

vimでMarkdownに数式を組込んでプレビューさせる

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Markdownの編集中にリアルタイムにプレビューしてくれると非常に便利である。

vimでMarkdownを編集する場合には、previmを利用すると、browser上でほぼリアルタイムにプレビューしてくれる(marked.jsを利用しているらしい)。

さて、本記事では、Markdownで書いている文章に、数式を綺麗に表示させる方法について記載する。

数式を綺麗に表示させるために「MathJax」を利用する。

previmでMathJaxに対応したMarkdownを利用するためには、previmのpluginの下記を変更すればよい。

変更点1

「preview/index.html」に以下を挿入する。

    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        CommonHTML: { matchFontHeight: false }
      });
    </script>
    <script async src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML">
    </script>

変更点2

「preview/js/previm.js」に1行挿入する。

    if (needReload && (typeof getContent === 'function') && (typeof getFileType === 'function')) {
      var beforePageYOffset = _win.pageYOffset;
      _doc.getElementById('preview').innerHTML = transform(getFileType(), getContent());

      mermaid.init();
      Array.prototype.forEach.call(_doc.querySelectorAll('pre code'), hljs.highlightBlock);
      autoScroll('body', beforePageYOffset);
      style_header();

      // ↓の1行を挿入する。
      MathJax.Hub.Typeset(document.getElementById("preview"));
    }

数式の書き方

MathJaxを利用しているのでMathJaxの記法(TeXの記法に準拠しているらしい)で記述できる。

以下に記述の例を示す。

複数行数式の例

\\[
  E = mc^2
\\]

本記事の冒頭の画像は、この例の記述で表示される数式(のキャプチャ)である。

インライン数式の例

計算式「\\( \alpha \times \beta \\)」で表される。

テキストベースの資料作成で使えるツールについて

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

序論

今更書き出すほどのものでもないが、テキストベースで文書を作成すると以下の利点がある。

  • 差分管理ツールが充実している(git, mercurial, …)
  • マウスの使用を最小限に抑えることができる

そこで、設計書をテキストベースで管理できないかを検討し、以下の構成で試したので簡単にまとめる。

  • 文章:Markdown
  • 図:PlantUML
  • ファイル管理:GitLab

PlantUMLについて

PlantUMLは、テキストベースでUMLが記載できるjava製のツールである。
図の出力に、graphvizを利用している。

例えば、以下の図を記載できる(下記に挙げたものは、全てではない)。

  • シーケンス図
  • ユースケース図
  • クラス図
  • アクティビティ図
  • コンポーネント図
  • 状態遷移図

また、UMLだけではなく、作図のための要素も用意されている。

使用したツール

Markdown

markdownの編集ツールは、vimを利用した。
vimのpluginのprevimを利用すると、browser上でほぼリアルタイムにプレビューしてくれる。

vimに拘りがなければ、atomや、haroopadも良いと思う。

PlantUML

Atomの下記pluginを利用して、編集時に図をリアルタイムにプレビューできるようになる。

  • language-plantuml
  • plantumlntuml-viewer

※但し、事前にplantumlを利用できる環境を準備しておく必要があるので注意。

なお、本記事の先頭の画像は、Atom上でPlantUMLをプレビューしている様子を表示している。

GitLab

GitLabにブラウザでアクセスすると、リポジトリ管理下のmarkdown形式のファイルを整形した状態で表示してくれる。
このため、ブラウザで整形された文書を確認することができる。

また、以下のような書式で同一ファイル内へのリンクだけではなく、
別ファイルへのリンクもできるためページ遷移も容易にできる。

  [ページ内リンク](#link)
  [別ファイルへのリンク](hogehoge.md)

振り返り

良かった点

  • マウス操作が、ほぼ不要になった。Atomを利用しないならターミナル上だけで操作を完結できる。
  • Officeソフトのような重たくて編集しづらいソフトから解放されVimだけで資料作成が完結できたことによりストレスから解放された。
  • 修正点をGitLab上で「明確」に確認できる。
  • 修正の反映もgitでpushすればよいだけなので非常に楽だった。
  • 指摘された点を修正した後、GitLabにpushしたことを通知すれば、メンバーはブラウザをリロードするか又は対象のURLにアクセスするだけで最新の仕様書を読むことができる。

悪かった点

  • GitLab上での「表」の表現力が低いため、大きな表を作成すると見辛い。
    • セル内の文字の配置がセンタリングしかできない(左寄せ、右寄せの指定ができない)。
    • 表のセル内で明示的な改行ができない。
    • 表の横幅を指定できない。
    • 表の外枠の横幅が決まっているため、横に長い表を作成すると、デザインがものすごく微妙になる。

悪かった点は、上述したように、文章の表現力の低さ、特に「表」に関する表現力の低さが目立つ。
これが改善されれば、ほぼ言うことはない。

まとめ

特に、修正した内容を確認してもらうときの速度が、かなり早くなったのが印象的だった。

Officeソフトで設計書を作成していると、修正された設計書を確認する人は、設計書が置かれたファイルサーバからローカルに持って来た後にファイルを開かなければならない。
Officeソフトは総じて動作が遅いため一々時間がかかる。

この作業は非常に面倒くさい。

しかし、今回の方式では、GitLab上でプレビューできるため、修正箇所のページのURLを渡せば、修正箇所を即座に確認することができる。既に該当個所のページを参照している場合には、ブラウザをリロードしてもらうだけでよい。

簡単な修正であれば、設計書に対する指摘があったときから修正後の設計書の確認完了まで1分以内に抑えることも可能だ。

スピード感を持った開発を目指すなら、良いアプローチの一つになると思う。

Fog を利用した IDCF オブジェクトストレージ へのアップロード・ダウンロード

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Railsで画像アップロード等を行うにはCarrierWaveを使用するのが便利であるが、これは特定のモデルに紐づくファイルをアップロードする事が基本的な使用方法である。 それに対して、ただ単純に(特定のモデルに紐付かない)ファイルをIDCFオブジェクトストレージへアップロードしたりIDCFオブジェクトストレージからダウンロードしたりするという用途においては、 Gem「fog」を利用すれば簡単に実装できるようになる。

Gemfile

gem 'fog'

アップロード方法

file_uploader = Fog::Storage.new(
  provider:               'AWS', # IDCFでもAWSと記述
  path_style:             true,
  host:                   'ds.jp-east.idcfcloud.com',
  port:                   443,
  scheme:                 'https',
  aws_access_key_id:      'XXX', # アクセスキー
  aws_secret_access_key:  ENV['SECRET_IDCF_SECRET_KEY'],
  region:                 'ap-northeast-1', # 東京
  aws_signature_version:  2
)

file_uploader.put_object(
  'XXX', # バケット名
  '/tmp/xxx/xxx.xxx', # ファイルのフルパス
 'XXX' # ファイル内容(パラメータで受け取る場合は、そのままparams[:xxx]等)
)

ダウンロード方法

file_uploader = ... # アップロード方法と同内容なので省略

File.open(file_full_path, 'w') do |f|
  f.write file_uploader.get_object(
    'XXX', # バケット名
    '/tmp/xxx/xxx.xxx' # ファイルのフルパス
  ).data[:body]
end

3分リファクタリング Rails.root編

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

log/ や public/など RAILS_ROOT 以下のファイルへの扱うとき、File や FileUtil などのクラスを使わずシンプルに記述できます。

BEFORE

Logger.new(File.join(Rails.root, "log", "production.log"))

AFTER

Logger.new(Rails.root.join("log", "production.log"))

POINT

Rails.rootが返すオブジェクトはPathnameなので、FileFileUtilでできることのほとんどをメソッドとして持っています。
File.joinなどを改めて呼ぶ必要はありません。

REFERENCE

http://ruby-doc.org/stdlib-2.4.3/libdoc/pathname/rdoc/Pathname.html

VERSIONS

Ruby MRI 2.3.1
Rails gem 'rails', '5.0.0'

CarrierWave を使用した IDCF オブジェクトストレージ保存

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Railsに画像等のファイルをアップロードする機能を実装するgem「CarrierWave」を使用して、ファイルをIDCFのオブジェクトストレージへ保存する方法。

アップローダの編集

「rails g uploader XXX」 にて生成されるアップローダ(app/uploaders/XXX_uploader.rb)を、以下の様に編集する。

class XXXUploader < CarrierWave::Uploader::Base
  storage :fog # オブジェクトストレージに保存する場合は :fog を指定
  ### 以下省略 ###
end

初期化設定

下記の様な設定ファイルを作成し、config/initializers/carrierwave.rb 等として保存。

CarrierWave.configure do |config|
  config.fog_credentials = {
    provider:              'AWS', # IDCFでもAWSと記述
    path_style:            true,
    host:                  'ds.jp-east.idcfcloud.com',
    port:                  443,
    scheme:                'https',
    aws_access_key_id:     'XXX', # アクセスキーを記述
    aws_secret_access_key: ENV['SECRET_IDCF_SECRET_KEY'], # シークレットキー
    region:                'ap-northeast-1', # 東京
    aws_signature_version: 2
  }
  config.cache_storage = :fog # 一時ファイルもオブジェクトストレージに保存する場合(LB使用時は必須)
  config.fog_directory = 'XXX' # バケット名を記述

  config.asset_host = 'ds.jp-east.idcfcloud.com' # CDNを使用しない場合
  config.asset_host = 'https://XXX.cdn.jp.idcfcloud.com/' # CDNを使用する場合
end

Rails.cacheでキャッシュ処理してみた

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

よく閲覧されるページで何度もDBを読み込むのは、負荷がかかったりしていいとは言えません。 なのでキャッシュ処理を使用して、DBアクセスを減らしサクサク動けるようにしたいです。 そこでRailsでは容易にキャッシュ処理ができるのでやってみました。

class BlogController < BaseController
  before_action :load_paper, :load_picture, only: [:show]
  # キャッシュの保有期間を設定
  CACHE_EXPIRE_TIME = 1.day.freeze

  def show
    ・・・・・
  end

  private

  def load_paper
    # Rails.cache.readで読み込む
    @papers = Rails.cache.read(cache_key(:paper))
    # なかったらRails.cache.writeで書き込む
    unless @papers
      @papers = Paper.all
      Rails.cache.write(cache_key(:paper), @papers, expires_in: CACHE_EXPIRE_TIME)
    end
  end

  def load_picture
    @pictures = Rails.cache.read(cache_key(:picture))
    unless @pictures
      @pictures = Picture.all
      Rails.cache.write(cache_key(:picture))
    end
  end

  # keyが被らないようにする
  def cache_key(type = nil)
    [
      self.class.name.underscore,
      type
    ].join('')
  end
end

メソッド化などをしなければキャッシュ処理は3~4行追加するだけでできるので非常に便利です。

またRails.cache.fetchを使用するとさらに短くなります。
fetchはキャッシュがあったらそのまま返し、なかったらキャッシュを生成して返すという処理が行われます。

  def load_paper
    @papers = Rails.cache.fetch(cache_key(:paper), expires_in: CACHE_EXPIRE_TIME) do
      Paper.all
    end
  end

翻訳されてないですが、RailsGuidesで詳しく載っているのでこちらを見るのもいいかもしれないです。

[rails] Jpmobileを使用する際の注意点 Edit

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

スマフォでPC表示させているときの条件に注意。

Jpmobileの概要

RailsでPCサイトと共にスマフォサイトを作成する場合に便利なGemとして、JpmobileというGemがあります。

このGemを使うことで、アクセス端末に応じてviewを切り替えることができます。

すなわち、Jpmobileを使用することで、PCからアクセスされた場合にはPC用のviewを表示させ、スマフォからアクセスされた場合にはスマフォ用のviewを表示させることを、Webサイトの開発者が意識することなく実装できます。

また、スマフォからのアクセスかどうかを「request.smart_phone?」のように判定することができるようになります。

ここで、スマフォでアクセスした場合であっても、PC用のviewを表示したいユーザーがいることを考慮して、「PCサイトを表示する」のようなリンクを用意することがあると思います。

この場合には、「disable_mobile_view!」メソッドをコールすることで、PCサイトを表示させることができます。

※恐らく、このようなリンクがクリックされたことを、cookieやsessionに保存し、ページ遷移した後であっても、PCサイトを表示するように実装されるかと思います。

問題点

スマフォからのアクセスに対してPCサイトを表示させている状態であっても、request.smart_phone?の結果は「true」になります。

すなわち、viewが絡む部分(*1)に関して「request.smart_phone?」で条件判定をすると、意図しない動作になる可能性があります。

(*1) controllerでインスタンス変数に値を設定する場合等も含む。

例えば、

  • PCの場合 → 12個のレコードをインスタンス変数に設定
  • スマフォの場合 → 8個のレコードをインスタンス変数に設定

とすべき場合、本来であれば、

  • PCアクセス(PC用の表示) → 12個のレコードがインスタンス変数に設定される
  • SPアクセスでスマフォ用のを表示 → 8個のレコードがインスタンス変数に設定される
  • SPアクセスでPC用の表示 → 12個のレコードがインスタンス変数に設定される

となって欲しいところです。

しかしながら、controllerで、

def index
  count = request.smart_phone? ? 8 : 12
  @records = TestTable.where(...).limit(count)
end

のように、「request.smart_phone?」を使用してしまうと以下のようになってしまいます。

  • PCアクセス(PC用の表示) → 12個のレコードがインスタンス変数に設定される
  • SPアクセスでスマフォ用のを表示 → 8個のレコードがインスタンス変数に設定される
  • SPアクセスでPC用の表示 → 8個のレコードがインスタンス変数に設定される(←12個になっていない!!)

■ 対策

このため、viewに絡む部分に関しては、

  • 判定1:アクセス端末によって切り替えるのか?
  • 判定2:PC用のviewとスマフォ用のviewのどちらを表示しているかによって切り替えるのか?

を常に意識しないと思わぬバグに繋ります。

先程の例では、判定2でやらなければいけません(判定方法は、どちらのviewを表示しているかの情報が保存されたcookieやsessionを参照して判定することになると思われます)。

なお、判定1が必要になる例としては「SPアクセスでPC用の表示をしているときに、スマフォ用のviewに戻すためのリンクを表示する場合(PCでアクセスして来た人に対してスマフォ用のviewを表示することは通常ない。スマフォのときにのみ有効。但し、この例の場合には、PC用のviewを表示している場合にのみ表示させる必要有り)」が挙げられます。

enumで数値型カラムを作る際に、テストデータを作る時に注意すること

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Railsの4.1でenumが使えるようになりました。

一般的には文字列型のカラムを用意して

class User < ActiveRecord::Base
  enum status: { :awake, :sleep, :dead }
end

と書いて

user = User.new(status: :awake)
user.awake? # => true

という使い方をしますが、使うカラムを数値型にすることで

class User < ActiveRecord::Base
  enum status: { awake: 1, sleep: 2, dead: 99 }
end

とすると

user = User.new(status: 1)
user.awake? # => true

とかできるようになります。業務アプリで定数処理しているところが捗りますね。

さて、これのテストを書くときにfactorygirlでモデルを作ろうとして、

FacrotyGirl.define do
  factory :user do
    status 1
  end
end

と書いたら

 Failure/Error: user = build(:user)

 ArgumentError:
  '1' is not a valid status

とエラーが出てしまいました。困る…。
こういう場合、

FacrotyGirl.define do
  factory :user do
    status :awake
  end
end

と名前のほうをfactoryに書けばいいです。

Macで自動作成される隠しファイルを削除

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Macだと勝手に隠しファイルが自動作成される場合がある。

「._.hogehoge」みたいな感じのファイル名。

見付ける度に、適当にfindしてrmするコマンドを実行していたりするが、
たまにvimで編集中に、現在のディレクトリ以下の
上記ファイルを全て削除したくなることがあるので、
vim scriptの勉強がてらscriptを作成してみた。

function! s:DeleteFilelist(list)
    let target = a:list

    let num = len(target)
    if 0 == num
        echo "No target file"
        return
    endif

    echo "The deleted file is shown."
    let j = 0
    while j < num
        echo target[j]
        let j = j + 1
    endwhile
    let yn = input("OK? (y or n) -> ")
    echo "\n"

    if "y" == yn
        let j = 0
        while j < len(target)
            call delete(target[j])
            let j = j + 1
        endwhile
        echo "Deleted!!"
        return
    endif
    echo "Canceled."
endfunction

function! s:DeleteMacAutoMakeFiles()
    let target = []
    let globout = glob("**/._*") . "\n"
    while globout != ''
        " Process one file at a time
        let name = strpart(globout, 0, stridx(globout, "\n"))

        " Remove the extracted file name
        let globout = strpart(globout, stridx(globout, "\n") + 1)

        if name == ''
            continue
        endif

        call add(target, name)
    endwhile

    call s:DeleteFilelist(target)
endfunction

command! -nargs=0 DeleteMacAutoMakeFiles :call s:DeleteMacAutoMakeFiles()

vim scriptでやるなよ、って気もするが…。

[scala] [vim] vimでplayの開発環境を構築する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

本記事の対象者

  • Railsの開発をvimでやっている。
  • vimのpluginとして、unite-railsを使っている。
  • Play(Scala)でもRailsと同じように開発したい人向け。

ちなみに、unite-railsは、vimのuniteというプラグイン向けのプラグイン。

よって、本記事は、vimのuniteを使っている人向け。

やりたい事

Playのプロジェクト配下のファイルを開いているときには、プロジェクト配下のソースの選択をuniteインターフェースで使いたい。

対応の概要

  • 項目1:Play用のuniteインターフェースを作成する。
  • 項目2:Playのプロジェクト配下のファイルを開いているときには、ファイルタイプに「play」が含まれるようにする。
  • 項目3:ファイルタイプに「play」が含まれているときに、play用のunite-pluginのキーバインドを有効にする。

【項目1】Play用のuniteインターフェースを作成する。

unite-railsを参考にunite-playを作成する。

参考までに、私が作成したunite-playの中は以下のようになっている。

% tree unite-play
unite-play/
├── README
├── autoload
│   └── unite
│       ├── kinds
│       │   └── bundled_gem.vim
│       └── sources
│           ├── play
│           │   ├── collector
│           │   │   ├── config.vim
│           │   │   ├── controller.vim
│           │   │   ├── javascript.vim
│           │   │   ├── model.vim
│           │   │   ├── root.vim
│           │   │   ├── route.vim
│           │   │   ├── stylesheet.vim
│           │   │   ├── test.vim
│           │   │   └── view.vim
│           │   └── helper.vim
│           └── play.vim
└── doc
    └── unite-play.txt

7 directories, 14 files

普通の開発者であれば、unite-railsの各ファイルの中身を参照すれば、簡単にplay用に修正できるはず。

プロジェクトのルートディレクトリ配下のファイルを全て一覧かするものを追加している(root.vim)。root.vimの中身はこれ↓。

function! unite#sources#play#collector#root#candidates(source)
  let target = a:source.source__play_root
  return unite#sources#play#helper#gather_candidates_file(target)
endfunction

controller.vimの中身はこれ↓。

function! unite#sources#play#collector#controller#candidates(source)
  let target = a:source.source__play_root . '/app/controllers'
  return unite#sources#play#helper#gather_candidates_file(target)
endfunction

ここまで見れば、どういう感じで修正さればよいかは分かるはず。

正しく修正することで、例えば、

  :Unite play/controller

でapp/models配下のファイル一覧を表示させたりできる。

後は、上記コマンドを適当なキーにバインドすればOK。

【項目2】Playのプロジェクト配下のファイルを開いているときには、ファイルタイプに「play」が含まれるようにする。

projectlocal」というvimのpluginを導入する(開発元のブログはこちら)。

「.vimrc」に以下の設定を追加する。

  let g:projectlocal#projectfile = get(g:, 'projectlocal#projectfile', '.projectfile')

そして、Playのプロジェクトのルートディレクトリに以下のファイルを置く。

% cat .projectfile
play

この例では、「.projectfile」が置かれているディレクトリ配下のファイルを開くとファイルタイプに「play」が含まれるようになる。

【項目3】ファイルタイプに「play」が含まれているときに、play用のunite-pluginのキーバインドを有効にする。

「.vimrc」に以下のような設定を追加する。

function! UnitePlaySetting()
    nnoremap <buffer><c-w><c-r>co :<c-u>Unite play/controller<cr>
    nnoremap <buffer><c-w><c-r>tp :<c-u>Unite play/root<cr>
endfunction

aug HogeAutoCmd
    au FileType *play* call UnitePlaySetting()
aug END

【おまけ】scalaのファイルを編集しているときには、ファイルタイプに「scala」が含まれるようにする。

vim-scalaというvimプラグインを導入する。

上記設定を全ておえ、当該プラグインが有効になれば、Playプロジェクト配下のscalaのファイルを開くと、ファイルタイプが「project.scala.play」となる。

無事に、scalaとplayのファイルタイプが含まれている。

【Rails / gem nested_form】nested_formへsortableの導入【jquery-ui/sortable

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

accepts_nested_attributes_for用のフォームをサポートしてくれる「nested_form」にドラッグ&ドロップで並び順を変更できる「jquery-ui/sortable」を導入する方法を記述します。

事前準備

1.Gemfileに追記
$ vim Gemfile

gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'nested_form'

2.モデルにaccepts_nested_attributes_forを追記
例としてBlog-< Entryな関連でEntryが並び順に使用するカラム(position)を所持

$ vim app/models/blog.rb

has_many :entries
accepts_nested_attributes_for :entries, allow_destroy: true

$ vim app/models/entry.rb

belongs_to :blog

3.コントローラにpositionパラメータを取得できるように追記
$ vim app/controllers/blogs_controller.rb

def blog_params
  params.require(:blog).permit(
    ....,
    entries_attributes: [
      ...,
      :position
    ]
  )
end

viewでの記述

$ vim app/views/blogs/_form.slim

= nested_form_for(@blog, url: ...) do |f|
  ....
    table#entries.table.table-striped.table-sortable
      = f.fields_for :entries, wrapper: false
    br
    .pull-right.
      = f.link_to_add '追加', :entries, data: { target: '#entries' }, class: 'btn btn-default'

$ vim app/views/blogs/_entry_fields.slim

tr.fields.form-group
  td ...
  ...
  td
    .pull-right
      = f.link_to_remove '削除', class: 'btn btn-danger'

  = f.hidden_field :position, class: :position

js.coffeeでの記述

$ vim app/assets/javascripts/blog.js.coffee

$ ->
  ...
  # 並び替え
  $('.table-sortable').sortable
    axis: 'y',
    items: '.fields',
    update: (e, ui) ->
      # ドラッグ&ドロップしたら各entryのhidden_fieldに現在の位置を入れる
      $('.position').each ->
        $(this).val($('.position').index($(this)) + 1)

以上でフォームをsubmitした時にドラッグ&ドロップで変更したpositionパラメータが取得できる様になります。

[rails] FactoryGirlを使用する際の注意点

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

rspecで思うように動かないケースがあってハマる可能性有り。

今回の問題を抽象的に表現すると

FactoryGirlを用いてインスタンスを生成するときにおいて、以下の条件を全て満たす場合には、生成されたインスタンスに意図した値が設定されない場合があります。

  • 条件1:所定のattributeに対して値を設定する方法が「複数」存在する。
  • 条件2:当該attributeに対して、上記「複数の方法のうち少なくとも2つ以上の方法」で値を設定する。

多分、上記表現では、抽象的すぎて意味不明だと思われるため、以下に具体例を示します。

事象の具体例

ケース1

store = FactoryGirl.create(:store)
p store.store_category
=> 1

ケース2

store = FactoryGirl.create(:store, store_category: 2)
p store.store_category
=> 1

2にならない!!

参考

以下の場合には、当然、値を代入できます。

store = FactoryGirl.create(:store)
store.store_category = 2
p store.store_category
=> 2

前提

  • 前提1:Storeテーブルには、store_category(カテゴリ名)というattributeが存在する。
  • 前提2:Storeクラスには、以下のようなメソッドが定義されている。
class Store < ActiveRecord::Base
           :

  # カテゴリ名でカテゴリコードに値を代入
  def store_category_name=(category_name)
    store_category = convert(category_name)
  end

  # カテゴリ名をカテゴリコードに変換
  def convert(name)
           :
  end

           :
end
  • 前提3:FactoryGirlを用いて、以下のように定義されている。
FactoryGirl.define do
  factory :store do
    store_category_name 'Japanese Restaurant'
  end
end

※「Japanese Restaurant」は、カテゴリコードに変換すると「1」

「今回の問題を抽象的に表現すると」との対応関係

上記条件1でいうところの、

「所定のattribute」は「Storeテーブルのstore_category」であり、

「所定のattributeに対して値を設定する方法」として、

  • 方法1:store.store_category = 1
  • 方法2:store.store_category_name=’Japanese Restaurant’

の2つがある。

どうすれば代入できるか

ケース3

store = FactoryGirl.create(:store, store_category_name: 'French Restaurant')
p store.store_category
=> 2

※「French Restaurant」は、カテゴリコードに変換すると「2」

原因

FactoryGirlのGemの中身を確認した訳ではありませんので、表面的な事象に基づいた話になります。

恐らくFactoryGirlの内部で、上記各ケースが以下のようになっていると推定されます。

・ケース1:「store = FactoryGirl.create(:store)」

Store.new(store_category_name: 'Japanese Restaurant')

・ケース2:「store = FactoryGirl.create(:store, store_category: 2)」

Store.new(store_category: 2, store_category_name: 'Japanese Restaurant')

・ケース3:「store = FactoryGirl.create(:store, store_category_name: ‘French Restaurant’)」

Store.new(store_category_name: 'French Restaurant')

そして、Storeのinitializeの中で、渡されたHashの順番にattributeを更新していき、

ケース2では、

代入1回目:最初にstore_categoryに2が入る
代入2回目:その後にstore_category_nameにJapanese Restaurantが渡されて、store_categoryに1が入る

となっているのだと思います。

「今回の問題を抽象的に表現すると」との対応関係

このように、ケース2では、代入1回目と代入2回目で異なる方法(「複数の方法のうち少なくとも2つ以上の方法」)で、値を設定していることから条件2を満たすことになり、意図した値が設定されていません。

ケース1, 3では、1つの方法でのみ値を設定しているため、条件2を満たすことなく、意図通りの値が設定されます。

対策

今のところ、各ソースコードの確認や実際にテストする際に値が意図したものに設定されているか等を確認しながら気を付けるくらいしか思い付きません。

こういう問題があるということを頭の片隅に入れておけば、問題が生じたときのデバッグが早くなると思います。

参考

selectable_attrというgemを使うと、所定のattributeに値を設定するために複数のメソッドが追加されます。

selectable_attrの対象としたattributeに対してFactoryGirlを使って値を初期化する場合には気をつけましょう。

最後に

rspecを記載したときには、各オブジェクトの値が意図したものになっているかを、しっかりと確認しましょう。

そうしないと意味の無いテストを行ってしまっている可能性があります。

最近人気な記事