Bitbucketのプライベートリポジトリで管理しているJekyllで作った静的サイトを、無料のCIサービスwerckerを使って自動でS3にデプロイする
先日S3に移行した片平堂のサイトですが、Jekyll、Bitbucketのプライベートリポジトリ、CIサービスのwerckerを利用して、リポジトリにpushしたら自動でS3に反映するようにしました。
なお、静的サイトジェネレータはMiddlemanとJekyllで迷ったのですが、非プログラマな方も触るので、規約がMiddlemanとくらべてうるさくないと感じたJekyllにしてみました。
ちなみに自分一人だけならMiddlemanを選ぶかなと思いました。
テンプレートもHamlとかSlimとか色々選べますし、Asset Pipelineも使えますし。
触る方のスキルが上がったらMiddlemanに乗り換えるかもしれません。
後、S3にデプロイするためにjekyll-s3 とかありますが、前述の通り、デプロイ作業をするのが一人ではないので、CIを使ってみました。
手順としては以下のような感じで進めました。
スタート,既存サイトのHTML(VCS未使用,Cyberduckで手動でS3にアップロードしていた)
↓
Jekyll使用に移行
↓
Jekyll使用にしたものをBitBucketに登録
↓
werckerにユーザ登録,Bitbucketの該当リポジトリを登録
↓
Bitbucketにpushしたらwerckerでbuild出来る所まで設定、テストする
↓
werckerのS3へのデプロイ情報を設定
↓
buildしたものをS3にデプロイできる事を確認
既存サイトをJekyllに移行
4ページ程度のサイトで動的な部分もないのでこの作業は簡単でした。
既存サイトのディレクリでGemfileを用意。
# Gemfile source 'http://rubygems.org' gem 'jekyll' gem 'redcarpet'
bundle installします。
% bundle install --path vendor/bundle
build時に、Gemfile,vendorなどが含まれないように_config.ymlを用意して設定。
# _config.yml name: 片平堂 markdown: redcarpet pygments: true exclude: ["vendor", "Gemfile", "Gemfile.lock"]
一度問題なく生成できるか確認。
% bundle exec jekyll serve --watch
OKだったので、レイアウトを使用するように。
% mkdir _layouts
default.html用意
<!- _layouts/default.html-> <!DOCTYPE html> <html> <head lang="jp"> <meta charset="UTF-8"> <title>{{page.title}} - {{site.name}}</title> </head> <body> {{content}} </body> </html>
各ページにYAML Front Matterを追加、レイアウト使用に合わせて修正
<!- index.html-> --- layout: default title: ホーム --- <div> some content </div>.....
フッター部を部品化。
% mkdir _includes
footer.htmlを用意
<!- _includes/footer.html-> <div id="footer"> (C) 2007 Katahirado. </div>
default.htmlにフッターの読み込みを追加
<!- _layouts/default.html-> <!DOCTYPE html> <html> <head lang="jp"> <meta charset="UTF-8"> <title>{{page.title}} - {{site.name}}</title> </head> <body> {{content}} {% include footer.html %} </body> </html>
Bitbucketに登録
Gitのプライベートリポジトリを無料で使いたかったのでBitbucketにしました。
Bitbucketにユーザ登録してなかったら登録して、サイト用のプライベートリボジトリを作成します。
ssh公開鍵などよしなに。
後はJekyllに移行したサイトディレクトリでいつものように*1。
% git init
% git add .
% git commit -m 'initial commit'
% git remote add origin git@bitbucket.org:bitbucket_account/bitbucket_repository.git
% git push -u origin master
SourceTreeを使うのもよいかと。
wercker
参考
- http://blog.wercker.com/2013/05/31/simplify-you-jekyll-publishing-process-with-wercker.html
werckerに登録
werckerにいってRegister for freeをクリック
REGISTER WITH GITHUBを選択。
githubアカウントで登録してみました。
スクリーンショット撮り忘れました。
後はアカウント名とメールアドレスを入れてフィニッシュするだけなのでよしなにしてください。
Bitbucketの該当リポジトリを登録
Add an applicationをクリック
use Bitbucketをクリック
該当リポジトリを選択して、Use selected repoをクリック
Bitbucketにpushしたらwerckerでbuild出来る所まで設定、テストする
Add werckerbotをクリック
Bitbucketのリポジトリのアクセス管理画面が開くので、先ほどの説明文通り、werckerbotアカウントを書き込み可能な権限で追加します。
werckerに戻ってNextをクリック
wercker.ymlを作成せよといってますが後で作りますので、Nextをクリック。
ちなみにすでにwercker.ymlをこの時点ですでに作成してリポジトリにアップしている場合、こんな感じになります。
Create applicationをクリック
追加がとりあえず完了。
ローカルでwercker.ymlを作成します。
bundle installしてjekyll buildして_siteを作成するという内容です。
# our build should run within a Ruby box box: wercker/ruby build: steps: # Run a smart version of bundle install # which improves build execution time of # future builds - bundle-install # A custom script step # that actually builds the jekyll site - script: name: generate site code: bundle exec jekyll build --trace
wercker.ymlがbuildされないようにexcludeに追加します。
name: 片平堂 markdown: redcarpet pygments: true exclude: ["vendor", "Gemfile", "Gemfile.lock","wercker.yml"]
Bitbucketにpushしたら、werckerでbuild出来るか実際にpushしてみます。
% git add wercker.yml
% git commit -m 'add wercker.yml'
% git push origin master
成功しました。
werckerのS3へのデプロイ情報を設定
SettingsのDeploy targetsでAdd deploy targetのCustom deployを選択します。
Deployのターゲットネームとレポジトリを設定。
AWS のアクセスキーID,シークレットアクセスキー,bucketのURLを設定していきます。
なお、AWSのシークレットアクセスキーについてはこちらの記事の件にも留意。
Add new variableをクリック
キーID用の変数名と実際の値を設定します。
続いてシークレット
バケットのURL
こんな感じになります。
wercker.ymlにs3デプロイの設定を追加します。
# our build should run within a Ruby box box: wercker/ruby build: steps: # Run a smart version of bundle install # which improves build execution time of # future builds - bundle-install # A custom script step # that actually builds the jekyll site - script: name: generate site code: bundle exec jekyll build --trace deploy: steps: - s3sync: key_id: $KEY key_secret: $SECRET bucket_url: $URL source_dir: _site/
buildしたものをS3にデプロイできる事を確認
% git add wercker.yml
% git commit -m 'Add deployment section'
% git push origin master
Build OK.
S3へのDeploy OK.
感想、その他
自動化するために、自前で用意するものが減って大変便利。
werckerがいつまで無料なのかわかりませんが、無料でここまで出来てありがたい限り。
Middlemanでも同様な感じで設定出来ます。
以上。
*1:実際にはJekyllのレイアウト化の前にローカルのgit使用でバージョン管理していたのですが、話を簡略化
Rails 4.0.4 から 4.1.0 に Update
こんな感じに作業。
↓
https://github.com/katahirado/kkfoodstuff/commit/7aca5b2986e26e88a78d7d58bc041ed97cba5e9e
https://github.com/katahirado/kkfoodstuff/commit/a0c49840145587336b52cb2d56ba71f1dda1e84c
Warning: you should require 'minitest/autorun' instead. Warning: or add 'gem "minitest"' before 'require "minitest/autorun"'
shoulda-matchersを2.5から2.6に
gem "shoulda-matchers", "~> 2.6.0"
参考
nginxとunicornをOS Xで自動起動にする
このエントリーで書いたレシピ食材検索アプリですが、自宅ネットワーク内のMac miniで、nginx+unicornで稼働させています。
permissionや所有者ではまると面倒なので、nginxもunicornもユーザ権限で動かしてます。nginxはport 8080、unicornはport 5000にしてます。妻にはURLのhttp://x.x.x.x:8080/をブックマークしてもらいました。
で、mac miniの再起動時に手動でnginxとunicornを起動させるのが面倒で、自動起動するようにしたので、やり方を記録しておきます。nginxとunicornの設定ファイル等もついでに記録。
#app_path/config/unicorn.rb
worker_processes 2 listen File.expand_path('tmp/sockets/unicorn.sock', ENV['RAILS_ROOT']) stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) preload_app true before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! old_pid = "#{ server.config[:pid] }.oldbin" unless old_pid == server.pid begin Process.kill :QUIT, File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end
#/usr/local/etc/nginx/nginx.conf
user user_account; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream unicorn.rails_app{ server unix:/path/to/kkfoodstuff/tmp/sockets/unicorn.sock fail_timeout=0; } server { listen 8080; server_name localhost; location / { root /path/to/kkfoodstuff/public; index index.html index.htm; try_files $uri/index.html $uri.html $uri @unicorn_rails_app; } location @unicorn_rails_app { if (-f $request_filename) { break; } proxy_redirect off; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Server $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://unicorn.rails_app; } } }
nginxの自動起動は、brewでnginxをインストールすると、やり方を表示してくれるのでその通りにするだけで自動起動できます。
Docroot is: /usr/local/var/www The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that nginx can run without sudo. To have launchd start nginx at login: ln -sfv /usr/local/opt/nginx/*.plist ~/Library/LaunchAgents Then to load nginx now: launchctl load ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist Or, if you don't want/need launchctl, you can just run: nginx
unicornはlocal.unicorn_rails.plistというファイル名でlaunchd.plistを用意しました。
#~Library/LaunchAgents/local.unicorn_rails.plist
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>local.unicorn_rails</string> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>WorkingDirectory</key> <string>/path/to/kkfoodstuff</string> <key>ProgramArguments</key> <array> <string>/Users/user_account/.rbenv/shims/bundle</string> <string>exec</string> <string>unicorn_rails</string> <string>-c</string> <string>/path/to/kkfoodstuff/config/unicorn.rb</string> <string>-E</string> <string>production</string> <string>-p</string> <string>5000</string> </array> </dict> </plist>
launchctrl コマンドでシステムにloadしておく。
$ launchctl load -w ~/Library/LaunchAgents/local.unicorn_rails.plist
参考
RailsでMySQL InnoDBの全文検索機能とMeCabによる形態素解析を使って出来るだけ検索結果をヒットさせる
前のエントリーの通り、妻と自分用にレシピ検索アプリを作りました。
ソースコードはこちら。
出来るだけ検索結果で、食材をいい感じでヒットさせるために色々やったので、記録しておきます。
あと、検索結果を出来るだけヒットさせることに、全文検索機能は実はあんまり関係ないので、タイトルは釣りです。
いい感じでヒットするというのは、例えば白菜、はくさい、ハクサイでそれぞれ検索しても白菜、はくさい、ハクサイで登録されたデータが全てヒットするという状態です。これにプラスして、レシピタイトルのあいまい検索が可能になる、というのがゴールです。
要点としては、表記にゆらぎがあっても検索で出来るだけヒットさせるために、データ登録時にMeCabで形態素解析して読みがなも登録する、検索時もMeCab使う、collate(照合順序)にutf8_unicode_ciを使用する、です。
妻の要望、実際の使い方は以下の様な感じ。
食材メインでの検索。献立的アプローチ。
何日間かの献立を作成するため、今ある食材を使うレシピを探す。
↓
レシピを作るのに足りない使用食材と、料理本の掲載ページ、レシピ名を買い物メモ兼献立メモに書き足す。
↓
メモを持って足りない食材を買いに行く
一方、自分の要望、使い方
レシピ名で検索するのがメイン。索引代わり
今ある食材を確認して、その食材を使うレシピをいくつか思い出す。
↓
あのレシピどの料理本にのってたかな?レシピ名で曖昧検索、料理本の掲載ページを確認
↓
料理本を見て、食材がたりなかったら適当にあるもので作る、アレンジする
妻と私では、検索ではあるのですが、求めているものが違います。
妻の場合は、食材で検索し、レシピで使う食材が出来るだけヒットして欲しい。
それに対して、私は料理名が曖昧検索出来るといい。
使い勝手的に、検索フォームはシンプルに一つだけのほうが混乱がなくわかりやすいと思ったので、フォームは一つだけにして内部的に妻の使い方でも、自分の使い方でも、ヒットするように実装しました。
レシピのデータ構造は、検索時に食材名を厳密にヒットさせるなら食材をマスタにして正規化する、タグ等にして補完で入力をカバーするなどのアプローチも考えられます。
しかし、それでは入力、マスター管理が面倒になってしまいますし、例えば豚肉、豚バラ薄切り、豚コマ切れ肉、など等、表記の揺れがどうしてもでてきてしまいます。
今回は、時間のあるときにお互いに少しずつレシピを手入力していくことにしたので、妻が出来るだけ簡単に入力できるように、タイトル、レシピ本の情報をstringで、その他食材等の情報をtextと全て自由記述で保存し、検索で頑張ることにしました。
以下の様なデータで、実際にそれぞれの要望をどう解決していったのか見ていきます。
料理名:豚肉と白菜のうま煮
料理本・掲載ページ:料理本A 20ページ
食材:
白菜 豚肉 人参 しいたけ
料理名:なんとか鍋
料理本・掲載ページ:料理本A 42ページ
食材:
はくさい ・・・・
料理名:味噌汁
料理本・掲載ページ:料理本B 30ページ
食材:
ハクサイ ・・・・
このデータに対して、妻の使い方ですと、白菜、はくさい、ハクサイ等の検索ワードでも、表記にゆらぎがある食材に検索でいい感じにヒットすればいいわけです。自分の場合はいわゆるLike検索ができればOKです。
全てヒットするために一つずつ解決していきました。
はくさい、ハクサイの検索でひらがな、カタカナ両方にヒットするように
これは、collate(照合順序)をutf8_unicode_ciにすればヒットするようになります。データベース全体がutf8_unicode_ciになるのは嫌だったので、検索用にutf8_unicode_ciの別テーブルを作成、レシピ登録時にレコードを生成するようにしました。
https://github.com/katahirado/kkfoodstuff/blob/master/config/database.yml.sample
https://github.com/katahirado/kkfoodstuff/blob/master/db/migrate/20140318065327_create_search_contents.rb
ちなみにテストのDBは、デフォルトだと、schema.rbから生成されて、migrationのoptions: 'COLLATE=utf8_unicode_ci'が無視されて、ひらがなでカタカナにヒットさせるといった検索のテストが失敗してしまうので、SQLダンプファイルをrake db:structure:dumpで作成の上、config/application.rb で、db/schema.rb ではなく db/structure.sql を吐くよう指定しました。
config.active_record.schema_format = :sql
漢字で登録された食材の白菜に、ひらがなやカタカナで検索してもヒットさせるように
形態素解析を利用して、読みがなも登録してしまうという方法を取りました。
mecabとmecab-ipadicをインストール、RubyとMeCabを繋ぐgemはnattoを利用しました。
豚肉と白菜のうま煮の食材部分"白菜\n豚肉\n人参\nしいたけ"を処理して下記のようになるようにしました。
Analyze.parse(recipe.content) => "白菜 ハクサイ 豚肉 ブタニク 人参 ニンジン しいたけ シイタケ"
これをレシピ名も同様の処理を施して、料理登録時に、検索用のテーブルに格納しました。
これでひらがな、カタカナで検索しても漢字で登録された食材にヒットするようになりました。
ついでにFULLTEXT INDEXも貼ってます。
https://github.com/katahirado/kkfoodstuff/blob/master/db/migrate/20140320120819_add_fulltext_index_to_search_contents.rb
参考
白菜と漢字で検索しても食材がはくさい、ハクサイとなっているレシピにヒットさせる
上記が出来たので簡単です。検索ワードをMeCabでparseして、読みがなと元の検索ワードをORで検索すればヒットします。
ちなみに検索ワードを形態素解析でばらしたりせず、読みがなを付与するだけにしています。
これは、例えば'はくさい'というキーワードが入力された場合に形態素解析してしまうと、"は くさい"などとなり、'は'が助詞と解釈されるといった、意図に反するような場合が出るためです。
投げられるSQLはこんな感じです。
SELECT `search_contents`.* FROM `search_contents` WHERE match(search_contents.title,search_contents.content) against('白菜 ハクサイ' in boolean mode)
白菜のうま煮など、レシピ名のあいまい検索でヒットさせる
データ件数的には2000件弱程度なので、like検索でも問題ないのですが、NgramとBoolean Full-Text Searchesを利用しました。
これもレシピ登録時に、検索用のテーブルにngram(bi-gram)変換したデータを登録しています。
検索ワードもngram(bi-gram)変換しています。
Ngramを使った部分だけのSQLではこんな感じです。
SELECT `search_contents`.* FROM `search_contents` WHERE match(search_contents.title_ngram,search_contents.content_ngram) against ('+(+白菜 +菜の +のう +うま +ま煮)' in boolean mode)
わかち書きでの全文検索も検討したのですが、検索ワードの例で出したように例えば"はくさいの〜"というレシピ名を形態素解析すると、"は くさい の 〜"などと、はが助詞と解釈されたりして、うぐぐとなったので、手っ取り早くNgramにしました。
参考
検索ワードがスペースで区切られていた場合はAND検索
"白菜 豚肉"と食材が入力される場合、"豚肉と うま煮"などのようにレシピ名の絞り込みとして入力される場合があります。
Ngramに対しては、要素ごとに条件を生成してそれをANDでつないで検索します。
食材の場合は検索ワード、読みのORのペアごとに条件を生成し、それをANDでつないで検索します。
投げられるSQLはそれぞれこうなります。
SELECT `search_contents`.* FROM `search_contents` WHERE ((match(search_contents.title,search_contents.content) against('白菜 ハクサイ' in boolean mode) AND match(search_contents.title,search_contents.content) against('豚肉 ブタニク' in boolean mode)) OR match(search_contents.title_ngram,search_contents.content_ngram) against ('+白菜' in boolean mode) AND match(search_contents.title_ngram,search_contents.content_ngram) against ('+豚肉' in boolean mode)) SELECT `search_contents`.* FROM `search_contents` WHERE ((match(search_contents.title,search_contents.content) against('豚肉と ブタニクト' in boolean mode) AND match(search_contents.title,search_contents.content) against('うま煮 ウマニ' in boolean mode)) OR match(search_contents.title_ngram,search_contents.content_ngram) against ('+豚肉 +肉と' in boolean mode) AND match(search_contents.title_ngram,search_contents.content_ngram) against ('+うま +ま煮' in boolean mode))
検索結果は読みがな順
レシピ登録時に料理名の読みがなを検索用テーブルに登録するようにして、検索結果の並び順に使用しました。
検索ワードが一文字の場合に対応する
だいぶいい感じにヒットしてくれるようになりましたが、まだ問題が残っていました。
ngramをbi-gramで処理しているので、一文字の検索ワードが来ると、空でSQLに投げてしまい、エラーになってしまいます。
色々方法はあろうかと思いますが、そもそも全文検索を使う意味があるほどのデータ量でもないので、検索ワードに1文字の単語が来た場合のみ、Ngramではなく、LIKE検索で逃げることにしました。
SELECT `search_contents`.* FROM `search_contents` WHERE (match(search_contents.title,search_contents.content) against('+(豚 ブタ) +(煮 ニ)' in boolean mode) OR (origin_title LIKE '%豚%' AND origin_title LIKE '%煮%' ) OR (origin_content LIKE '%豚%' AND origin_content LIKE '%煮%' )) ORDER BY `search_contents`.`title_yomi` ASC
その他
collate(照合順序)にutf8_unicode_ciを使うと、前述のとおり、ゆらぎを吸収して検索が出来るわけですが、それには相応のデメリットもあります。
例えばウドを検索しようとすると、ゴボ'ウと'ササミのサラダとか、サヤエンド'ウと'豚バラの〜とか、ザワークラ'ウト'などがヒットしたりします。
ただ、これは逆にいうと、例えば粉山椒にサンショウがヒットするということでもあるので、やむを得ない部分かなと思います。
今回色々富豪なアプローチをしていますが、データ件数が2000件弱と少ないですし、一度登録後はめったにデータ更新もされないと思うのでよしとしています。
実際の処理はソースコードを読めばだいたい分かるかと思います。
以上。
妻と自分の為にRailsでレシピ食材検索アプリを作りました
https://github.com/katahirado/kkfoodstuff
レシピの登録と、検索ができるだけのシンプルなWebアプリです。
あまり特別なことはしていないのですが、検索でしっかりヒットさせたかったので、MeCabによる形態素解析を使ってます。
あとMySQL InnoDBの全文検索機能を使っています。
構成はRuby2.1.1,Rails4.0.4,MySQL5.6.17,nginx,unicorn。
家庭内で使っているので、外部で稼働していません。
技術的なことは別エントリーで書きます。
妻には満足頂いているようです。
IT系で自分の仕事を家族にわかってもらうには、家族が欲しているものを作るといいかもしれませんね
第28回 Rails勉強会@東北に参加
https://www.facebook.com/events/378705102216002/
OzakiさんによるRails4.0ネタでした。
はじめにこちらのスライド。
https://speakerdeck.com/alindeman/rails-4-dot-0-whirlwind-tour
その中から特にStrong ParametersとTurbolinksについては、スライド見終わった後、RailsCastsをネタに皆で手を動かしながらワイワイとやりました。
http://railscasts.com/episodes/371-strong-parameters
http://railscasts.com/episodes/390-turbolinks
Turbolinksはこのままリリースされたらギャッという人がたくさん出そうでだいぶアレ。
後、スライド中で出てきたnoneというメソッドやallがActiveRecord::Relationを返す件について↓
#Relation#none # Chainable null object > Post.none #<ActiveRecord::Relation []> # Doesn't hit database > Post.none.to_sql "" > Post.none.to_a [] #Relation#all returns a relation (chainable) # Rails 3 > Post.all.class Array # Rails 4 > Post.all.class ActiveRecord::Relation > Post.all.to_a.class Array
勉強会中に、jQueryや関数型言語っぽくチェーンして書けて、条件分岐を書くケースが減るという事かなとか言いましたが、実際の使用ケースを見ないとわからないという意見がありました。
で、記事に書いてみようかと思ったら、Active Record Query Interface — Ruby on Rails Guidesここに書いてあったのでまるまる引用。
9 Null Relation
The none method returns a chainable relation with no records. Any subsequent conditions chained to the returned relation will continue generating empty relations. This is useful in scenarios where you need a chainable response to a method or a scope that could return zero results.
Post.none # returns an empty Relation and fires no queries. # The visible_posts method below is expected to return a Relation. @posts = current_user.visible_posts.where(name: params[:name]) def visible_posts case role when 'Country Manager' Post.where(country: country) when 'Reviewer' Post.published when 'Bad User' Post.none # => returning [] or nil breaks the caller code in this case end end
Rails4.0では、noneでActiveRecord::Relationを返してくれるので、上記のようにcurrent_user.visible_postsのところで空配列が来てるかの条件分岐を入れずに、jQueryのようにチェーンして書けると。
ScalaのOptionのNoneとかも彷彿とさせますね。
Rails3.2までの場合だと、例えば[]やnilを返してそれをチェックするとか、visible_posts_user_nameといったvisible_postsとwhere(name: params[:name])を一気に処理するメソッドを作成するといったアプローチになるかと。
Rails4.0の場合は、visible_postsメソッドを他でも利用出来て、再利用性を高めて、さらに重複を排除してコードを書けるようになるというのがメリットかなあと。
allがActiveRecord::Relationを返すようになるというのも同様な流れな気が。で、allがActiveRecord::Relation返せば、scopedはいらない子になるのでDEPRECATIONと。
もっともallの場合は、all呼ばないでwhere呼ぶ事が多い気がするので使用ケースは少ないかと。
個人的にはこんな風に理解しました。
参加の皆様お疲れ様でした。
第27回Rails勉強会@東北
https://www.facebook.com/events/295738007193281/
参加してきました。
参加者5名。
今回もRailsCastsを手を動かして皆でやっていった感じです。
やったのは、Deviseなどの認証系ライブラリを使わず認証をスクラッチで作るやつです。
認証↓
http://railscasts.com/episodes/250-authentication-from-scratch-revised
認証に権限をつける↓
http://railscasts.com/episodes/385-authorization-from-scratch-part-1
参加の皆様お疲れ様でした。