pluginの事を考えるとbeforeが複数回定義されてもちゃんとそれぞれが実行されないと意味が無い。なので試してみた。

komagata's double_before at master - GitHub

require 'rubygems'
require 'sinatra'

before do
@name = 'Masaki'
end

before do
@name += ' Komagata'
end

get '/' do
"Hello, #{@name}"
end
require 'rubygems'
require 'test/unit'
require 'rack/test'
require 'shoulda'
require './double_before'

class DoubleBeforeTest < Test::Unit::TestCase
include Rack::Test::Methods

def app
Sinatra::Application
end

context "Access pages" do
should "show index" do
get '/'
assert_equal 'Hello, Masaki Komagata', last_response.body
end
end
end
% ruby double_before_test.rb 
Loaded suite double_before_test
Started
.
Finished in 0.030489 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

おお、問題無い!これは期待してなかったので嬉しいですゾ!(@ムック)

PyhaLokkaにMLを作りました。

Lokka-ja | Google グループ

僕一人ではすごく悲しい雰囲気になってしまうのでサクラでいいので入ってください・・・。

PyhaLokkaの開発について

ブログってフレームワークのHello world的な扱いで出てくるぐらいなので誰でも作れます。逆に言うと技術的なチャレンジは少なく、どれだけ手を動かせるか的なところがあってプログラマー的には面倒です。だからあまりエッジな人は作りませんよね。あるとすればミニマリストのための超シンプルツールで、これは作ってて楽しい。僕も以前、普通に作り始めたらそうなってしまって、一般ユーザーやデザイナーがWordPressに求めてるようなものは出来ませんでした。

PHP以外で一般ユーザーやデザイナーにも普及するWebアプリなんて無理なんだと諦めていましたが、RedmineはWeb制作会社にいるデザイナーに何人か聞いたら結構な割合で知ってました。なんだ、Rubyでも行けるんじゃん。

「なんで僕らは仕事で、自分のブログで、WordPressを使ってるんだ?Rubyでそういうのが無いのはおかしい!」

そんなよく分からない義務感?が開発の原動力になっていて、元々そういうツールがあればそれを使いたいし、その開発に参加すれば良いと思っています。しかし上記の様な事情があってあまり作りたがる人はいません・・・。

※Radiant CMSは僕的に設計やコードは素晴らしくて若干うっとりしたぐらいです。しかしデザイナーに聞くと、本当に欲しいのは純粋なCMSではなく、ブログツールベースのCMSであるようなのです。

PyhaLokkaはSinatraベースのまだまだ未熟なブログツールなので、Rubyがわかれば誰でもコーディングの余地がいくらでもあります。(例えば投稿した後にflushで「投稿しました」とか出すべきなのを出してないとか、helperその他はpadrinoのモジュールに置き換えたいとか、テストが無いとか・・・)

貧相なプロジェクトの割にWordPress打倒!という分り易くも無茶な目標を掲げてやっていくのは面白いかもなあと最近思いはじめました。

「みんな、オラに力(コード)を分けてくれ!」

インストール

% bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head )

.zshrcに追加

if [[ -s /Users/komagata/.rvm/scripts/rvm ]] ; then source /Users/komagata/.rvm/scripts/rvm ; fi

ruby1.9.2をインストール

% rvm install 1.9.2

ruby1.8.7をインストール

% rvm install 1.8.7

デフォルトのrubyを設定する

% rvm --default 1.8.7-p299

RailsのオススメファイルアップロードプラグインのPaperclipですが、最新版(2.1.4)で嬉しい機能が増えてました。

  • ImageMagick(convertコマンド)に自由にオプションを渡せるようになった。
  • 画像が無いときのパスを指定できるようになった。

これは嬉しい。ソース内のコメントの例では、アップされた画像をlargeとnegativeというstyleに分け、両方にprofileやexif情報を削除する-stripオプションを適応し、negativeには補色で補完する(つまり反転?)-negateオプションを適応してます。

class User < ActiveRecord::Base
  has_attached_file :avatar,
    :styles => {
      :large => "300x300",
      :negative => "100x100"},
    :convert_options => {
      :all => "-strip",
      :negative => "-negate"}
end

RMagickや他のAPIを使わず、直接convert使ってる利点が生かされてますな。 他にも-monochromeオプションでモノクロにしたりとか色々出来そうです。

画像無いときのパス指定は、「あれ?これ指定できないの?」ぐらいだったんで俺がすっきりしただけですが。

以前にも書きましたが、Capistrano利用時にはアップ画像を/public/system以下に置きたいのでオプション指定が必要です。

いちいち指定してたらModelがキモくなるので通常、下記を使ってます。

config/initializers/paperclip.rb:

module Paperclip::ClassMethods
  def has_attached_file_with_default(name, options = {})
    default = {
      :path => ":rails_root/public/system/:class/:attachment/:id/:style/:basename.:extension",
      :url => "/system/:class/:attachment/:id/:style/:basename.:extension",
      :default_style => :normal,
      :default_url => "/images/:class/:attachement/missing_:style.png" 
    }

    has_attached_file_without_default(name, default.update(options))
  end

  alias_method_chain :has_attached_file, :default
