# config/application.rb
module Foo
  class Application < Rails::Application
    (snip)
    config.sass.preferred_syntax = :sass
  end
end

cordovaを使う時にhamlとsassとcoffeeを使いたかったのでguardでそれぞれをwatchするようにした。

普段は何らかのWebサーバーが立ち上がってて出力を直接返すからこういう風にそれぞれの静的ファイルを必要とすることって意外と少ないですね。

$ gem install guard-haml guard-sass guard-coffeescript

Terminal — zsh — 80×24

このようなディレクトリ構成にする場合。

# Guardfile
haml_options = { format: :html5, attr_wrapper: '"', ugly: true } 
guard "haml", input: "haml", output: "www", haml_options: haml_options  do
  watch %r{^haml/.+\.haml}     
end
guard "sass", input: "sass", output: "www/stylesheets"
guard "coffeescript", input: "coffeescripts", output: "www/javascripts", bare: true

GUIのCodeKitってヤツを試したんだけど、ちょっとカスタマイズしたくなるとやっぱりCLIが便利ですね。

ペパボの新しいPaaS、SQALEのクローズドβ招待頂いたのでやってみた。

ダッシュボードで公開鍵を登録して下記。

$ git clone ssh://sqale@gateway.sqale.jp:2222/komagata/foo.git
$ cd foo
$ vi config.ru
require 'rubygems'
require 'rack'

class App
  def call(env)
    [200, {'Content-Type' => 'text/plain'}, ['foo']]
  end
end

run App.new

$ git commit -am'First commit'
$ git push origin master
$ open http://foo-komagata.sqale.jp/

http://foo-komagata.sqale.jp/

おお、動いた。

他のPaaSとどう差別化していくのか気になりますね。

Macを再インストールしたのでrvmが新しくなったからか、capれない。

