VOYAGE GROUPのインターンシップ行ってきたこと

こっちのブログに書きました。
http://katryo.hatenablog.com/entry/2012/09/19/210446
セキュリティやPHPでのコーディング、プロジェクトマネジメントについて書きました。あんまりコード書いてないので非技術ブログに書きましたが、どっちに置こうかけっこう悩みました。

ところで、このはてダ技術ブログをどうするか考え中です。
はてブロがMarkdown記法に対応( http://staff.hatenablog.com/entry/2012/09/19/153219 )したのでこれからはKobito( http://kobitoapp.com/ )で書いて投稿するスタイルにしようと思うのですが、そうするとMarkdownに対応してないはてダのために、頭を切り換えないといけなくなる。

技術ブログをGithubのPagesにOctpressで作ろうかなーと考えてます。

Rails3.2のウェブサービスにOAuthを導入したこと。にせほボタンの解

かとりょーです。
あー。書くのに時間がかかってしまった……。
予告( http://katryo.hatenablog.com/entry/2012/05/05/122513 )通り、にせほボタンの解説です。
にせほボタンはこちら。 http://nisehobutton.heroku.com/
OAuthを導入する練習のために作りました。ついでにtwitter連携の練習にもなりました。これからOAuthやtwitter連携を始める人は、読むと参考になります。

にせほボタンの概要

  • ボタンを押すと、ユーザーのアカウントでツイートする
  • TwitterOAuth認証する
  • Rails3.2.3製
  • herokuにデプロイした

詳しくはここ http://katryo.hatenablog.com/entry/2012/05/05/122513 に書きました。
GitHubはこちら。https://github.com/katryo/oauthtest

参考

Railscastの#241 simple OmniAuthを参考にしました。
http://railscasts.com/episodes/241-simple-omniauth?language=ja&view=asciicast

準備

Twitter Developers
とりあえず、 https://dev.twitter.com/ でアプリ登録します。
Access levelはRead and writeに設定します。
あとで設定は変えられるので、Callback URLも適当なURLを入れておいてください。これを書いておかないと、あとでOAuthが動いてくれません。

OmniAuth認証の仕組み

OmniAuthを使います。

Gemfileに

source 'https://rubygems.org'

gem 'rails', '3.2.3'

# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'

#gem 'omniauth'
gem 'twitter'
gem 'omniauth-twitter'

# Gems used only for assets and not required
# in production environments by default.
group :assets do
  gem 'sass-rails',   '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'
  gem 'twitter-bootstrap-rails'

  # See https://github.com/sstephenson/execjs#readme for more supported runtimes
  # gem 'therubyracer', :platform => :ruby

  gem 'uglifier', '>= 1.0.3'
end

# Heroku
group :production do
    gem 'pg'
end

group :development do
gem 'sqlite3'
end


という風に書き加えます。
これで

$ bundle install --without production

したあと、Gemfile.lockを見てみると、oAuth関連のgemは

    oauth (0.4.6)
    omniauth (1.1.0)
      hashie (~> 1.2)
      rack
    omniauth-oauth (1.0.1)
      oauth
      omniauth (~> 1.0)
    omniauth-twitter (0.0.11)
      multi_json (~> 1.3)
      omniauth-oauth (~> 1.0)


となりました。
種類が多くて内実がよくわからないです。もしかして、いらないもの入っている?

まず/config/initializers/omniauth.rbというファイルを作成し、そこに

Rails.application.config.middleware.use OmniAuth::Builder do
		provider :twitter, 'CONSUMER_KEY', 'CONSUMER_SECRET' 
end

と書きます。'CONSUMER_KEY'と'CONSUMER_SECRET' の''の中には、https://dev.twitter.com/ でのアプリ登録でもらえる'CONSUMER_KEY'と'CONSUMER_SECRET'を入れましょう。

にせほボタン | Twitter Developers

この'CONSUMER_KEY'と'CONSUMER_KEY'を他人に知られると、「そのアプリのふりをする」いたずらをされる恐れがあるので、公開しないようにしてください。

で、このOAuthログインページまでユーザーを誘導するパスが"/auth/twitter"なので、にせほボタンのログインページにはこんなerbを書きました。

<%= link_to 'にせほボタンを始める', "/auth/twitter", :class => 'btn btn-large' %>


実際にブラウザで見るとこんな図です。
にせほボタン-1


ユーザーがこのボタンをクリックするとTwitterhttps://api.twitter.com/oauth/authorize に移動して、認証を許諾するとコールバックされて、にせほボタンのウェブページに戻ってきます。このとき、戻ってくる先のウェブページを設定しておく必要があります。おなじみ https://dev.twitter.com/ で、この画像のようにCallback URLを設定しておいてください。僕の場合は、"http://nisehobutton.heroku.com/contents/buttons/"に設定しました。

にせほボタン | Twitter Developers-1


ユーザーがログインした状態を保つため、sessionsコントローラをまず作ります。

$ rails g controller sessions

userモデルも作ります。モデル内の要素はprovider, uid, name, と指定します。

$ rails g model user provider:string uid:string name:string

さっそくデータベースをマイグレートして、

$ rake db:migrate

"/model/user.rb"にはこう書きます。

class User < ActiveRecord::Base
  attr_accessible :name, :provider, :uid

  def self.create_with_omniauth(auth)
  create! do |user|
    user.provider = auth["provider"]
    user.uid = auth["uid"]
    user.name = auth["info"]["name"]
  end
  end
end

OAuthでもらってきたauth["provider"]やauth["uid"]などのユーザーの情報を、Userテーブルに入れるというメソッドがself.create_with_omniauth(auth)ですね。


sessions_controller.rbには以下のように書きます。

#coding: utf-8
class SessionsController < ApplicationController
  def create
    auth = request.env["omniauth.auth"]
    user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
    session[:user_id] = user.id
   
    Twitter.configure do |config|
      config.oauth_token = auth['credentials']['token']
      config.oauth_token_secret = auth['credentials']['secret']
    end
    redirect_to '/contents/buttons', :notice => "認証しました!"
  end

  def destroy
    session[:user_id] = nil
    redirect_to '/', :notice => "認証を外しました"
  end
end

createでセッション情報を作り、destroyで認証を外します。実際のにせほボタンでは認証を外す機能がない(2012/07/08の段階では)ので、destroyは使わないのですが一応残してあります。

userには、すでにOAuthで認証ずみの場合は認証したユーザーのprovider(さっき登場したauth["provider"]が入っている)と同じくuid(auth["uid"]が入っている)をもとに特定したユーザーが入り、認証していない場合はUser.create_with_omniauth(auth)でUserクラスのcreate_with_omniauthメソッドを使って、新たにユーザーを作成します。



これでようやくOAuthは完成です。OAuthの仕組みを使って認証・Twitter連携ができます。

Twitter連携

せっかく手に入れたOAuthなので、Twitterと連携してツイートできるようにします。
Gemfileに

gem 'twitter'

と書いてbundleしておいたので、すでに"The Twitter Ruby Gem"( http://twitter.rubyforge.org/ )は導入されています。これの機能を使って、ユーザーにツイートさせます。
config/initializers/twitter.rb というファイルを作って、

Twitter.configure do |config|
  config.consumer_key = 'CONSUMER_KEY'
  config.consumer_secret = 'CONSUMER_SECRET'
end

と書きます。'CONSUMER_KEY', 'CONSUMER_SECRET' にはOAuthと同じく、 https://dev.twitter.com/ でもらった文字列を入れます。
これで、OAuth認証したユーザーのツイートを操れます。


app/controllers/contents_controller.rbはこんな風にしました。

#encoding: utf-8
class ContentsController < ApplicationController
  def index
  end

  def buttons

    if current_user

      @user = Twitter.user.screen_name
      @random_number = Time.now.sec % 4
      if params[:button_1]

        if @random_number == 2 
          Twitter.update("にせほー! にせほー! そこにいるの?おしいー! おしいー! 明日があるの! 3分間\ハイ!/リプライを\ハイ!/か・ぞ・え・て・たー\人☆工☆知☆能☆/\( ゜ヮ゜)>\(゜ヮ゜)/ \(゜ヮ゜)/ <(゜ヮ^ )/ #にせほボタン http://nisehobutton.heroku.com/")
        else
          Twitter.update("@nisehorn @nisehorrn @nisehorrrn @nisehorrrrn にせほー #にせほボタン http://nisehobutton.heroku.com/") 
        end
        session[:button_pushed_1] = true

      elsif params[:button_2]
        if @random_number == 3
          Twitter.update("ロックスターはオワコン。時代はレッドブル #にせほボタン http://nisehobutton.heroku.com/")
        else
          Twitter.update("ロックスター・エナジードリンクなう #にせほボタン http://nisehobutton.heroku.com/")
        end

        session[:button_pushed_2] = true
      elsif params[:button_3] 
        Twitter.update("ゆ #にせほボタン http://nisehobutton.heroku.com/") 
        session[:button_pushed_3] = true
      elsif params[:button_4]
        Twitter.update("#zekitterは神 #にせほボタン http://nisehobutton.heroku.com/") 
        session[:button_pushed_4] = true
      elsif params[:button_5]
        Twitter.update("アイエエエ!? ニンジャ!? ニンジャナンデ!? #にせほボタン http://nisehobutton.heroku.com/") 
        session[:button_pushed_5] = true

      elsif params[:button_6]
        Twitter.update("たいぷかのんほー #にせほボタン http://nisehobutton.heroku.com/") 
        session[:button_pushed_6] = true

      end
      @msg = 'あなたのアカウントでツイートできました。たぶん。'
    else
      redirect_to '/'

    end
  end

  def show

  end
end

解説

Twitter.update("ツイートの本文")
メソッドを使って、OAuthでトークンを渡してくれたユーザーにツイートさせる、シンプルな仕組みです。

@user = Twitter.user.screen_name

は、twitterユーザーのスクリーンネーム(たとえばkatryo)を取ってきて、/views/contents/index.html.erbで

ようこそ<%= render :text => @user %>さん。
このページはあなたのために生まれました。

と書くことで、

にせほボタン-2

こんなApple製品の箱を開けたあと風のページにする狙いです。

@random_number = Time.now.sec % 4

は、「1/4の確率をで特別なツイートになる」仕組みのためにやってます。現在時刻を4で割った余りが2や3のとき、別のツイートになります。
うーん、今見ると、ifじゃなくてcaseを使ったほうがrubyらしいコードになった気がする。直すのめんどいので次回に生かすことにしますー。

デプロイ

herokuにデプロイしました。herokuはPostgreSQLしか使えないので、Gemfileにdevelopmentとproductionを分けて、このように書いておいて、

group :production do
    gem 'pg'
end

group :development do
gem 'sqlite3'
end

デプロイ前に

$ bundle install --without development

とします。
デプロイしてから、DBのマイグレーションをheroku runコマンドでします。

$ heroku run rake db:migrate

herokuへのデプロイでハマるのは、assetsとDB周りが大半です。特にRails3.1から導入されたasset pipelineは比較的新しい機能のため、本によっては対応してないことがあるので古めの本を読んでる人は注意が必要です。
asset pipelineは要するにCSSや画像、Javascriptをこれまでのような/publicでなく/app/assetsに入れておき、デプロイ時に/assetsに圧縮して入れる仕組みです。ウェブページのレンダリング時のリクエスト回数を減らせるので高速化できるそうです。
Railscastにasset pipelineを紹介した記事があるので、見ておくといいです。 http://railscasts.com/episodes/279-understanding-the-asset-pipeline?language=ja&view=asciicast
こっちはRails公式の解説 http://guides.rubyonrails.org/asset_pipeline.html

かつてherokuはasset pipelineに標準対応していなかったのでアプリ作成時に

heroku create アプリの名前 --stack cedar

と、stack cedar(cedarはただのコードネーム。1つ前のバージョンはbambooだった)を指定しないといけなかったのですが、2012年6月でstack cedarが標準になったので、今は単純に

heroku create アプリの名前

とすれば、勝手にstack cedarのアプリを作ってくれます。
herokuの公式マニュアルに色々書いてあるので読みましょう。 https://devcenter.heroku.com/articles/cedar/
herokuの設定やデプロイ順序は頻繁に変わるので、日本語で書かれたブログを探すよりもheroku公式マニュアルを読んだほうが速いことが多いです。

デプロイしてもアプリが動かないときは、

$ heroku logs

でログを見て、プリコンパイルしたりDB設定を変えながら対応すると時間を無駄にしなくて済むと思います。
ひがしのてらこや。公式サイト( http://higashinoterakoya.herokuapp.com/ )のように、DBの内容を表示するタイプのアプリでは、DB内にレコードが1つもないとsomething went wrongが出ます。なので、とりあえずDBに何か入れましょう。

heroku run rails console

とすれば、heroku上でRuby対話環境を起動できます。
もしUserテーブルにレコードを追加したいなら、

User.create(name:'katryo', password:'secret')

とすれば、ユーザー情報が入ります。
ユーザーが入ったことを確認したいなら、このあと

User.count

とすれば、ユーザー数を表示してくれます。

ではでは!

ウェブページ「ひがしのてらこや。」にログイン機

 おひさしぶりの更新です。
 こっちのブログは技術ブログにしちゃおうと思います。

ひがしのてらこや。とは

 このウェブサイトです。http://higashinoterakoya.herokuapp.com/
 僕が友達といっしょに作った、ゲーム制作サークルです。

 今までは、更新のたびにHTMLを書き直して、Windows7にデフォルトで入ってるFTP接続機能でfc2のウェブサイトサービスにアップロードしてたのですが、編集も転送もけっこうめんどくさくて、更新ペースはかなり遅かったです。月に1回、あるかどうか、というくらいでした。

 そこで、リニューアルを機会に更新を楽にしようと思って、ブラウザ上で記事を編集できるシステムを作りました。ふつうのユーザーにとっては関係ないけれど、管理者(僕と友人)にとっては便利になりました。

 コードはGitHubに上げてあります。こちら。 https://github.com/katryo/higashinoterakoya

実現したこと

  • IDをパスワードでログイン・ログアウトできる
  • ログインすると、記事を編集できる
  • 記事はデータベース(PostgreSQL)で管理
  • 「過去の記事」ページで、これまでの記事を最新10件まで一覧にして表示できる
  • 記事は新しい順に自動的に並べられる
  • 記事にはすべて投稿日時が併記される
  • 最新の記事は、トップページに自動的に表示される

……ということを実現しました。

どういう風に作ったか

 RailsによるアジャイルWebアプリケーション開発 第4版

 の第14章「タスクI:ログイン」通りに作りました。

 ……。
 ほとんどこの本の言うとおりそのままです。この本を読んで、書いてある通りに写経して作るとよいと思います。
 でもまあ、工夫したところがないわけでもなくて、

工夫したところ

 RailsによるアジャイルWebアプリケーション開発 第4版を手元に、ここからは読んでほしいです。

投稿時刻通りに記事が並ぶようにした

 記事を作成するページは、RailsによるアジャイルWebアプリケーション開発 第4版でいうところのProductページと同じ作り方をしています。63ページに書いてある、

Rails generate scaffold Product title:string description:text image_url:string price:decimal

のかわりに

Rails generate scaffold Article title:string description:text

として、Articleコントローラとビューをscaffoldします。image_urlやpriceはいらないです。
このあとは本通りにArticleを作ってくのですが、記事の並ぶ順番を日時通りにソートするために、ちょっと手を加えます。

Articleコントローラのindexメソッドが、http://higashinoterakoya.herokuapp.com/articlesページを開いたときの動向を指示しているのですけど、ここで、

  def index
    @articles = Article.order("created_at DESC")

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @articles }
    end
  end

 と、("created_at DESC")を書き加えて、投稿日時が新しい順番に並べています。
 /articlesページの編集できないバージョンであり、非管理者ユーザーが見るページである/archivesのコントローラでも、同様の処理をして、投稿日時で並べています。
 created_atというヘルパーメソッドは、Rails3に標準で入ってるので新たに設定する必要はないです。

 @articlesには記事全体が順序正しく並び、@articleには1つ1つの記事が入ります。1文字違いで別のものなので気をつけましょう。

投稿日時を表示させた
  <h4>
      投稿日時:
      <%= article.created_at %>
      </h4>


 とapp/view/articles/index.html.erbとapp/view/archives/index.html.erbに書き入れただけです。ただ、初期設定のままだと世界標準時になってしまうので、config/application.rbに

config.time_zone = 'Tokyo'

 と書き込みます。これで日本時間で表示される!

markdown記法を導入

 RailsによるアジャイルWebアプリケーション開発 第4版のProductページのように作り終えても、トップページ(本ではstore#indexにrootを通しているのでapp/views/store/index.html.erb)でdescriptionを表示するタグはsanitizeされているので、記事を書くときにHTMLのタグを書いたり、改行したりしても無視されます。
 これだと不便なので、書いた記事をmarkdown記法で解釈してくれるように機能を加えました。


 使ったのは、redcarpetです。
 Railscastにあるチュートリアル通りに導入しました。これです。 http://railscasts.com/episodes/272-markdown-with-redcarpet?language=ja&view=asciicast
 このRailscast通りにすれば導入はできるので、ここでは詳しくは書きません。

 ただし、ここで注意すべきところがあります。
 redcarpet、ver2以降だと動きません。このRailscastチュートリアルはver1系列のredcarpetが対象のようで、うっかりGemfileにgem 'redcarpet'とだけ書くと、動きません。
 なので、今回はredcarpetのバージョンを1.17.2に指定して、Gemfilesには

gem 'redcarpet', '1.17.2'

と書きましょう。


 コードはGitHubに上げてあります。こちら。 https://github.com/katryo/higashinoterakoya

次回予告

 生まれて初めて作ったウェブサービス「にせほボタン( http://nisehobutton.heroku.com/ )」の作り方メモを次回は書きます。
 見直してみたら、いらないコードとか試しに書いてみたメソッドとかが多かったので、リファクタリングし直してから投稿します。

Rails3の学習、環境を整えるの巻

はじめる! RailsからRailsによるアジャイルWEBアプリケーションに移る

結局、達人研究会の「はじめる! Rails3(1)」をiPadで開いて読みながら、たまにPCでも開いてお手本コードをコピペしながら最後まで読み進めました。本に載ってる演習問題も最初は真面目に解いていったのだけど途中からなぜかSyntax Errorが消せなくなったので諦めて本文の書き写しだけでも最後までやり終えることにしました。
最後まで読み終える直前に「RailsによるアジャイルWEBアプリケーション開発第4版」というRails開発では有名な本を京大情報学図書館で見つけたので、借りて続けて読むことにしました。2月16日のことです。
この本はユーモアがいい感じで、文体も読みやすいです。good.

開発環境を整えるのに四苦八苦すること

どうせウェブサービスを作るのだし、そろそろgitとかherokuを使ってみようかなーと思ったので、手を出してみることにしました。
で、いろいろ調べながらGit Bashってなにこれ必要なのー? とか思いながらgit設定をしていたのですが、何度git push origin masterとやってもPermission denied (publickey).と言われて繋がりませんでした。
そこで、この記事ローカル(Windows, cygwin)からGithubのリポジトリにpushするメモ - TMD45LOG!!!を参考にして、cygwinを入れてみることにしました。以前cygswinを使ってみると快適だというはてぶ記事を見たことがあったのでちょうどいい機会だと思ったのです。
いますぐコマンドプロンプトを捨てて、Cygwinを使うべき10+の理由 - それマグで!

で、cygwinを導入したんですが、えーと、結論を言うと、うまくいきませんでした。「Railsによるアジャイル〜」のお手本プロジェクトをrails sしても通らず(たぶん文字コードのせい)、もうcygwinは嫌になってしまいました。ディレクトリの場所がわかりにくいし変な場所に余計なものをインストールした気がするので触る気がなくなってます。

VMを導入すること

ということで思い切ってVMを使うことにしました。
ここからはまた次回に書きます。

Rails3の学習、環境を整えるの巻

はじめる! RailsからRailsによるアジャイルWEBアプリケーションに移る

結局、達人研究会の「はじめる! Rails3(1)」をiPadで開いて読みながら、たまに
PCでも開いてお手本コードをコピペしながら最後まで読み進めました。本に載ってる演習問題も最初は真面目に解いていったのだけど途中からなぜかSyntax Errorが消せなくなったので諦めて本文の書き写しだけでも最後までやり終えることにしました。
最後まで読み終える直前に「RailsによるアジャイルWEBアプリケーション開発第4版」というRails開発では有名な本を京大情報学図書館で見つけたので、借りて続けて読むことにしました。2月16日のことです。
この本はユーモアがいい感じで、文体も読みやすいです。good.

開発環境を整えるのに四苦八苦すること

どうせウェブサービスを作るのだし、そろそろgitとかherokuを使ってみようかなーと思ったので、手を出してみることにしました。
で、いろいろ調べながらGit Bashってなにこれ必要なのー? とか思いながらgit設定をしていたのですが、何度git push origin masterとやってもPermission denied (publickey).と言われて繋がりませんでした。
そこで、この記事http://d.hatena.ne.jp/tmd45/20110203/1296744114を参考にして、cygwinを入れてみることにしました。以前cygswinを使ってみると快適だというはてぶ記事を見たことがあったのでちょうどいい機会だと思ったのです。
http://d.hatena.ne.jp/takuya_1st/20111121/1321865738

で、cygwinを導入したんですが、えーと、結論を言うと、うまくいきませんでした。「Railsによるアジャイル〜」のお手本プロジェクトをrails sしても通らず(たぶん文字コードのせい)、もうcygwinは嫌になってしまいました。ディレクトリの場所がわかりにくいし変な場所に余計なものをインストールした気がするので触る気がなくなってます。

VMを導入すること

ということで思い切ってVMを使うことにしました。
ここからはまた次回に書きます。

Ruby on Rails3学習開始

経緯

2012/02/11くらいかたRails3の勉強始めました。
最初はまずRubyからやろうかなーと思ってたのですけど具体的に作るものを決めてから、そのために言語を学んでくというアプローチのほうが速そうなので、まあ、Railsに手を出したわけです。
バイト先のRailsに詳しい人に聞いたところ、Railsの進化は速くてドキュメントがすぐ時代遅れになってしまうから、本よりウェブを漁ったほうがよいとのアドバイスをもらいました。

本を手に入れるまで

Google先生に訊ねながら調べたところ、現在のRailsはver3.2だと知りました。ver2とは全然違って、古い資料は参考にならない。良質のチュートリアルはたいていが英語で、プログラミング初心者が手に取るにはちょっと難敵だなと思わざるを得ませんでした。
結局、達人研究会の「はじめる! Rails3(1)」http://tatsu-zine.com/books/rails3電子書籍版を買いました。1000円です。

今日のエントリはここまでにします。

アルゴリズムの勉強開始

アルゴリスムイントロダクション改訂2版 第1巻数学的基礎とデータ構造 を読み始めました。
練習のため、出てきた擬似コードRubyで動くように書きかえました。
まずは第2章。16ページの挿入ソートです。
a[n] の中に具体的な非負整数値を入れてソートしてます。

a = [9, 2, 4, 6, 3, 5, 8, 7, 1, 0]
for j in 1..9
key = a[j]
i = j-1
while ((a[i] > key) && (i >= 0))
a[i+1] = a[i]
i = i-1
end
a[i + 1] = key
end
puts a

配列の中は0から始まるので、擬似コードとは2行目の数を1だけ変えてあります。これのおかげで20分くらい悩みました。comparison of Fixnum with nil failed (AugumentError)というのが出てきて、「nilと比較してるからダメだよー」と言われてるのはわかってたのですがどこにnilがあるのかと。結局a[10]が存在してないからダメだったのです。
あとそういえば、インデント使ってなかった。こんどから使います。