end

config/initializers/以下は一番最後(pluginよりあと)に読まれるのでこういうアプリの本質的でない部分の変更には向いてますな。

RMagickインストール地獄にハマってる方はぜひご検討ください! (Debian etch、CentOS 5.2共にimagemagick/ImageMagickパッケージを入れるだけで済みます)

参照: Capistrano利用時のPaperclip

大体の画像系と同じようにnilとかを入れるだけでOK。

% ./script/console
Loading development environment (Rails 2.1.0)
>> grave = Grave.first
=> (略)
>> grave.overview.url
=> "/system/graves/overviews/1/normal/test_picture_large.gif" 
>> grave.overview = nil
=> nil
>> grave.save
=> true
>> grave.overview.url
=> "/overviews/normal/missing.png"

しかも、削除した場合のURLが自動的にmissing.pngに変わってる。

この勝手な挙動が嫌いな人もいるかもしれないけど面倒臭がりの俺としては嬉しい。

画像があるかどうかは、grave.overview.exists? で分かる。

thoughtbot: Paperclip File Attachments

Requirements

Only ImageMagick, which you can install quite easily install via apt, yum, or port, or the package manager of your choice.

あとやっぱりRMagick無くても動く!そういやImageMagick自体が問題なんじゃなくて、殆どの場合、パッケージのImageMagickが言語バインディングと合わないことが問題だったんだよね。PureRubyで再実装しかないと思ってた。頭良いな作者。

月曜日なので一心不乱にコード(仕事の)。

画像アップするプラグインを前に目を付けていたPaperclipに変えてみた。

file_columnと同じでファイルに画像を保存する形式。で、attachment_fuと違って専用のテーブルを作らないタイプ。

うーん、ファイルに保存方式だとcapistranoでdeployしてるとき困るんだよな~。そんでsystem以下に保存するように変えたり。

とりあえず使ってみた。

class User < ActiveRecord::Base
  has_attached_file :avatar, 
    :styles => { :medium => "300x300>",
      :thumb => "100x100>" }
end

モデルにhas_attached_fileを定義。

class AddAvatarColumnsToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :avatar_file_name, :string
    add_column :users, :avatar_content_type, :string
    add_column :users, :avatar_file_size, :integer
  end
  (略)
end

DBは専用のじゃなくて普通にそのモデルのテーブルに上記3種を追加。

<% form_for :user, :html => { :multipart => true } do |form| %>
  <%= form.file_field :avatar %>
<% end %>

アップするフォームはこんな感じ。

<%= image_tag @user.avatar.url %>
<%= image_tag @user.avatar.url(:medium) %>
<%= image_tag @user.avatar.url(:thumb) %>

画像表示もこんな風に深く考えなくてもいいようになってる。

あとImageMagickだけでRMagickが要らないっぽいです。そこは嬉しい。

で、file_columnでちょっと面倒だったファイルの保存場所関係はhas_attached_fileのオプションで結構柔軟っぽい設定ができそうでした。

:url => "/:attachment/:id/:style_:basename:extension" 
:url => "http://some.other.host/stuff/:class/:id_:extension"

シンプルなところが気に入りました。使ってこ。

参照: thoughtbot: Paperclip File Attachments

HABTMのupdateは面倒だ。

でも http://wiki.rubyonrails.com/rails/pages/CheckboxHABTM ここに詳しく載ってた。(と思ったらリンク先無くなってますね)

<% Group.find(:all).each do |g| %>
<%= check_box_tag "user[group_ids][]",
  g.id, @user.groups.include?(g)) %> <%= g.name %>
<% end %>

こんな感じで書いて、controllerのupdateに

@user.groups.clear if !params['user']['group_ids']

こう書いておけばチェック外したらちゃんと消える。

中間テーブルにidがあると変なidが勝手に入るし、Duplicate Entryになる。create時にidがつかないようにしとく。

create_table(:groups_users, :id => false) do |t|
 ・・・
end

昔ハマったはずなのにまたハマった。鳥頭・・・。

ヘルパー

普段どうやってるかというと、こういうヘルパーを使っています。

def habtm_check_box(object, method, target_method, options = {})
  id = object.class.name.underscore
  items = method.to_s.camelize.constantize
  items.all.map do |item|
    label_tag("#{id}_#{method}_#{item.id}",
      check_box_tag("#{id}[#{method}_ids][]",
        item.id,
        object.send(method.to_s.pluralize).include?(item),
        :id => "#{id}_#{method}_#{item.id}")+' '+h(item.send(target_method)),
    :class => 'checkbox')+"\n" 
  end.join
end

でgrave(お墓)が複数のcharacter(特徴)を持つ場合、

<%= habtm_check_box @grave, :character, :name %>

みたいな感じで使います。