LokkathonはLokka + Hack + Marathonです。 Lokkaに関する作業をモクモクとするイベントです。会場は用意されますが、Lingrのチャットのみでの参加も可能です。(むしろ推奨)
毎週やってるLokkathon #5、明日もやります。リモート参加も歓迎です。(リモート参加の場合はATND登録しなくて大丈夫です。)腹減るので食べてくるのがオススメです。
成果は毎回下記のようにlokka.orgのエントリーになるのでリモートでも何かやった方はURLとかスクリーンショットをLingrにいただければ載せていきたいと思います。(活動してるプロジェクト感を維持するために・・・)
module Foo
module Helpers
def bar
'unk'
end
end
end
こういうHelpersを
helpers do
include Foo::Helpers
end
こういう風に使ってた場合。
RSpec.configure do |config|
config.include Foo::Helpers
end
describe Foo::Helpers do
context 'bar' do
it 'should return unk' do
bar.should eql('unk')
end
end
end
Spec::Runner.configでincludeするとテスト出来る。
LokkaはSinatraベースなので同じようにHelpersのテスト書ける。でもRspecややこしいな。config.includeのとことか。とTest::Unit, Shoulda信者が申しております。
先週、怖話.jpのランキングを重いサブクエリを書いて実装しましたが、Rails3レシピブック(Recipe 093 カウンタキャッシュを利用する)を見ていたらcounter_cacheというので簡単に速くなりそうだったのでやってみた。
ASCIIcasts - “Episode 23 - Counter Cache Column”
要はfoo has many barsという関係の時にbarのbelongs_toに:counter_cache => true
と書いて、fooのDBにbars_countというカラムを追加すればいいらしい。
怖い話(story)に付いている怖い(scare)とコメント(comment)の集計にcounter_cacheを使ってみた。
class Scare < ActiveRecord::Base
belongs_to :story, :counter_cache => true
end
class Comment < ActiveRecord::Base
belongs_to :story, :counter_cache => true
end
class AddCounterCacheToStories < ActiveRecord::Migration
def self.up
add_column :stories, :comments_count, :integer, :null => false, :default => 0
add_column :stories, :scares_count, :integer, :null => false, :default => 0
Story.all.each do |story|
Story.update_counters(story.id, :comments_count => story.comments.count)
Story.update_counters(story.id, :scares_count => story.scares.count)
end
end
def self.down
remove_column :stories, :comments_count
remove_column :stories, :scares_count
end
end
counter_cacheはfooのcreateとdestroyのコールバックとして数を増減するというだけの動作なので、後付けする場合はupdate_countersメソッドで集計し直してやる必要がある。
class Story < ActiveRecord::Base
scope :order_by_ranking, joins(:user).order("view + (select count(*) from scares where scares.story_id = stories.id) * #{Scare::RANKING_WEIGHT} + (select count(*) from comments where comments.story_id = stories.id) * #{Comment::RANKING_WEIGHT} desc, stories.id desc").includes(:user)
end
お陰でこんな醜悪なクエリが、
class Story < ActiveRecord::Base
# scares_count and comments count is using counter_cache.
scope :order_by_ranking, joins(:user).order("view + scares_count * #{Scare::RANKING_WEIGHT} + comments_count * #{Comment::RANKING_WEIGHT} desc, stories.id desc").includes(:user)
end
ホッとするシンプルなクエリに。
しかし、キャッシュ系によくあることですが、カウンタキャッシュを使っているということをちゃんと意識してないと端からみたらわかり辛いことになるので、現在は一人開発ですが、将来の自分を含めた他人に向けて注意を喚起するコメントを残しておくことにしました。
rails + jenkinsでgithubにpushしたらテストというところまでは下記を参照してください。
ウェブオペレーションで継続的デプロイというキャッチーな単語を知ったので試してみた。
継続的デプロイなんつっても、上記の様にいつものテストにcapのタスクを追加するだけ。簡単。
githubにpushされると勝手にjenkinsが動き出して…
ステージング環境にデプロイ。
これでデザイナーの@machidaさんがgit pushした時も勝手にステージング環境が最新になる。デザインが変わっただけでも頻繁にデプロイされるので問題点などが議論し易い。(特にスマホサイトは実機からアクセス出来る環境があると便利。)
最近はデザイナーも簡単にGithubが使える環境が揃ってきたので、テスト・開発・チェックイン・デプロイというサイクルにデザイナーが入る良いタイミングかも。
% rake
`include Capybara` is deprecated please use `include Capybara::DSL` instead.
include Capybara
がdeprecatedになってたので指示通り書き換えました。
# test/test_helper.rb:
class ActiveSupport::TestCase
(...)
class ActionDispatch::IntegrationTest
include Capybara::DSL
Capybara.app = KowabanaJp::Application
end
end
Unit::TestとCapybaraでのIntegrationTestは簡単なのにちゃんと動く(バグを見つけたりデグレを防ぐ役割をちゃんと果たすという意味で)のでお気に入りです。
unicornのデフォルトとportが被ってるので変更した。Debianパッケージ版jenkinsは下記に設定がある。
# /etc/defaults/jenkins:
# port for HTTP connector (default 8080; disable with -1)
#HTTP_PORT=8080
HTTP_PORT=8000
毎日昼飯をどこで食べるのかに本業より頭を使ってる気がするので自動化した。
require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'mail'
api_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
version = 'v1.0'
station_ids = ['2800', '2811'] # hatagaya, hatsudai
page = 1
entries = 10
total_entries = 100
restaurants = []
station_ids.each do |station_id|
while page * entries < total_entries
url = "http://api.gourmet.livedoor.com/#{version}/restaurant/?api_key=#{api_key}&station_id=#{station_id}&sort=total"
doc = Nokogiri::XML(open("#{url}&page=#{page}"))
total_entries = doc.xpath('/results/total_entries').text.to_i
doc.xpath('/results/restaurant').each do |restaurant|
restaurants << {:name => restaurant.xpath('name').text,
:link => restaurant.xpath('permalink').text}
end
page += 1
end
end
restaurants.shuffle!
body = ''
restaurants[0, 10].each_with_index do |restaurant, i|
body += <<-EOS
#{i + 1}. #{restaurant[:name]}
#{restaurant[:link]}
EOS
end
mail = Mail.new do
from 'komagata@gmail.com'
to 'komagata@gmail.com,machidanohimitsu@gmail.com'
subject "Today's recommended restaurants"
body body
end
mail.delivery_method :sendmail
mail.deliver
ライブドアグルメの初台、幡ヶ谷の店からランダムで10個、12時になったらメールしてくれる。(これを前のエントリーの要領でcronに登録する)
こういうメールが届く。
これをWebサービスとして公開し、ユーザー同士で同じ店に行くことになったら偶然を利用してマッチングするというのを考えた。でもkowabana.jpをやりたいので誰か作って。
LokkathonはLokka + Hack + Marathonです。 Lokkaに関する作業をモクモクとするイベントです。会場は用意されますが、Lingrのチャットのみでの参加も可能です。(むしろ推奨)
予定通り毎週やってきます。スゴイ捗るんですが、スゴク疲れたので3時間から2時間にしました。あと、腹が減るので飯食ってからもしくは食いながらがいいと思います。
時間中はLingrにみんな常駐しますので何か言いたいとか聞きたいなどあれば是非。
0 12 * * 1,2,3,4,5 bash -c 'source ~/.rvm/scripts/rvm; rvm ruby-1.9.2p290@default exec ~/code/random_lunch/random_lunch.rb'
Use bash -c
and rvm exec