nirasan's tech blog

趣味や仕事の覚え書きです。Linux, Perl, PHP, Ruby, Javascript, Android, Cocos2d-x, Unity などに興味があります。

paperclip_database の導入メモ

はじめに

  • ActiveRecord のオブジェクトに画像ファイルを添付する gem の Paperclip で、画像の保存先をデータベースにする gem の paperclip_database の導入メモ。
  • Paperclip は導入済みで、User モデルの avatar カラムに添付画像情報を入れているものとする。

バージョン

  • Rails 4.2
  • Paperclip 4.2.1
  • paperclip_database 2.3.1

インストール

  • Gemfile
gem "paperclip_database", "~> 2.0"
  • インストール
bundle install

マイグレーションファイルの作成と実行

rails generate paperclip_database:migration User avatar
rake db:migrate

モデルの設定

  • :storage オプションを追加する
has_attached_file :avatar, :storage => :database

画像を返すアクションとルートの作成

ルートの作成

  • routes.rb で users リソースが定義済みの場合、member でルートの追加
resources :users do
  member do
    get :avatars
  end
end

アクションの作成

  • UsersController で paperclip_database のコントローラ拡張ミックスインのインポートと画像返却用のアクション定義メソッドの追記
class UsersController < ApplicationController
  include Paperclip::Storage::Database::ControllerClassMethods
  downloads_files_for :user, :avatar

テンプレートで画像の呼び出し

  • @user.image.url(:style) だと URL エンコード済みの文字列が出てきてしまうので、普通にルート名で URL を指定する。
<% image_tag(images_user_url(@user, :style => :medium)) %>

NGUI の UITweener の Animation Curve に任意の曲線を設定する

はじめに

  • Unity + NGUI で TweenPosition や TweenAlpha などの UITweener を継承したコンポーネントで Animation Curve の曲線をプログラムから設定する方法についてメモ。

バージョン

  • Unity 4.6.1f1
  • NGUI 3.7.6

設定方法

  • Animation Curve の曲線は AnimationCurve クラスで設定する
  • コンストラクタは AnimationCurve(Keyframe[])
  • Keyframe は曲線上の任意の点で Keyframe(x, y) で x が時間軸、y が変化量になる。
    • Keyframe の x は、開始地点が 0 で、終了地点が 1 になる。duration が 3秒 なら「x:0 = 0秒」で「x:1 = 3秒」となる。
    • Keyframe の y は、開始地点が 0 で、終了地点が 1 になる。TweenAlpha で変化前が 1 で変化後の値が 0 なら「y:0 = 1」で「y:1 = 0」となる。

コード例

開始から半分の時間まで変化しない場合

GameObject go = GameObject.Find("Path/To/Any/GameObject");
UITweener tw = TweenAlpha.Begin(go, 1f, 0.5f);
tw.animationCurve = new AnimationCurve(
	new Keyframe(  0f, 0f),
	new Keyframe(0.5f, 0f),
	new Keyframe(  1f, 1f)
);

点滅する場合

GameObject go = GameObject.Find("Path/To/Any/GameObject");
UITweener tw = TweenAlpha.Begin(go, 1f, 0.5f);
tw.animationCurve = new AnimationCurve(
	new Keyframe(  0f, 0f),
	new Keyframe(0.2f, 1f)
	new Keyframe(0.4f, 0f),
	new Keyframe(0.6f, 1f)
	new Keyframe(0.8f, 0f),
	new Keyframe(  1f, 1f)
);

Keyframe に入る角度と出る角度の指定をする

  • Keyframe のコンストラクタで Keyframe(x, y, inTangent, outTangent) というパターンが有り inTangent と outTangent で曲線の入る角度と出る角度を指定できる。
  • inTangent, outTangent の単位は tangent なので、角度を指定したい場合は変換する必要がある。

角度からタンジェントへの変換

// 角度からタンジェントへ
float DegreesToTan (float degrees) {
	return Mathf.Tan(DegreesToRadians(degrees));
}
// 角度からラジアンへ
float DegreesToRadians (float degrees) {
	return degrees * Mathf.PI / 180f;
}

コード例

イーズアウト

GameObject go = GameObject.Find("Path/To/Any/GameObject");
UITweener tw = TweenAlpha.Begin(go, 1f, 0.5f);
tw.animationCurve = new AnimationCurve(
	new Keyframe(0f, 0f, 0f, DegreesToTan(70f)),
	new Keyframe(1f, 1f, DegreesToTan(10f), 0f)
};

イーズイン

GameObject go = GameObject.Find("Path/To/Any/GameObject");
UITweener tw = TweenAlpha.Begin(go, 1f, 0.5f);
tw.animationCurve = new AnimationCurve(
	new Keyframe(0f, 0f,                0f, 0f),
	new Keyframe(1f, 1f, DegreesToTan(70f), 0f)
};

波を描く

GameObject go = GameObject.Find("Path/To/Any/GameObject");
UITweener tw = TweenAlpha.Begin(go, 1f, 0.5f);
tw.animationCurve = new AnimationCurve(
	new Keyframe(   0f,   0f,                 0f,                 0f),
	new Keyframe(0.25f, 0.5f, DegreesToTan(-85f), DegreesToTan(-85f)),
	new Keyframe(0.5f,  0.5f, DegreesToTan(-85f), DegreesToTan(-85f)),
	new Keyframe(0.75f, 0.5f, DegreesToTan(-85f), DegreesToTan(-85f)),
	new Keyframe(   1f,   1f,                 0f,                 0f)
};

