Redmine 1.2をMacにインストールしてみた
引っ越し関連のTODOを管理しようと思い、以前インストールしたまま埃をかぶっていたRedmineを引っ張りだしてみたところ、ローカル環境のRubyのバージョンが1.9になっていたりRailsのバージョンが3になっていたりしてまったく動かなくなっていたので、RVMを使ってRedmine用のgemsetを新しく作ってみました。そのときのメモです。
構築した環境
今回は下記のような環境を構築してみました。
Redmine | Redmine 1.2 |
OS | Mac OS X 10.6 |
データベース | SQLite |
Webサーバ | Apache |
Ruby | 1.8.7 |
Rails | 2.3.11 |
データベースは、設定が面倒くさいのでMySQLではなくSQLiteにしました。
Webサーバは、せっかくMacにはデフォルトでApacheが入っているので、MongrelではなくApacheを使うことにしました。
Redmine用のgemsetの作成
RVMを使ってRedmine用のgemsetを作成します。
$ rvm use ruby-1.8.7-p352 $ rvm gemset create redmine-1.2 $ rvm gemset use redmine-1.2
gemパッケージのインストール
Redmineのインストールに必要なgemパッケージをインストールします。
Rails 2.3.11のインストール
Redmine 1.2はRails 2.3.11でしか動かないので、Rails 2.3.11をインストールします。
$ gem install rails -v=2.3.11
gemsetにデフォルトで入っていたgemのバーションが1.8.10でしたが、Rails 2.3.11はgem 1.8未満でしか動かないらしいので*1、gemをダウングレードします。
利用可能なバーションを調べてみます。
$ gem search -rda ruby rubygems-update (1.8.11, 1.8.10, 1.8.9, 1.8.8, 1.8.7, 1.8.6, 1.8.5, 1.8.4, 1.8.3, 1.8.2, 1.8.1, 1.8.0, 1.7.2, 1.7.1, 1.7.0, 1.6.2, 1.6.1, 1.6.0, 1.5.3, 1.5.2, 1.5.0, 1.4.2, 1.4.1, 1.4.0, 1.3.7, 1.3.6, 1.3.5, 1.3.4, 1.3.3, 1.3.2, 1.3.1, 1.3.0, 1.2.0, 1.1.1, 1.1.0, 1.0.1, 1.0.0, 0.9.5, 0.9.4, 0.9.3, 0.9.2, 0.9.1, 0.9.0, 0.8.11, 0.8.10, 0.8.8, 0.8.6, 0.8.5, 0.8.4, 0.8.3) Authors: Jim Weirich, Chad Fowler, Eric Hodel Rubyforge: http://rubyforge.org/projects/rubygems Homepage: http://rubygems.org RubyGems is a package management framework for Ruby
1.7系では1.7.2が最新のようなので、これをインストールします。
$ gem install rubygems-update -v=1.7.2 $ update_rubygems $ gem -v 1.7.2
Rack 1.1.1のインストール
Rack 1.1.1をインストールします。
Rails 2.3.11インストール時にいっしょにインストールされた1.1.2はアンインストールします。
$ gem install rack -v=1.1.1 $ gem uninstall rack -v=1.1.2
Rake 0.8.7のインストール
Rake 0.8.7をインストールします。
$ gem install rake -v=0.8.7
いつの間にか入っていたRake 0.9.2をアンインストールしようとしたところ、下記のエラーが発生しました。
$ gem uninstall rake -v=0.9.2 ERROR: While executing gem ... (Gem::InstallError) cannot uninstall, check `gem list -d rake`
いわれたとおりをgem list -d rakeを実行してみます。
$ gem list -d rake *** LOCAL GEMS *** rake (0.9.2, 0.8.7) Author: Jim Weirich Rubyforge: http://rubyforge.org/projects/rake Homepage: http://rake.rubyforge.org Installed at (0.9.2): /Users/<アカウント名>/.rvm/gems/ruby-1.8.7-p352@global (0.8.7): /Users/<アカウント名>/.rvm/gems/ruby-1.8.7-p352@redmine-1.2.1 Ruby based make-like utility.
どうやらRVMのglobalにインストールされているようです。
というわけで、gemsetをglobalに変更してから再度試してみたところ、無事アンインストール成功しました。
$ rvm gemset use global $ gem list $ gem uninstall rake
gemsetをもとに戻しておきます。
$ rvm gemset use redmine-1.2.1
Passengerのインストール
Passengerをインストールします。
$ gem install passenger
最終的なgemsetは下記のようになりました。
$ gem list *** LOCAL GEMS *** actionmailer (2.3.11) actionpack (2.3.11) activerecord (2.3.11) activeresource (2.3.11) activesupport (2.3.11) i18n (0.4.2) rack (1.1.1) rails (2.3.11) rake (0.8.7) rubygems-update (1.7.2) sqlite3 (1.3.4)
Redmineのインストール
今回はSVNのソースからインストールしました。
$ svn export http://redmine.rubyforge.org/svn/branches/1.2-stable/
Apache上で動作させるので、エクスポートしたソースを~/Sites配下に移動しておきます。
$ mv 1.2-stable ~/Sites/redmine
データベースの設定を行います。
$ cd ~/Sites/redmine/ $ cp config/database.yml.example config/database.yml $ cat config/database.yml production: adapter: sqlite3 database: db/production.sqlite3
セッションデータ暗号化用鍵の生成とテーブル作成を行います。
$ rake generate_session_store $ rake db:migrate RAILS_ENV=production
PassengerのApache用モジュールのインストール
インストーラを実行してPassengerのApache用モジュールをインストールします。
$ passenger-install-apache2-module
インストールが完了する下記のように表示されます。
あとでApacheに設定するのでコピペしておきます。
LoadModule passenger_module /Users/<アカウント名>/.rvm/gems/ruby-1.8.7-p352@redmine-1.2/gems/passenger-3.0.9/ext/apache2/mod_passenger.so PassengerRoot /Users/<アカウント名>/.rvm/gems/ruby-1.8.7-p352@redmine-1.2/gems/passenger-3.0.9 PassengerRuby /Users/<アカウント名>/.rvm/wrappers/ruby-1.8.7-p352@redmine-1.2/ruby
Apacheの設定
Passengerの設定の追加
/etc/apache2/other/passenger.confを作成し、下記設定を追加します。
設定内容は公式サイトを参考にしました。
# Passengerの基本設定。 # passenger-install-apache2-module --snippet を実行して表示される設定を使用。 # 環境によって設定値が異なりますので以下の3行はそのまま転記しないでください。 # LoadModule passenger_module /Users/<アカウント名>/.rvm/gems/ruby-1.8.7-p352@redmine-1.2/gems/passenger-3.0.9/ext/apache2/mod_passenger.so PassengerRoot /Users/<アカウント名>/.rvm/gems/ruby-1.8.7-p352@redmine-1.2/gems/passenger-3.0.9 PassengerRuby /Users/<アカウント名>/.rvm/wrappers/ruby-1.8.7-p352@redmine-1.2/ruby # Passengerが追加するHTTPヘッダを削除するための設定。 # Header always unset "X-Powered-By" Header always unset "X-Rack-Cache" Header always unset "X-Content-Digest" Header always unset "X-Runtime" # 必要に応じてPassengerのチューニングのための設定を追加。 # PassengerMaxPoolSize 20 PassengerMaxInstancesPerApp 4 PassengerPoolIdleTime 3600 PassengerUseGlobalQueue on PassengerHighPerformance on PassengerStatThrottleRate 10 RailsSpawnMethod smart RailsAppSpawnerIdleTime 86400 RailsFrameworkSpawnerIdleTime 0
バーチャルホストの設定の追加
/etc/apache2/httpd.confを下記のように編集し、バーチャルホストの設定を有効にします。
$ diff httpd.conf httpd.conf.org 465c465 < Include /private/etc/apache2/extra/httpd-vhosts.conf --- > #Include /private/etc/apache2/extra/httpd-vhosts.conf
/etc/apache2/extra/httpd-vhosts.confの最後に下記設定を追記します。
<VirtualHost *:80> DocumentRoot /Users/<アカウント名>/Sites/redmine/public ServerName myredmine.example.com </VirtualHost>
/etc/hostsにMacのIPアドレス(僕の場合は192.168.1.4)を追記します。
192.168.1.4 myredmine.example.com
Apacheの再起動後、ブラウザでhttp://myredmine.example.comにアクセスするとRedmineのトップ画面が表示されました。満足。
あれ、引っ越しのTODOが1つも終わってない…。
Node.js + Socket.IOでチャットアプリを作ってみた
Node.js + Socket.IOを使って簡単なチャットアプリを作ってみました。
ベースは『パーフェクトJavaScript (PERFECT SERIES 4)』の「17章 WebSocket」に出てきたサンプルコードです。
今回はこのサンプルコードをSocket.IOを使って書き直してみました。
ソースコードはGitHubにアップしています。
サーバサイド
server.js
var io = require('socket.io').listen(8080); io.sockets.on('connection', function(socket) { console.log('onconnection:', socket); // クライアントからのイベント'all'を受信する socket.on('all', function(data) { // イベント名'msg'で受信メッセージを // 自分を含む全クライアントにブロードキャストする io.sockets.emit('msg', data); }); // クライアントからのイベント'others'を受信する socket.on('others', function(data) { // イベント名'msg'で受信メッセージを // 自分以外の全クライアントにブロードキャストする socket.broadcast.emit('msg', data); }); socket.on('disconnect', function() { console.log('disconn'); }); });
サーバサイドの実装です。
イベント名でメッセージの返信先を切り替えています。
イベント名が'all'であればメッセージ送信者を含む全クライアントにブロードキャスト、'others'であればメッセージ送信者以外の全クライアントにブロードキャストしています。
クライアントサイド
client.js
var socket = io.connect('http://localhost:8080'); var timer; $(document).ready(function() { $('#text').keydown(function(event) { // エンターキーで発言をサーバに送信する if (event.keyCode === 13) { // イベント名'all'でメッセージをサーバに送信する socket.emit('all', { action: 'post', user: $('#user').val(), css: $('#css').val(), text: $('#text').val() }); // タイピング中というステータスをサーバに送信する } else { // イベント名'others'でメッセージをサーバに送信する socket.emit('others', { action: 'typing', user: $('#user').val() }); } }); // サーバからのイベント'msg'を受信する socket.on('msg', function(data) { switch (data.action) { case 'post': // 発言の描画 $('<li></li>').text(data.user + ': ' + data.text) .attr('style', data.css) .appendTo('body'); break; case 'typing': // タイピング中ステータスの描画 $('#typing').text(data.user + 'さんがタイピング中です...'); clearTimeout(timer); timer = setTimeout(function() { $('#typing').empty(); }, 3000); break; } }); });
クライアントサイド(JavaScript)の実装です。
発言はイベント名'all'で送信しています。
タイピング中ステータスは相手にだけ表示させたいので、イベント名'others'で送信しています。
chat.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>simple chat client powered by socket.io</title> <script src="http://localhost:8080/socket.io/socket.io.js"></script> <script src="jquery-1.6.4.min.js"></script> <script src="client.js"></script> </head> <body> <input id="user"> <input id="css"> <input id="text"> <div id="typing"></div> </body> </html>
クライアントサイド(HTML)の実装です。
シンプルなチャット画面を表示します。
実行
nodeコマンドでサーバを起動させます。
$ node server.js
サーバを起動したら、複数のブラウザでchat.htmlを開きます。
チャット画面から発言を送信すると、Socket.IOサーバ経由で発言がブロードキャストされ、すべてのブラウザのチャット画面に発言が表示されます。
まとめ
Node.js + Socket.IOを使ってみた感想です。
- サーバサイドでは考慮すべき点がほとんどなかった(クライアントから受け取るイベント名とメッセージの返信先の指定くらい)
- クライアントサイドでJSONの組み立て方とロジックを変更するだけで、いろいろな機能追加が簡単に実現できた
パーフェクトJavaScript (PERFECT SERIES 4)
- 作者: 井上誠一郎,土江拓郎,浜辺将太
- 出版社/メーカー: 技術評論社
- 発売日: 2011/09/23
- メディア: 大型本
- 購入: 24人 クリック: 588回
- この商品を含むブログ (12件) を見る
Google+ APIを試してみた(OAuth 2.0編)
前回の続きです。
今回は、OAuth 2.0のアクセストークンを使って公開ストリームを取得するアプリをRailsで作ってみました。
ソースコードはGitHubにアップしています。
OAuth 2.0の仕様はこちら。
OAuth - Google+ Platform — Google Developers
OAuth 2.0を利用するには、事前にGoogle APIコンソールにてクライアントID、クライアントシークレット、リダイレクトURIなどを登録しておく必要があります(この辺りを参考)。
登録するリダイレクトURIはlocalhostでもOKです。
ただし、ここで登録したURLと実際にアプリでリダイレクトさせるURIが一致しないと、認証APIを実行したときにエラーになるので注意が必要です。
今回はリダイレクトURIを下記のように登録してみました。
localhost:3000/activities/oauth2callback
ビュー
app/views/activities/index.html.erb
<h1>Listing activities</h1> <table> <tr> <th>Title</th> <th>Published</th> <th>URL</th> </tr> <% if @activities.present? && @activities["items"].present? %> <% @activities["items"].each do |activity| %> <tr> <td><%= activity["title"] %></td> <td><%= activity["published"] %></td> <td><%= activity["url"] %></td> </tr> <% end %> <% end %> </table>
なんの変哲もないビューです。
コントローラ
app/controllers/activities_controller.rb
def index # アクセストークン未取得または有効期限切れの場合はOAuth 2.0で認証する redirect_to "https://accounts.google.com/o/oauth2/auth?"\ "client_id=#{CLIENT_ID}&"\ "redirect_uri=#{REDIRECT_URI}&"\ "scope=https://www.googleapis.com/auth/plus.me&"\ "response_type=code" and return if cookies[:access_token].blank? # 公開ストリームを取得する uri = URI.parse("https://www.googleapis.com/plus/v1/people/me/activities/public?"\ "access_token=#{cookies[:access_token]}") https = Net::HTTP.new(uri.host, 443) https.use_ssl = true https.verify_mode = OpenSSL::SSL::VERIFY_NONE response = https.start do |https| request = Net::HTTP::Get.new(uri.path << '?' << uri.query) https.request(request) end @activities = ActiveSupport::JSON.decode(response.body) end
認証済みの場合は公開ストリーム取得APIを実行しますが、未認証の場合はアクセス許可画面にリダイレクトさせます(認証情報をクッキーに保存しています)。
CLIENT_ID、REDIRECT_URIは、事前登録したクライアントIDとリダイレクトURIです。
注意点は、サーバ側の実装なのでresponse_typeをcodeにすること。
リダイレクトURIのアクションの実装です。
def oauth2callback # アクセスを許可しなかった場合はトップ画面にリダイレクトする redirect_to url_for(:controller => "tops", :action => "index") and return if params["code"].nil? # 認可コードをアクセストークンおよびリフレッシュトークンと交換する uri = URI.parse("https://accounts.google.com/o/oauth2/token") https = Net::HTTP.new(uri.host, 443) https.use_ssl = true https.verify_mode = OpenSSL::SSL::VERIFY_NONE response = https.start do |https| request = Net::HTTP::Post.new(uri.path) request.set_form_data({ :code => params[:code], :client_id => CLIENT_ID, :client_secret => CLIENT_SECRET, :redirect_uri => REDIRECT_URI, :grant_type => "authorization_code" }, "&") https.request(request) end response_hash = ActiveSupport::JSON.decode(response.body) cookies[:access_token] = { :value => response_hash["access_token"], :expires => response_hash["expires_in"].seconds.from_now } @activity = Activity.new(:access_token => response_hash["access_token"]) @activity.save redirect_to url_for(:activities) end
アクセス許可画面にてアクセスを許可した場合は認可コードがリクエストパラメータとして渡されるので、これをアクセストークンおよびリフレッシュトークンと交換します。
取得したアクセストークンはクッキーなりDBなりに保存しておきましょう。
動作確認
http://localhost:3000/activitiesにアクセスしてみます。
すると、まだ認証していないのでアクセス許可画面にリダイレクトされます(Twitterなどでもおなじみの画面です)。
ここで「アクセスを許可」を選択すると、まずhttp://localhost:3000/activities/oauth2callbackにリダイレクトされて認証したあと、http://localhost:3000/activitiesにリダイレクトされます。
今度は認証済みなので、公開ストリームを取得できるはず。
おー、できました。
Google+を使っていないことがバレバレの公開ストリームですが、気にしないでください。
なお、アクセストークンの有効期限は1時間なので、1時間以内であれば再認証は不要です。
Google+ APIを試してみた
Google+には無関心の態を装いながらも、実は内心興味津々で、「誰か招待してくれないかなー」などと思いながら毎日を過ごしていましたが、最近になってようやく招待してもらうことができ、Google+を使いはじめることができました。
そんなわけで、早速最近公開されたばかりのGoogle+ APIを試してみました。
Google+ APIの認証方式には、APIキーによる認証方式とOAuth 2.0による認証方式の2種類があります。
今回は、OAuth 2.0について調べるのが面倒くさいのでAPIキーによる認証方式を試してみました。まだAPIキーを持っていない人は、この辺りを参考にしてAPIキーを取得してください。
言語はRubyです。
専用のライブラリもあるみたいですが、使い方がわからないので華麗にスルー(笑)。
どうせHTTPSでリクエストを送るだけなので、net/httpsを使って実装しました。
下記がソースコードです。
get_profile.rb
#!/usr/bin/ruby require 'net/https' USER_ID = '102346903570321430420' API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # 取得したAPIキー uri = URI.parse("https://www.googleapis.com/plus/v1/people/#{USER_ID}?key=#{API_KEY}") https = Net::HTTP.new(uri.host, 443) https.use_ssl = true https.verify_mode = OpenSSL::SSL::VERIFY_NONE response = https.start do |https| request = Net::HTTP::Get.new(uri.path << '?' << uri.query) https.request(request) end puts response.body
USER_IDで指定したユーザのプロフィールを取得します。
実行してみます。
$ ruby get_profile.rb { "kind": "plus#person", "id": "102346903570321430420", "displayName": "Yuta NAGAMIYA", "gender": "male", "aboutMe": "Ruby好きのプログラマです。", "url": "https://plus.google.com/102346903570321430420", "image": { "url": "https://lh3.googleusercontent.com/-GijUqtWTz08/AAAAAAAAAAI/AAAAAAAAACY/A-cPZmjZRUQ/photo.jpg" }, "urls": [ { "value": "http://twitter.com/ngmy" }, { "value": "https://plus.google.com/102346903570321430420", "type": "profile" }, { "value": "https://www.googleapis.com/plus/v1/people/102346903570321430420", "type": "json" } ], "placesLived": [ { "value": "群馬県前橋市" }, { "value": "神奈川県横浜市", "primary": true } ] }
プロフィールを取得できました。簡単!
次回はOAuth 2.0を使った方法を試してみたいと思います。