% bundle exec cap staging deploy
/Users/komagata/.rvm/lib/rvm/capistrano.rb:5:in `': RVM - Capistrano integration was extracted to a separate gem, install: `gem install rvm-capistrano` and remove the `$LOAD_PATH.unshift` line, note also the 'set :rvm_type, :user' is now the default (instead of :system). (RuntimeError)

長いエラーをちゃんと読むと、rvmのcapistrano関連の部分はrvm-capistranoとして別gemになったようです。Gemfileに追加します。

group :development do
  gem 'rvm-capistrano'
end

また「$LOAD_PATH.unshiftしてんのを取れ」と出てるので大抵の人はRAILS_ROOT/config/deploy.rbに書いてる下記を取ればOK。

$:.unshift(File.expand_path('./lib', ENV['rvm_path'])) # REMOVE ME!

コンパイラが変わるという大転換期なので仕方無いとは思いますが、Xcode依存のゴタゴタはプログラマーにも厄介。デザイナーさんに環境作ってと気軽に言い辛いここ最近のMac環境です…。

I reinstalled Mac OS X Lion in Golden Week. 

Clean install by Bootable USB Memory at first.

System Preferences

System Preferences

  • Keyboard
    • Keyboard
      • Delay Until Repeat
        • Shortest
      • Use all F1, F2, etc. keys as standard functions keys [X]
      • Modifier Kyes
        • Caps Lock
          • Control
    • Keyboard Shortcuts
      • Application Shortcuts
        • +
          • Application: All Applications
          • Menu Title: Zoom
          • Cmd-Enter
        • +
          • Application: Terminal
          • Menu Title: Select Next Tab
          • Cmd-]
        • +
          • Application: Terminal
          • Menu Title: Select Previous Tab
          • Cmd-[
        • Full Keyboard Access:In windows and dialogs, press Tab to move keyboard focus between:
          • All controls
      • Mouse
        • Point & Click
          • Scroll direction: natulal [ ]
      • Dock
        • Automatically hide and show the Dock [X]
      • Energy Saver
        • Power Adapter
          • Computer sleep
            • 3 hrs
          • Display sleep
            • 3 hrs
      • Spotlight
        • Search Results
          • Spotlight menu keyboard shortcut: [ ]
          • Spotlight window keyboard shortcut: [ ]
      • Date & Time
        • Clock
          • Use a 24-hour clock [X]
          • Show date [X]
      • Desktop & Screen Saver
        • Screen Saver
          • Start screen saver: Never
      • Software

        Applications

        Software from App Store

        Purchases

        • Keynote
        • Xcode
        • Echofon Lite for Twitter
        • iShowU
        • Skitch
        • The Unarchiver
        • MPlayerX

        Other

        • Software Update
        • Remove all icons from Dock

        Auto start movies on QuickTime X

        $ defaults write com.apple.QuickTimePlayerX MGPlayMovieOnOpen 1

        Accelarate a keyrepeat

        $ defaults write NSGlobalDomain KeyRepeat -int 1

        And reboot.

        Show dot files in Finder

        $ defaults write com.apple.finder AppleShowAllFiles TRUE
        $ killall Finder

        Disable the “Is An Application Downloaded from the internet” Warning

        $ xattr -d -r com.apple.quarantine ~/Downloads

        Disable Dashboard

        $ defaults write com.apple.dashboard mcx-disabled -boolean YES
        $ killall Finder

        Hide a last login date

        $ touch ~/.hushlogin

        Terminal

        Terminal — zsh — 80×24

        • Preferences
          • Settings
            • Text
              • Monaco 14 pt
            • Window
              • Scrollback
                • Limit number of rows to: 10000
          • Shell
            • When the shell exits:
              • Close if the shell exitd cleanly

        Development Environment

        Xcode

        • Preferences
          • Downloads
            • Components
              • Command Line Tools
                • Install

        Android

        Download and Install Android SDK

        ssh

        $ cp -r /BACKUP_DIR/.ssh ~/

        zsh

        $ chsh -s /bin/zsh

        dotfile

        komagata / dotfile / source — Bitbucket

        bitbucket is pretty good for dotfile repos. because private repos is free.

        $ git clone git@bitbucket.org:komagata/dotfile.git ~/code/dotfile
        $ cd ~/code/dotfile
        $ ruby symlink.rb
        $ source ~/.zshrc

        vim

        Terminal — vim — 80×24

        .vimrc and plugins is contained dotfiles directory.

        Plugins:

        Bundle ‘The-NERD-tree’
        Bundle ‘quickrun’
        Bundle ‘fakeclip’
        Bundle ‘tpope/vim-rails’
        Bundle ‘vim-ruby/vim-ruby’
        Bundle ‘Shougo/neocomplcache’

        rvm

        $ curl -L get.rvm.io | bash -s stable
        $ source ~/.rvm/scripts/rvm
        $ rvm requirements

        homebrew

        $ /usr/bin/ruby -e “$(/usr/bin/curl -fsSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)”
        $ brew install libksba

        imagemagick

        If you get something wrong, use below.

        $ brew install imagemagick –build-from-source

        ruby

        You can’t use multibyte-language (Japanese etc) in irb when install without option.

        $ rvm pkg install readline iconv
        $ rvm install 1.9.3-p194 –with-readline-dir=$rvm_usr_path --with-iconv-dir=$rvm_path/usr

        mysql

        $ brew install mysql
        $ unset TMPDIR
        $ mysql_install_db –verbose –user=whoami –basedir=”$(brew –prefix mysql)” –datadir=/usr/local/var/mysql –tmpdir=/tmp
        $ cp /usr/local/Cellar/mysql/5.5.20/homebrew.mxcl.mysql.plist ~/Library/LaunchAgents/
        $ launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
$ rvm install ruby-1.9.3-p125
Installing Ruby from source to: /home/deployer/.rvm/rubies/ruby-1.9.3-p125, this may take a while depending on your cpu(s)...

ruby-1.9.3-p125 - #fetching 
ruby-1.9.3-p125 - #extracted to /home/deployer/.rvm/src/ruby-1.9.3-p125 (already extracted)
Applying patch 'xcode-debugopt-fix-r34840' (located at /home/deployer/.rvm/patches/ruby/1.9.3/p125/xcode-debugopt-fix-r34840.diff)
Error running 'patch -F 25 -p1 -N -f <"/home/deployer/.rvm/patches/ruby/1.9.3/p125/xcode-debugopt-fix-r34840.diff"', please read /home/deployer/.rvm/log/ruby-1.9.3-p125/patch.apply.xcode-debugopt-fix-r34840.log

autoconfが必要らしいので入れる。

$ sudo apt-get install autoconf

こういう場合、普通にinstallするとパッチ当て損ないのソースをもう一度使おうとするらしく、reinstallする。

$ rvm reinstall ruby-1.9.3-p125

OK。

rvmでruby-1.9.3-p125をinstallしたらエラー。指示に従ってmakeログを見てみる。

% lv /Users/komagata/.rvm/log/ruby-1.9.3-p125/make.log
[2012-03-20 05:12:02] make 
        CC = clang
(snip)

おお。平然とcコンパイラがclangになってる。ちょっとおっさん、軽く遠い目をしてしまいました。

% vi ~/.zshrc
export CC=gcc-4.2

コンパイラをgcc-4.2にしたら無事installできました。 clangって何か未来的な感じがしますね。今度勉強しよう。

deviseはデフォルトでuserの更新(Devise::RegistrationsController#update)に現在のパスワード(current_password)が要る。

ソースを見てみるとmodelにupdate_without_passwordというのがあるのでこれかと思いきや、これはpasswordとpassword_confirmation無しでupdateするものだった。

自分でupdate_without_current_passwordを作る。

# app/models/user.rb:
class User < ActiveRecord::Base
  def update_without_current_password(params, *options)
    params.delete(:current_password)                                                                                  

    if params[:password].blank?
      params.delete(:password)
      params.delete(:password_confirmation) if params[:password_confirmation].blank? 
    end

    clean_up_passwords
    update_attributes(params, *options)
  end
end

controllerからもこれを使うようにする。

# app/controllers/registrations_controller.rb:
class RegistrationsController < Devise::RegistrationsController    
  def update
    @user = User.find(current_user.id)
    if @user.update_without_current_password(params[:user])
      sign_in @user, bypass: true
      set_flash_message :notice, :updated
      redirect_to after_update_path_for(@user)
    else
      render 'edit'
    end
  end
end

面倒ですね。

@tomykairaさんの素晴らしいエントリーに触発されて、Lokkaの現在の課題と何をしようとしてるのかを書いてみます。

[lokka][ruby][test]lokka コミッタからのお願いをお読みください - tomykaira makes love with codes

テスト問題も重要で@tomykairaさんや皆さんの協力でテスト拡充に向けて動き始めました。それとは別に僕の取り組んでる事について。

優先してやりたいこと

  • プラグインの仕様を決めること。
  • gem化。
  • 普通の人でも使えるようにすること。

Lokkaに足りない機能は色々ありますが、まずは機能を追加して行ける土台を作ることが大事だと思っています。gem化もその土台に必要なものです。

現在の問題

  1. gem化可能なプラグインの仕様がちとむずい(gem化するとviewの場所がわからなくなる)
  2. 以前のプラグインとの互換性をどうするか
  3. プラグインの自動読み込みがむずい
  4. bundle installオプションとかむずい。管理画面にプログラマー向けっぽい項目が最初から出てる。

1. Lokkaのプラグインは管理画面を持つ事が多いのでRailsで言えばEngine的な性質を持つものが多いことになる。ここはSinatraアプリがRackアプリでもあるという性質を使って、Sinatraアプリ(恐らくそれを継承したLokka::Plugin)をプラグインということにしてuseする。

2. 従来のものも普通にregisterする。

bundlerではlokka-hello.gemをBundler.requireしてもlokka/hello.rbはrequireしてくれない。lokka-hello.rbをrequireする。

3. railsでもそういう名前のgemではlokka-hello.rbを用意してその中でrequireしてるので、

# lokka-hello.rb:
require 'lokka/hello'
register Lokka::Hello

みたいに書いてくださいという決まりにする。

4. どうしよう。Lokka本体をgem化する時に簡単になるように考える?

まとめ

要は

  • Before Rails3 style gem -> Sinatra extension style gem
  • Rails3 style gem -> Sinatra App Style gem

って感じでrailsのパクリで行こうと思います。

Railsで綺麗なURLにしたいと思うと一つのControllerに機能が集中して困ることがあります。

/comments
/posts/1/comments
/users/1/comments
# config/routes.rb:
Foo::Application.routes.draw do
  resources :comments
  resources :posts do
    resources :comments
  end
  resources :users do
    resources :comments
  end
end

例えばこんな風にしたい時。

# app/controllers/comments_controller.rb:
class CommentsController < ApplicationController
  def index
    @comments =
      if params[:post_id]
        Post.find(params[:post_id]).comments
      elsif params[:user_id]
        User.find(params[:user_id]).comments
      else
        Comment.all
      end
  end
end

こんな風に書く?えーキモーイ。そもそもそれぞれの場合でviewが全然違うんですけどーみたいな場合。

そんなんねぇ俺の糞みたいな悩みはねぇStack Overflowさんに聞けば一発なんですよ。

Rails Namespace vs. Nested Resource - Stack Overflow

controllerのnamespaceでスッキリ書けるみたいです。

/comments
/posts/1/comments
/users/1/comments
# config/routes.rb:
Foo::Application.routes.draw do
  resources :comments
  resources :posts do
    resources :comments, controller: 'posts/comments'
  end
  resources :users do
    resources :comments, controller: 'users/comments'
  end
end
# app/controllers/comments_controller.rb:
class CommentsController < ApplicationController
  def index
    @comments = Comment.all
  end
end

# app/controllers/posts/comments_controller.rb:
class Posts::CommentsController < ApplicationController
  def index
    @comments = Post.find(params[:post_id]).comments
  end
end

# app/controllers/users/comments_controller.rb:
class Users::CommentsController < ApplicationController
  def index
    @comments = User.find(params[:user_id]).comments
  end
end
$ rake routes
(snip)
comments GET    /comments(.:format)                       comments#inde
post_comments GET    /posts/:post_id/comments(.:format)     posts/comments#index
user_comments GET    /users/:user_id/comments(.:format)     users/comments#index
(snip)

おおお、これはスッキリ!

Stack Overflow脳の恐怖。