NGUI で UILabel の文字量に従って縦幅だけ変動させるスクリプト

using UnityEngine;
using System.Collections;

/// <summary>
/// UILabel の横幅を固定して text に従った縦幅に設定するスクリプト
/// </summary>
public class UILabelHeightFitter : MonoBehaviour {

    /// <summary>
    /// リサイズ対象の UILabel
    /// </summary>
    public UILabel label;

    private string beforeText = "";

	void Update () {
        // UILabel.text が更新されるたびにリサイズを実行
        if (label.text != beforeText) {
            ResizeHeight();
            beforeText = label.text;
        }
	}

    /// <summary>
    /// UILabel.text の文字量に従って UILabel.height を変更する。
    /// 簡単のため「UILabel.fontSize == 文字の幅 == 文字の高さ」という前提で計算しているので、
    /// 半角全角の混在や可変幅フォントの使用によりずれが生じる場合がある
    /// </summary>
    void ResizeHeight () {
        int line = 1;
        int chara = 0;
        int maxChara = label.width / (label.fontSize + label.spacingX);
        string text = label.text;
        for (int i = 0; i < text.Length; i++) {
            if (text[i] != '\n') {
                chara++;
                if (chara >= maxChara) {
                    chara = 0;
                    line++;
                }
            } else {
                chara = 0;
                line++;
            }
        }
        label.height = (label.fontSize + label.spacingY) * line;
    }
}

自分用 RubyMine ショートカットメモ

ジャンプ
宣言へジャンプ
Command + b
使用箇所のリスト
Alt + F7
タブ移動
左へ
Command + Shift + @
右へ
Command + Shift + [

NGUI の ScrollView で気持ちのいいスクロールを実装する

気持ちが良いスクロールとは?

  • 今回は「ちょっとスワイプするだけで次の要素にスッと切り替わる」ものを実装する。

バージョン情報

  • Unity 4.6.1f
  • NGUI 3.7.6

ヒエラルキー

UI Root
	ScrollView
		Grid

ScrollView の作成

  • メニューの [NGUI] > [Create] > [Scroll View] で作成

Grid の作成

  • メニューの [NGUI] > [Create] > [Grid] で作成
  • UICenterOnChild をアタッチ

オプション設定

  • UIGrid の Sorting を None 以外にする
    • わからなければ Custom にする
  • UICenterOnChild の NextPageThreshold を 1 にする

動作確認

  • Grid 配下に任意の UIDragScrollView とコライダーがアタッチされたオブジェクトを追加して動作を確認する。

解説

  • UICenterOnChild.NextPageThreshold が 0 より大きく、UIGrid の Sorting が None 以外である時、スワイプした距離が NextPageThreshold より大きければ UICenterOnChild により次あるいは前の要素に切り替わる。

注意点

  • ScrollView をループさせるスクリプトの UIWrapContent が有効であると、この処理は正常に行われなかった。

Rails 4.2 で Heroku にデプロイしたメモ

はじめに

  • Rails 4.2 で開発していたアプリを Heroku にデプロイした時にやったことメモ

環境

Heroku にユーザー登録

Heroku アプリの作成

$ cd /path/to/rails/app
$ heroku create

Heroku 用の gem の追加

$ vi Gemfile
-gem 'sqlite3'
+gem 'sqlite3', :group => [:development, :test]
+gem 'pg', :group => [:production] # heroku で DBMS として PostgreSQL を使用するために必要
+gem 'rails_12factor', group: :production # heroku で Rails 4 を動かすために調整してくれるやつ
$ bundle install --without production

Devise の設定

  • Devise を使っている場合
$ vi config/initializers/devise.rb
config.secret_key = '<%= ENV["DEVISE_SECRET_KEY"] %>' if Rails.env.production? 
heroku config:add DEVISE_SECRET_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

データベースの設定

$ vi config/database.yml
production:
  adapter: postgresql
  encoding: unicode
  pool: 5

シークレットキーの設定

  • シークレットキーを環境変数から読み込むように
$ vi config/secrets.yml
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>                                                                                                                                    
  • .gitignore に config/secrets.yml が登録されている場合は削除する

デプロイ

$ git commit -am 'for heroku'
$ git push heroku master
$ heroku run rake db:migrate

Rails 4.2 で destroy のバリデーションをする

任意の条件でバリデーションをする

  • http://qiita.com/tbaba/items/9ea139dc77443e6d7be2 の通り、before_destroy に指定したメソッド内で条件を判定し、destroy 不可であれば return false する
  • 前記記事の通り before_destroy :method_name の記法ではなく、before_destroy do ... end で宣言すると、return false 時に LocalJumpError の例外が発生して意図したように動作しなくてはまった

関連レコードがある場合は destroy できないように

  • バリデーションの条件として、関連するレコードがあったら destroy 出来なくしたいだけの場合は has_meny のオプションだけで対応できる
models
has_many :associate_name, dependent: :restrict_with_error
# has_many のその他のオプション
# http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
controllers
if @result = @obj.destroy
  # 成功
else
  # 失敗
end