homebrewは元々自分のディレクトリ以外を汚さないように出来ているので好きな場所に置いてPATHを通す。
% curl http://github.com/mxcl/homebrew/tarball/master -LO
% tar zxf master
% mv mxcl-homebrew-348d28f ~/homebrew
# ~/.zshrc
export PATH=~/homebrew/bin:$PATH
homebrewは元々自分のディレクトリ以外を汚さないように出来ているので好きな場所に置いてPATHを通す。
% curl http://github.com/mxcl/homebrew/tarball/master -LO
% tar zxf master
% mv mxcl-homebrew-348d28f ~/homebrew
# ~/.zshrc
export PATH=~/homebrew/bin:$PATH
% ls
% GEM_HOME=`pwd` gem list > /dev/null
% ls
cache doc gems specifications
なにそれこわい。
gem environmentとかでも同様。
option + y
@dandasoに何故gitを使うのか、svnから移行するコストを払うに見合う嬉しさは何なのか聞かれた。
gitを使いこなしてる方々に取っては噴飯ものの解答だと思うが、俺はこう答えた。
「殆どのトラブルはcommit時に起こる。svnは1ステップで全員共通のリポジトリにcommitされるのでmergeやcommitは怖いが、gitはcommitした後にpushしないと他人に影響が出ない。だから気軽にcommitしたりmerge出来る。その違いが嬉しい。」
LokkaにSnippet(スニペット)を追加しました。
Snippetとはテンプレート間で共有したい部品を入れておくものです。Pageも同じ用途に使えるのでWordPressではそれが常套手段っぽいですが、@machidaさんが
「PageはURLが存在するので直接アクセスできるのが気持ち悪い」
と言っていたのでSnippetという名前で別に用意しました。
このブログで言えば、右のプロフィールの部分でSnipetを使っています。今まではPageの機能を使っていたので、プロフィール単体がURLを持っているので妙なページが存在することになっていました。
Snippetは好きに名前を付けられるのでテンプレ内では下記のようにかけます。
<%= Snippet.first(:name => 'about').body %>
今回、各モデル用にユーティリティメソッドを用意しました。そのユーティリティメソッドとは"そのクラスで一番使いそうなメソッドをクラス名と同名のメソッドとして用意したもの"です。それを使えば上記は下記のように書けます。
<%= Snippet('about').body %>
要はこれです。
Ruby - クラス名と同名の関数にデフォルト動作をさせるパターン - komagata [p0t]同じように他のモデルにも用意されています。
<h2><%= Page('inquiry').title %></h2>
DataMapperのAPIを使えば何でも取れますが、テンプレートがスッキリするかなと。
SPAMで大変なことになっていたこのブログのコメントを@yagi_さんのAkismetプラグインをきっかけに整理してみた。とりあえず既存のSPAMを消すが大変だった。そもそもSPAM判定されようがされまいが、コメントがDBに投稿される数が多過ぎるので、
%form
:javascript
document.write('<input type="hidden" name="check" value="check" />')
と入れて、checkという値が無かったら404を返すようにした。SPAM BOTがJavascript を理解するかどうかというただそれだけだけど、今までは1日に数百個コメントSPAMが来るとかザラだったので大分違う気がします。何か他に簡単で99%ぐらいのスパムを弾ける方法があればいいなと思います。
テーマを書くときに、今どのページなのか(カテゴリー別ページなのか、個別ページなのか等)を判断する関数をWordPressではConditional Tagと言うらしいです。@machidaさんからの要望で、個別ページ(entry?)の中でも投稿(Post)なのかページ(Page)なのかが一発で判断できるConditional Tagが欲しいと言っていたので追加しました。
%w[index search category tag yearly monthly daily post page entry entries].each do |name|
define_method("#{name}?") do
@theme_types.include?(name.to_sym)
end
end
post?とpage?というhelperを追加しただけです。
何文字以上だったら"xxxxxxxxxxxxx..."みたいに縮めるtruncateが日本語文字列の途中でぶった切ってしまうのを直しました。微妙に気になってたんです。
def truncate(text, options = {})
options = {:length => 30, :ommision => '...'}.merge(options)
if options[:length] < text.split(//u).size
text.split(//u)[0, options[:length]].to_s + options[:ommision]
else
text
end
end
split(//u)で配列にして文字数を判断するようにしました。何か場当たり的な感じで怒られそうだけど・・・。
S3を触っています。S3に独自のユーザー管理の仕組みを組み込む方法がわからず困ってます。(@junyaさんや@yagi_さんに色々教えてもらいました。ありがとうございます。)
例えば、Webサービスを作ったとして、そのサービスのアカウント毎にS3に領域を作ってファイルにアクセスさせたい場合に、そのサービス経由でファイルをダウンロードしては不必要なトラフィックが発生してしまうのでS3から直接ダウンロードして欲しいハズです。
PROXY的な手法は使えないのでS3自身にユーザーを作成したり、そのユーザー毎に権限を設定したりが可能である必要があります。
S3の認証方法は色々あるんですが、Webサービスのユーザーと同期させるような大量ユーザーを想定のものは無いっぽいです。(もしあればホント教えて欲しいです・・・)
色々な認証方法:
今Preview Beta中のIAM(Identity and Access Management)という仕組みもユーザー数は最大5000となっていて、企業内とか開発者とかのアクセス権限を細かく設定するための仕組みっぽいです。
そこで気になっていたのがHeroku PG Backupsでdumpファイルのダウンロード方法が期限付きのS3のURLになってた仕組みです。ちょっとわかり辛いんですが、"Query String Authentication"とか"Signed URLs"とかでググると出てきます。
require 'aws/s3'
AWS::S3::Base.establish_connection!(
:access_key_id => 'XXXXXXXXXXXXXX',
:secret_access_key => 'XXXXXXXXXXXXXXXXXX')
puts AWS::S3::S3Object.url_for(
'foo.jpg',
'my-bucket-name',
:expires_in => 60 * 10)
http://s3.amazonaws.com/my-bucket-name/foo.jpg?AWSAccessKeyId=xxxxxxxx&Expires=1293402048&Signature=xxxxxxxx
aws-s3だとurl_forというメソッドで認証済みのURLが簡単に取得できます。Signatureの生成方法はちゃんと見てないんですが、このオブジェクトだけに通用するSignatureなので前述したような"独自のユーザー管理を使いつつS3から直接ダウンロードさせたい"という場合に使えそうです。
しかし、ダウンロードはこれでいいとしてもアップロードの方はどうすればいいんでしょう。根本的な解決にはなってない気がします。せいぜい、アップロード専用の制限されたアカウントでアップロードして、別アカウントからmoveするぐらいしか思いつきません・・・。
DataMapperを教えておじいさん | Selfkleptomaniacに回答しようとしたら、既に解決されていた・・・。
require 'rubygems'
require 'dm-core'
require 'dm-migrations'
class Repo
include DataMapper::Resource
property :id, Serial
property :body, String
end
DataMapper.logger.set_log STDERR, :debug, "SQL: ", true
DataMapper.setup(:default, 'sqlite::memory:')
Repo.auto_migrate!
puts Repo.all(:body.like => '%hoge%') |
Repo.all(:body.like => '%fuga%') |
Repo.all(:body.like => '%piyo%')
結果:
SQL: (0.000045) SELECT sqlite_version(*)
SQL: (0.000082) DROP TABLE IF EXISTS "repos"
SQL: (0.000014) PRAGMA table_info("repos")
SQL: (0.000393) CREATE TABLE "repos" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "body" VARCHAR(50))
SQL: (0.000079) SELECT "id", "body" FROM "repos" WHERE ("body" LIKE '%piyo%' OR "body" LIKE '%hoge%' OR "body" LIKE '%fuga%') ORDER BY "id"
検索条件の場合、分かりやすく書くとこういう感じでしょうか。検索条件の論理演算がRubyの演算子で出来るのが面白いですね。しかし恐ろしく遅そうなSQLが。
Lokkaでもしちゃんと検索をやるならばLuceneのRuby版であるFerretをdm-ferret-adapterで使うのが楽そうです。datamapperのadapterになってるということはindexの置き場所も何でもいいというフリーダムさ。検索式を解析するFerret::QueryParserが日本語対応してるかわからないので面倒かもしれません。
@func09さんがオフィスに来てフレグランス的なものくれました。あざーす!
@func09さんはStartups2010の支援チームの5組の一つに選ばれ、FoodFotoという会社を作られたばかりなので忙しそうです。
[jp]サイバーエージェントがStartups2010の支援チームを発表、結果は5チーム
100チームぐらい応募があってその中の5組なんでスゴイですよね!
僕らはといえば純喫茶車で脳が溶ける程だらだらしていたところに@func09さんがいらっしゃるという情報をキャッチして、
「飲み物は無難にスタバか・・・」「いや豆乳も」「いやいや、豆乳は人選びすぎでしょ」
とか
「お茶菓子はブルボン的なルマンドみたいなものがいいか」「いや、甘い飲み物にチョコは・・・」「子供の頃は友達の家に遊びに行って出されるお菓子って今考えると高めの物が多いんだけどクソガキにとってはポテチとか出して欲しかったっすよね?」
とかしょうもない時間を過ごしていました。
しかし、何か妙な縁がありますな。
@func09さんとはじめてあったのは確か今から36万・・・いや2〜3年前だったか。元同僚の@llpkenさんとかと飲もうという話をしたら「今FlashやってるデザイナーさんでRailsとかも好きでkomagataさんのブログ知ってるって人いますよ」と聞いて、マジすかということで飲み会であったのが最初。
Help me, hackers!というサイトを作ってたらオープン前日にラペコがオープンし、サイトリリースの作業そっちのけでラペコ初日に肉を投稿しまくって注目のユーザー1位をゲットしたり、何故か旧オフィスでフィヨルド+つくる社+@func09さんで飲み会を開催したり。
暇そうなヤツということで何故かスペイシーズの社外取締役になり、@ebiharahideyukiさんがイベントをやると言っていたのでブログに書いたらそれ見て@func09さんが応募したとか言ってたり。Twitterで忙しそうだなーと思ってたら支援チームに選出されて会社を作られたり。
「Railsが好き」とか「37signalsが好き」とか「理論よりも動く物が好き」など、嗜好が似た人達って、会ったことは無くてもお互いのブログチェックしてたり、毎日チェックしてるサイトが同じだったり、行きたいイベントが同じだったりしてほっておいてもどこかで偶然出会っちゃうんですよね。
初めて会った人に、
「komagataさんのブログ見てますよ」
っ言われることが稀にありますが、
「うるせー!俺のほうがお前のブログ見てるわ!」
ってことが殆どです。
FoodFotoはRailsとiPhoneができるエンジニアを募集してるっぽいです。応募方法は多分@func09さんにTwitterのDM?
そういった意味でもFoodFotoにオモロイプログラマーが入ったらオモロイですよねー(俺が)
募集してなかったり締切ってたらごめんなさいね。