tag:blogger.com,1999:blog-2988187052395095902024-02-08T15:34:24.457+09:00Ruby 開発備忘録Unknownnoreply@blogger.comBlogger60125tag:blogger.com,1999:blog-298818705239509590.post-68238165044374332032014-04-11T01:54:00.001+09:002014-04-11T12:14:15.957+09:00SBI証券から無料でリアルタイム株価を取得するライブラリHFT(もどき)が個人でもできないかと方法を探していたのですが、個人にストリーミングの株価データを配信してくれるところが見つからず。<br />
しかたがないので、SBI証券のリアルタイム更新を利用して、ほぼリアルタイム(3秒ディレイくらい)で株価を取得できるライブラリを作りました。<br />
SBI証券のアカウントは必須です。<br />
<br />
まずはインストール
<br />
<br />
<pre class="ruby" name="code">gem install Sbirsp
</pre>
使い方のサンプル
<br />
<pre class="ruby" name="code">require "sbirsp"
Sbirsp.configure do |config|
config.username = "user_id"
config.password = "password"
end
@client = Sbirsp::Client.new
@client.code = 9984
@client.show_stock_price
loop do
if @old_price != @client.price
puts "#{@client.price}"
@old_price = @client.price
end
end
</pre>
複数クライアントを同じプロセス内で起動した時の動作が怪しいので、なんとか調整したい。<br />
<br />
githubにソースコードをアップしています。<br />
<a href="https://github.com/face-do/sbirsp">https://github.com/face-do/sbirsp</a>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-58289624706955580652013-03-15T21:38:00.004+09:002013-03-15T21:44:20.834+09:00rubyからr言語を使って、キャンペーン前後で売上に変化があったか判断する同一期間ではないので、対応のない場合のt検定を行います。<br />
rubyからR言語を使うには、rsrubyというライブラリを使う。
<br />
<br />
まずはRのインストール<br />
$ brew install R
<br />
<br />
で、rのpathを設定します。<br />
$ export R_HOME=/Library/Frameworks/R.framework/Resources
<br />
<br />
次にrsrubyのインストール<br />
$ gem install rsruby -- --with-R-include=/Library/Frameworks/R.framework/Headers --with-R-lib=/Library/Frameworks/R.framework/Libraries
<br />
<br />
で、準備は完了。
<br />
<br />
今回はこんな感じの想定です。<br />
・送料無料キャンペーン(今まで送料無料ではなかった部分の売上が増える=平均単価が減少する仮説)<br />
・送料無料キャンペーンをやっていなかった、去年の売上と今年の売上を比較<br />
・月初から今日までの期間を考える<br />
<br />
<br />
以下がコード<br />
<br />
まずはヒストリカルグラフで確認
<br />
<pre class="ruby" name="code">require 'rsruby'
r = RSRuby::instance
x = Order.where("created_at between ? and ?" , Time.now.beginning_of_month, Time.now).map(&:price).(&:to_f)
y = Order.where("created_at between ? and ?" , Time.now.beginning_of_month - 1.years, Time.now - 1.years).map(&:price).(&:to_f)
r.eval_R(<<-RCOMMAND)
hist(#{y.join(",")}, breaks = 5 ,col = "#0000ff40", border = "#0000ff", freq = TRUE)
hist(#{x.join(",")}, breaks = 5 ,col = "#ff00ff40", border = "#ff00ff", freq = TRUE, add = TRUE)
RCOMMAND
</pre>
一応F検定
<br />
<pre class="ruby" name="code">r.var_test(x, y)
</pre>
<br />
t検定
<br />
<pre class="ruby" name="code">r.t_test(x, y, altenative="two.sided")
</pre>
<br />
するとこんな感じの結果がでます。<br />
<br />
{"statistic"=>{"t"=>1.8121550934930575}, "parameter"=>{"df"=>4.0}, "p.value"=>0.1441855869309796, "conf.int"=>[-14560.490812856453, 69286.49081285646], "estimate"=>{"mean of x"=>32613.0, "mean of y"=>5250.0}, "null.value"=>{"difference in means"=>0.0}, "alternative"=>"two.sided", "method"=>"Welch Two Sample t-test", "data.name"=>"c(63210L, 14385L, 74970L, 5250L, 5250L) and c(5250L, 5250L)"}
<!---rcommand--><!---rcommand-->Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-17696107078699006572013-03-04T18:04:00.002+09:002013-03-04T18:04:49.039+09:00ruby2.0 on Rails4.0でABテストができる短縮URLサービスを作った<p>
先日ruby2.0が公開され、Rails4.0がついにbetaとしてgem化されていたので、早速使ってみた。
</p>
作ったサービスは、こちら
<a href="http://url-s.herokuapp.com/" target="_blank">http://url-s.herokuapp.com/</a>
</p>
<p>
ソースはgithubに<a href="https://github.com/face-do/split_shorten_urls" target="_blank">あげてあります。</a>。
</p>
<p>
これは2種類以上のURLを登録できる短縮URLサービスです。<br />
外部サービスを利用していてABテストができないときに、2種類のランディングページを用意しておいて、短縮URLでランダムに飛んでもらいテストするという用途を想定しています。
</p>
<p>
以下ruby2.0とRails4.0を使ってみた感想。
<ul>
<li>起動早い。2.0のおかげだと思うけど、前の環境には戻りたくない</li>
<li>マジックコメントいちいち書かなくていいの最高!</li>
<li>strong paramerterでちょいはまり。特にネストしたモデルのを扱うなら、attributesの方のidを許可しないと、updateした時に、新規で作成されてしまうので注意。</li>
<li>find_byメソッドのほうが直感的でよい。というかなんでそうじゃなかったの?</li>
</ul>
</p>
<p>
結論。
新規でアプリ作る場合、特に躊躇する理由もないので、この組み合わせで積極的に使っていきたい。
</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-19879288658885534032013-01-19T15:27:00.002+09:002013-01-19T15:27:27.089+09:00railsでorder時に特定IDのデータだけ、前に持ってくる方法例えば、IDが1〜10のデータがある時に、IDの降順にしようとした時には
<br />
<pre class="ruby" name="code">Model.order("id desc").all
</pre>
などとするが、時々この中の一部(例えばID:3)は先頭に、それ以外はIDの降順にしたいときなどがある。<br />
そんなときは、
<br />
<pre class="ruby" name="code">Model.order("'id' = CASE WHEN id = 3 THEN 0 ELSE 'id' END").order("id desc").all
</pre>
などとすると、できる。
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-82393345308087768582013-01-10T23:18:00.003+09:002013-01-11T01:25:37.995+09:00vanityとchankoを使ってRailsで簡単安全にABテストをするvanityはRailsのABテスト用ライブラリ。導入が一番簡単っぽい。<br />
元々はテキストとか画像をのABテストを行うためのもののようだが、
chankoという限定公開用のライブラリを使って、機能単位でもABテストができるようにしてみる。<br />
<br />
まずはGemfileに
<br />
<pre class="ruby" name="code">gem 'chanko', :git => 'git://github.com/cookpad/chanko.git'
gem "vanity"
</pre>
を記述して、<br />
# bundle install<br />
<br />
それぞれに必要な初期設定をする。<br />
# rails generate chanko:install<br />
# rails generate vanity<br />
# rake db:migrate<br />
<br />
config/vanity.ymlを作成
<br />
<pre class="ruby" name="code">development:
adapter: active_record
active_record_adapter: mysql2
host: localhost
database: DBNAME
user: USERNAME
password: PASSWORD</pre>
<br />
development.rbに以下を記述
<br />
<pre class="ruby" name="code"> Vanity.playground.collecting = true
</pre>
<br />
vanityのDashboard用コントローラを作成
<br />
<pre class="ruby" name="code">class VanityController < ApplicationController
include Vanity::Rails::Dashboard
end </pre>
<br />
ルーティングを設定
<br />
<pre class="ruby" name="code">match '/vanity(/:action(/:id(.:format)))', :controller=>:vanity
</pre>
<br />
測定用のユーザアイデンティティを設定。
<br />
<pre class="ruby" name="code">class ApplicationController < ActionController::Base
use_vanity :current_user
end
</pre>
<br />
Railsのルートディレクトリ下にテストと測定用のファイルを作成<br />
#mkdir -p experiments/metrics<br />
<br />
postした回数測定用のファイルを作成<br />
experiments/metrics/post.rb
<br />
<pre class="ruby" name="code">metric "Post" do
description "Postした回数"
end</pre>
<br />
コントローラの好きな場所に、
track! :post
を入力すれば、その場所がよばれた回数を測定できるようになります。
<br />
<pre class="ruby" name="code">class PostController < ApplicationController
def create
track! :post
# ...投稿する処理
end
end
end
</pre>
<br />
テスト用ファイルを作成<br />
experiments/post_labels.rb
<br />
<pre class="ruby" name="code">ab_test "Post labels" do
description "テスト"
alternatives true, false
metrics :post
end</pre>
<br />
次にchanko用設定<br />
# rails generate chanko sample
<br />
<pre class="ruby" name="code">
module Sample
include Chanko::Unit
active_if do |context, options|
ab_test(:price_options)
end
scope(:controller) do
function(:controller_show) do
# controller code here
end
end
scope(:view) do
function(:view_show) do
render :partial => "/show"
end
end
end
</pre>
で、好きな場所にinvoke(:sample, :controller_show) をおいたり、<br />
invoke(:sample, :show)
を置けばOK。<br />
chankoの詳しい使い方は<a href="https://github.com/cookpad/chanko" target="_blank">こちら</a>を参考に。<br />
<br />
どちらが優位かなんてのは、Vanityが表示してくるので、
評価しやすいはず。<br />
<br />
production環境でうまく動かなかったので、<br />
そのときはredisによる接続をためしてみるといいかも。<br />
<pre class="ruby" name="code">
production:
adapter: redis
host: localhost
</pre>
<br />
<br />
<br />
参考:<br />
<a href="http://eccyan.hatenablog.com/entry/2011/12/08/223603">http://eccyan.hatenablog.com/entry/2011/12/08/223603</a><br />
<a href="https://github.com/assaf/vanity">https://github.com/assaf/vanity</a><br />
<a href="http://webandy.com/articles/a-b-testing-with-vanity">http://webandy.com/articles/a-b-testing-with-vanity</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-69096903076750377622012-12-05T11:03:00.000+09:002012-12-05T11:03:29.904+09:00rubymotionとrailsの連携を試行錯誤した話 <p>
この記事は<a href="http://www.adventar.org/calendars/18">RubyMotion Advent Calendar 2012</a>の5日目記事です。
</p>
<p>
rubymotionメリットのひとつに、サーバサイド(Rails)とクライアントサイドが同じ言語でかけることがあると思いますが、<br />
思いの外Railsとどう連携していくかの情報が少ないような気がします。<br />
なので他の人の参考になればと、個人的に試行錯誤したことを残しておこうと思います。
</p>
<p>
ちなみに、<a href="https://itunes.apple.com/jp/app/one-minutes/id568641977?mt=8">one minutes</a>というアプリを、rubymotionで作りましたので、よければダウンロードしてください。
</p>
<h3>
試行錯誤1、babble-wrapで都度処理を書く</h3>
<p>
先述のone minutesでは、表示させるニュース情報をサーバからjsonで取得するだけの単純作業なので、以下の様な感じで実装しました。
</p>
<pre class="ruby" name="code">
BW::HTTP.get(SERVER_URL) do |response|
if response.ok?
@data = BW::JSON.parse(response.body.to_str)
else
App.alert(response.error_message)
end
end
</pre>
<p>
実装はかなり楽でしたが、複数情報を取得したい先がある場合や、postを行うときには、かなり面倒なことになってしまいました。<br />
それが↓です。
</p>
<h3>
試行錯誤2、babble-wrapで都度処理を書く(その2)</h3>
<p>ソーシャルアプリを作ろうとした際の実装です。<br />
アプリ概要は、facebookみたいなものなので、記事の投稿、投稿に対するコメント、投稿に対するいいね、それぞれを表示させるタイムラインの実装が必要でした。<br />
それが下記コード群です。
</p>
#記事読み込み
<pre class="ruby" name="code">
BubbleWrap::HTTP.get("#{SERVER_URL}/entries.json?page=#{@page}") do |response|
if response.ok?
json = BubbleWrap::JSON.parse(response.body.to_str)
unless json.count == 0
@table_dates << json
self.tableView.reloadData
@page += 1
@readMoreButton.enabled = true
@readMoreButton.hidden = false if @page
else
@page = nil
@readMoreButton.hidden = true
end
else
App.alert(response.error_message)
end
end
</pre>
#記事投稿
<pre class="ruby" name="code"> BubbleWrap::HTTP.post("#{SERVER_URL}/entries.json", {payload: data})
</pre>
#コメント
<pre class="ruby" name="code">
BubbleWrap::HTTP.post("#{SERVER_URL}/comments.json", {payload: data}) do |response|
if response.ok?
App.alert("コメントしました")
elsif response.status_code.to_s =~ /40\d/
App.alert("comment failed")
else
App.alert(response.error_message)
end
end
</pre>
#いいね
<pre class="ruby" name="code">
BubbleWrap::HTTP.post("#{SERVER_URL}/likes.json", {payload: data}) do |response|
if response.ok?
App.alert("likeしました")
else
App.alert(response.error_message)
end
end
</pre>
<p>
企画自体が没になったため、コレ以上コードは書いていないのですが、<br />
重複が多く、メンテナンス性も非常に悪いものができてしまいました。
</p>
<p>
で、このあとECアプリを作ることになりました。<br />
これまでの経験を踏まえ、もう少しRailsライクに実装したいと感じるように。
</p>
<p>
具体的には、<br />
1.new、find、save、allなどで情報が取得や保存ができるように<br />
2.バリデーションエラーは、その内容までも分かるように<br />
3.ネットワークエラーなどがでたら、バリデーションエラーなどとは別に判別できるように<br />
</p>
<p>
という理想を掲げ、作ってみた現実(ライブラリ)はこちら。<br />
<a href="https://github.com/face-do/motion-rails-model">https://github.com/face-do/motion-rails-model</a>
</p>
<p>
初めて作ったライブラリでもあり、非常にできはよくないのですが、それでも一応の理想は実現できました。<br />
(といっても、babble-wrapのさらにwrapperライブラリだったりしますが。。。)
</p>
<p>
使い方としては、最初にアクセスしたいURLやbasic認証の情報を入力</p>
<br />
<pre class="ruby" name="code">
RM::Model.set_url("#{URL}/api/")
RM::Model.set_username("username")
RM::Model.set_password("password")
</pre>
<p>その後モデル用のクラスを作り、ライブラリを継承。</p>
<pre class="ruby" name="code">class Orders < RM::Model
attr_accessor :name
def attributes_update(json)
@name = json['name']
super
end
end
</pre>
<p>これで、</p>
<pre class="ruby" name="code">
order = Orders.new
order.name = "hogehoge"
order.save do |x|
if x.ok?
App.alert("保存しました。")
end
end
</pre>
<p>とかすると、<br />
railsに対して<br />
/api/orders.json?name=hogehoge<br />
のpostメソッドを実行するし、<br />
</p>
<pre class="ruby" name="code">
Orders.find(1) do |x|
if x.ok?
@order = x.body
end
end
</pre>
<p>で、<br />
/api/orders/1.json<br />
のgetをしたりします。
</p>
<p>
またgetしてきた、Objectに対してsaveをすると、<br />
/api/orders/1.json<br />
に対してputをするようになってます。<br />
</p>
<p>
これを作った後、メタプログラミングrubyを読みまして、<br />
もう少し抽象化ができそうな気がしているので、機会を見て修正していく予定です。</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-18009295430848304832012-10-29T19:02:00.001+09:002012-10-29T19:02:23.352+09:00今ウェブサイトを作るなら必須のアイコン画像サイズ一覧 <br />
漏れがないようにまとめてみました。<br />
<br />
サイト全体<br />
favicon<br />
16×16<br />
<br />
facebook(OGP)対策<br />
200x200<br />
<br />
ウェブクリップアイコン(ios、android)対策<br />
114×114(iPhone、iPod touchのRetina)<br />
57×57(iPhone、iPod touchの非Retina)<br />
144×144(iPadのRetina)<br />
72×72(iPadの非Retina)<br />
<br />
一括作成サービスができてくれるといいなあ。<br />
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-65579983005289417982012-09-29T17:38:00.001+09:002012-09-29T17:38:20.562+09:00rubymotion用ライブラリの作り方 <p>
ライブラリのコードは予め書いておき、またrubygemsに公開するなら、<br />
そのアカウントを取得しておく。<br />
</p>
<p>
適当なフォルダで<br />
# bundle gem motion-hogehoge<br />
で、gemの雛形を作成<br />
</p>
<p>
.gemspecに必要な項目を入力。<br />
依存ライブラリがある場合は、ここに<br />
gem.add_dependency "bubble-wrap", "~>1.1.4"<br />
などと追記しておく。<br />
</p>
<p>
次に、lib/motion-hogehoge.rbというファイルができているので、ここを修正。<br />
rubymotionではrequireが対応していないので、rubymotion用に書き直す必要がある。<br />
以下がサンプル<br />
</p>
<pre class="ruby" name="code">
unless defined?(Motion::Project::Config)
raise "This file must be required within a RubyMotion project Rakefile."
end
Motion::Project::App.setup do |app|
Dir.glob(File.join(File.dirname(__FILE__), 'motion-hogehoge/*rb')).each do |file|
app.files.unshift(file)
end
end
</pre>
<p>
ライブラリのコードは、lib/motion-hogehoge/以下に入れておく。
</p>
<p>
rubygemsに登録する場合は、テストが通ってる必要がある。<br />
とりあえず通すだけなら、以下でOK。<br />
</p>
app/app_delegate.rbに<br />
<pre class="ruby" name="code">
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
@window.rootViewController = UIViewController.alloc.init
@window.makeKeyAndVisible
true
end
end
</pre>
spec/main_spec.rbに
<pre class="ruby" name="code">
describe "Application 'modeltest'" do
before do
@app = UIApplication.sharedApplication
end
it "has one window" do
@app.windows.size.should == 1
end
end
</pre>
<p>
で、<br />
#bundle install<br />
#rake spec<br />
でテストが通ることを確認する。<br />
</p>
<p>
問題がなければ、<br />
gem build motion-hogehoge.gemspec<br />
で、gemファイルを作成し、<br />
</p>
<p>
gem push motion-hogehoge-0.0.1.gem <br />
で、rubygemsにアップする。<br />
</p>
<p>
アップするときに取得したアカウント情報が聞かれるので入力すればOK。
</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-39656865174031601972012-09-28T15:21:00.000+09:002012-09-28T15:21:16.109+09:00Railsとjsonでやり取りするmotion-rails-modelというrubymotion用ライブラリを作ってみた <p>
Railsと連携する際、babble-wrapを使っていたのですが、<br />
取得先が複数になったときに面倒だったのでラッパーライブラリを作ってみました。<br />
Active Record風のメソッドで、Rest風にアクセスをします。
</p>
<p><a href="https://github.com/face-do/motion-rails-model.git" target="_blank">github</a></p>
使い方<br />
rails側はindex,show,create,update,destoryをjsonで返信するようにします。
アプリ側では適当にmodelクラスを作って、motion-rails-modelを継承し、<br />
attr_accessorとattributes_updateに項目を追加します。
<br />
<pre class="ruby" name="code">class Entries < RM::Model
attr_accessor :title, :description
def attributes_update(json)
@title = json['title']
@description = json['description']
super
end
end
</pre>
利用するときは、まずurlを設定します。
<br />
<pre class="ruby" name="code">class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
RM::Model.set_url("http://localhost:3000/")
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
@window.rootViewController = RootViewController.alloc.init
@window.makeKeyAndVisible
true
end
end
</pre>
あとは、
<br />
<pre class="ruby" name="code">Entries.all do |x|
if x
p x
else
p "error"
end
end
</pre>
で、<br />
http://localhost:3000/entriesにアクセスし
<br />
<pre class="ruby" name="code">Entries.find(1) do |x|
if x
p x
else
p "error"
end
end
</pre>
で、<br />
http://localhost:3000/entries/1<br />
にアクセス。
<br />
<pre class="ruby" name="code">@entry = Entries.new
@entry.title = "title"
@entry.description = "description"
@entry.save do |x|
if x
p x
else
p "error"
end
end
</pre>
で、<br />
http://localhost:3000/entries<br />
にpost。
<br />
<pre class="ruby" name="code">@entry.title = "title2"
@entry.save do |x|
if x
p x
else
p "error"
end
end
</pre>
で、http://localhost:3000/entries/1<br />
にput。
<br />
<pre class="ruby" name="code">@entry.destory do |x|
if x
p x
else
p "error"
end
end
</pre>
で、http://localhost:3000/entries/1<br />
にdeleteでアクセスするようになってます。
<p>
TODOとして<br />
attributes_updateを設定しなくてもいいようにする。
エラー処理をもう少ししやすく。
</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-59594705789705284872012-09-26T22:22:00.000+09:002012-09-26T22:22:04.178+09:00現在のフォルダにあるファイルをリネームする <pre class="ruby" name="code">
files = Dir::entries(Dir::pwd)
files.each do |f|
File.rename(f, f.sub(/aaa-/, '')) if f =~ /aaa-/
end
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-8619661103182629832012-09-26T22:16:00.002+09:002012-09-26T22:18:10.011+09:00csvを読み込んで、別のcsvの項目のうち2つ一致した項目を表示する <pre class="ruby" name="code">
# -*- coding: utf-8 -*-
require 'csv'
a_csvs=[]
b_csvs=[]
succsess = []
failed = []
a_csvs_tmp = CSV.open('a.csv', 'r')
b_csvs_tmp = CSV.open('b.csv', 'r')
a_csvs_tmp.each{|x| a_csvs << x }
b_csvs_tmp.each{|x| b_csvs << x }
a_csvs.each do |x|
a = b_csvs.select{|b| x[0] == b[0] and x[1] == b[1] }
unless a.empty?
succsess << a
else
failed << x
end
end
puts "見つかったモノ"
p succsess.flatten
puts "失敗したモノ"
p failed.flatten
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-91170797493033117102012-07-24T16:14:00.001+09:002012-07-24T16:39:26.463+09:00iosとrailsでinstagramのクローンサービスを作る<p>
iosとrailsでinstagramのクローンサービスを作る<br />
<br />
railsと連携したネイティブアプリを作りたかったので、<br />
instagramのクローンサービスを作ってみました。<br />
<br />
完成度はかなり低く、多分全体実装の5%くらいのですが、<br />
会員登録(ログイン)、登録者に紐付いたタイムラインの表示、写真(加工)、ユーザ検索、フォロー、アンフォロー<br />
あたりまではできるようになっています。<br />
<br />
ソースはいつものようにgithubに。<br />
<a href="https://github.com/face-do/clonestagram">https://github.com/face-do/clonestagram</a><br />
<br />
server側のコードと、client側のコードがセットではいってます。<br />
<br />
実際に試す場合には、<br />
画像のアップロードには、carrierwaveを使ってS3にあげているので、そのトークンを変更し、<br />
またios側で通信先のURLをすべて変更してください。<br />
<br />
会員登録(ログイン)の処理はserver側でdeviseを使っていて、<br />
ios側がusernameとpasswordをjsonで送信すると、その結果をjsonで返してくれるので、<br />
それをうけて適当に処理するようにしてます。<br />
<br />
TODOとしては、<br />
フィルタがしょぼいので調整する。<br />
各種バグの修正。<br />
ユーザ個別画面の修正。<br />
<br />
参考:<br />
<a href="http://wp.serpere.info/archives/2110">http://wp.serpere.info/archives/2110</a><br />
<a href="http://d.hatena.ne.jp/tomute/20091121/1258884514">http://d.hatena.ne.jp/tomute/20091121/1258884514</a><br />
<a href="http://d.hatena.ne.jp/sparkgene/20120422/1335075063">http://d.hatena.ne.jp/sparkgene/20120422/1335075063</a><br />
<a href="http://oneworld-inc.jp/blog/?p=148">http://oneworld-inc.jp/blog/?p=148</a><br />
<br />
iosのライブラリ<br />
<a href="https://github.com/glassonion1/R9HTTPRequest">https://github.com/glassonion1/R9HTTPRequest</a><br />
<a href="https://github.com/ldandersen/scifihifi-iphone/tree/master/security">https://github.com/ldandersen/scifihifi-iphone/tree/master/security</a><br />
<a href="http://stig.github.com/json-framework/">http://stig.github.com/json-framework/</a><br />
</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-74814006775333103042012-03-23T02:35:00.005+09:002012-03-23T10:47:39.892+09:00自分用のdropbox automatorが作れる!dropbox+herokuでtwitterに写真を自動投稿する方法dropboxにファイルを上げると、自動的にfacebookやflickrに投稿するようにできる<a href="http://wappwolf.com/dropboxautomator/" target="_blank">dropbox automator</a>というサービスがあります。<br />このサービスはtwitterへのphoto投稿が対応していないので、dropbox apiとherokuを使って、できるようにしてみたいと思います。<br />今回のファイルは<a href="https://github.com/face-do/dropbox_sdk_test" target="_blank">github</a>にあげておきました。<br /><br />とりあえずgemをインストール<br /># vim Gemfile<br /><br />下記を記述。<br /><pre name="code" class="ruby"><br />source "http://rubygems.org"<br />gem "clockwork"<br />gem 'dropbox-sdk'<br />gem 'twitter'<br /></pre><br /><br /># bundle install<br /><br />次にdropbox apiを使えるように<a href="https://www.dropbox.com/developers/apps" target="_blank">こちら</a>から登録してください。<br />ログイン後、<a href="https://www.dropbox.com/developers/apps" target="_blank">アプリ登録画面</a>で「create an App」をクリック<br />適当にアプリ名と説明を入れて、「App folder」の方をチェックして、登録。<br /><br />アプリの詳細画面でApp keyとApp secretを確認してください。<br />apiを使うためには、コレ以外にrequest_tokenとaccess_tokenが必要なのですが、<br />そのためにはブラウザでフォルダへの許可を取る必要があります。<br /><br />なので、まずはその取得用のスクリプトを作成。<br /><br /><pre name="code" class="ruby"><br /># -*- coding: utf-8 -*-<br />require 'dropbox_sdk'<br /><br />APP_KEY = 'INSERT-APP-KEY-HERE'<br />APP_SECRET = 'INSERT-APP-SECRET-HERE'<br />ACCESS_TYPE = :app_folder<br />session = DropboxSession.new(APP_KEY, APP_SECRET)<br /><br />request_token = session.get_request_token<br /><br />authorize_url = session.get_authorize_url<br />puts "AUTHORIZING", authorize_url<br />gets<br /><br />access_token = session.get_access_token<br /><br />p "request_token:", request_token<br />p "access_token:", access_token<br /></pre><br /><br /><br />上のスクリプトを一端起動してください。<br />途中urlが表示されると思いますので、それをブラウザに入力。<br />認証完了後、ターミナルに戻り、エンターを押してください。<br /><br />request_tokenとaccess_tokenのkeyとsecretがそれぞれ表示されると思いますので、メモしておきます。<br /><br />次に実際に動かすスクリプトの作成。<br /><br />herokuのcedar stackでは、webの代わりにスクリプトを動かしっぱなしにできるので、それを利用します。<br />具体的には、clockworkというライブラリを使い、一定ごとにdropboxのapiを叩き、新規ファイルが登録されていれば、それを投稿という流れ。<br /><br />設定用のファイルを作成。<br /># vim Procfile<br /><pre name="code" class="ruby"><br />cron: bundle exec clockwork clock.rb<br /></pre><br /><br />コードは下記の通り。<br /><pre name="code" class="ruby"><br /># -*- coding: utf-8 -*-<br />require 'clockwork'<br />require 'twitter'<br />require 'dropbox_sdk'<br />include Clockwork<br />@time = Time.now<br /><br />Twitter.configure do |config|<br /> config.consumer_key = 'XXXXXXXXXXXXXXXX'<br /> config.consumer_secret = 'XXXXXXXXXXXXXXXX'<br /> config.oauth_token = 'XXXXXXXXXXXXXXXX'<br /> config.oauth_token_secret = 'XXXXXXXXXXXXXXXX'<br />end<br /><br />APP_KEY = 'INSERT-APP-KEY-HERE'<br />APP_SECRET = 'INSERT-APP-SECRET-HERE'<br />ACCESS_TYPE = :app_folder<br />session = DropboxSession.new(APP_KEY, APP_SECRET)<br />session.set_request_token('REQUEST_TOKEN_KEY', 'REQUEST_TOKEN_SECRET')<br />session.set_access_token('ACCESS_TOKEN_KEY', 'ACCESS_TOKEN_SECRET')<br />client = DropboxClient.new(session, ACCESS_TYPE)<br /><br />handler do |job|<br /> filedata = nil<br /> file_metadata = client.metadata('/')<br /> filedata = file_metadata["contents"].map { |x| x if Time.parse( x["modified"]) > @time }<br /> filedata.each do |f|<br /> unless f == nil<br /> file = client.get_file(f["path"])<br /> filename = Time.now.to_i.to_s<br /> File.open("/tmp/" + filename, "w") {|f| f.write file}<br /> tmp = File.open("/tmp/" + filename, "rb")<br /> p tmp<br /> Twitter.update_with_media(@time.strftime("%F %H:%M"), tmp)<br /> end<br /> end<br /> @time = Time.now<br />end<br /><br />every(1.minutes, 'check')<br /></pre><br /><br />apiのキーはそれぞれ先程メモったものなどを入力してください。<br /><br />あとはherokuに上げるだけ。<br /># git init<br /># git add .<br /># git commit -m 'first commit'<br /><br /># heroku create --stack cedar<br /># git push heroku master<br /># heroku scale cron=1<br /><br />ちゃんと動いているかどうか確認します。<br /># heroku ps<br />起動しているプロセスがcron.1だけのはず。<br /><br /># heroku logs --tail<br />Triggering checkみたいなログがでているはずです。<br /><br />あとは、dropboxに先程登録したアプリ名のファイルができているので、画像をコピーしてみます。(なぜかgitがうまく投稿できませんでした。。。)<br />twitterに自動投稿されていれば成功です。<br /><br />ファイル名や種類、アップするフォルダで処理を変えるようにすれば、自分なりの「dropbox automator」がつくれます。Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-10058078655440185762012-03-19T01:08:00.003+09:002012-03-19T13:09:02.075+09:00iphoneで撮った写真をherokuにアップロードする(iosアプリ)<a href="http://face-do.blogspot.jp/2012/03/herokuimage-uploader.html">herokuで無料のimage uploaderを作る</a>の続き。<br /><br />mongolabを使って、写真のアップローダを作れるようにしましたが、せっかくなのでiphoneから写真を直接あげられるようにしておきます。<br />写真をアップロードはhttpを使ってサーバにpostします。<br /><br />postするサンプルを作っている人がいたので、これをベースにして使うことに。<br /><a href="https://github.com/tochi/HTTPFileUploadSample.git" target="_blank">https://github.com/tochi/HTTPFileUploadSample</a><br /><br />HTTPFileUploadSampleViewController.hを以下のように修正<br /><pre name="code" class="c"><br />@interface HTTPFileUploadSampleViewController : UIViewController <HTTPFileUploadDelegate, UITextFieldDelegate><br />{<br /> IBOutlet UITextField *codeTextField;<br /> IBOutlet UIImageView *_imageView;<br />}<br /><br />- (IBAction)postButtonClicked:(id)sender;<br />- (IBAction)showCameraSheet:(id)sender;<br />@property (retain, nonatomic) IBOutlet UITextField *codeTextField;<br /></pre><br /><br />HTTPFileUploadSampleViewController.mを以下のように修正<br />httpFileUpload postWithUriは自分のherokuのURLに修正してください。<br /><br /><pre name="code" class="c"><br />#import "HTTPFileUploadSampleViewController.h"<br /><br />@implementation HTTPFileUploadSampleViewController<br />@synthesize codeTextField = _codeTextField;<br /><br />- (void)dealloc<br />{<br /> [_imageView release];<br /> [_codeTextField release];<br /> [super dealloc];<br />}<br /><br />- (void)didReceiveMemoryWarning<br />{<br /> [super didReceiveMemoryWarning];<br />}<br /><br />#pragma mark - View lifecycle<br />- (void)viewDidLoad<br />{<br /> [super viewDidLoad];<br /> _codeTextField.returnKeyType = UIReturnKeyDone;<br /> _codeTextField.delegate = self;<br />}<br /><br />- (BOOL)textFieldShouldReturn:(UITextField *)textField {<br /> [_codeTextField resignFirstResponder];<br /> return YES;<br />}<br /><br />- (void)viewDidUnload<br />{<br /> [_imageView release];<br /> _imageView = nil;<br /> [codeTextField release];<br /> codeTextField = nil;<br /> [self setCodeTextField:nil];<br /> [super viewDidUnload];<br />}<br /><br />- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation<br />{<br /> return (interfaceOrientation == UIInterfaceOrientationPortrait);<br />}<br /><br />- (IBAction)postButtonClicked:(id)sender<br />{<br /> // Get image data.<br /> //UIImage *image1 = [UIImage imageNamed:@"Icon.png"];<br /> <br /> // File upload.<br /> HTTPFileUpload *httpFileUpload = [[HTTPFileUpload alloc] init];<br /> httpFileUpload.delegate = self;<br /> [httpFileUpload setPostString:self.codeTextField.text withPostName:@"name"];<br /> [httpFileUpload setPostImage:_imageView.image withPostName:@"photo" fileName:@"Icon.png"];<br /> [httpFileUpload postWithUri:@"http://XXXX.herokuapp.com/users/photo.json"];<br /> [httpFileUpload release], httpFileUpload = nil;<br />}<br /><br />- (IBAction)showCameraSheet:(id)sender {<br /> // アクションシートを作る<br /> UIActionSheet* sheet;<br /> sheet = [[UIActionSheet alloc] <br /> initWithTitle:@"Select Soruce Type" <br /> delegate:self <br /> cancelButtonTitle:@"Cancel" <br /> destructiveButtonTitle:nil <br /> otherButtonTitles:@"Photo Library", @"Camera", @"Saved Photos", nil];<br /> [sheet autorelease];<br /> <br /> // アクションシートを表示する<br /> [sheet showInView:self.view];<br />}<br /><br />- (void)actionSheet:(UIActionSheet*)actionSheet <br />clickedButtonAtIndex:(NSInteger)buttonIndex<br />{<br /> // ボタンインデックスをチェックする<br /> if (buttonIndex >= 3) {<br /> return;<br /> }<br /> <br /> // ソースタイプを決定する<br /> UIImagePickerControllerSourceType sourceType = 0;<br /> switch (buttonIndex) {<br /> case 0: {<br /> sourceType = UIImagePickerControllerSourceTypePhotoLibrary;<br /> break;<br /> }<br /> case 1: {<br /> sourceType = UIImagePickerControllerSourceTypeCamera;<br /> break;<br /> }<br /> case 2: {<br /> sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;<br /> break;<br /> }<br /> }<br /> <br /> // 使用可能かどうかチェックする<br /> if (![UIImagePickerController isSourceTypeAvailable:sourceType]) { <br /> return;<br /> }<br /> <br /> // イメージピッカーを作る<br /> UIImagePickerController* imagePicker;<br /> imagePicker = [[UIImagePickerController alloc] init];<br /> [imagePicker autorelease];<br /> imagePicker.sourceType = sourceType;<br /> imagePicker.allowsImageEditing = YES;<br /> imagePicker.delegate = self;<br /> <br /> // イメージピッカーを表示する<br /> [self presentModalViewController:imagePicker animated:YES];<br />}<br /><br />- (void)imagePickerController:(UIImagePickerController*)picker <br /> didFinishPickingImage:(UIImage*)image <br /> editingInfo:(NSDictionary*)editingInfo<br />{<br /> // イメージピッカーを隠す<br /> [self dismissModalViewControllerAnimated:YES];<br /> // オリジナル画像を取得する<br /> UIImage* originalImage;<br /> originalImage = [editingInfo objectForKey:UIImagePickerControllerOriginalImage];<br /> <br /> // グラフィックスコンテキストを作る<br /> CGSize size = { 300, 400 };<br /> UIGraphicsBeginImageContext(size);<br /> <br /> // 画像を縮小して描画する<br /> CGRect rect;<br /> rect.origin = CGPointZero;<br /> rect.size = size;<br /> [originalImage drawInRect:rect];<br /> <br /> // 描画した画像を取得する<br /> UIImage* shrinkedImage;<br /> shrinkedImage = UIGraphicsGetImageFromCurrentImageContext();<br /> UIGraphicsEndImageContext();<br /> <br /> // 画像を表示する<br /> _imageView.image = shrinkedImage;<br />}<br /><br />- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker<br />{<br /> // イメージピッカーを隠す<br /> [self dismissModalViewControllerAnimated:YES];<br />}<br /><br />- (void)httpFileUpload:(NSURLConnection *)connection<br /> didFailWithError:(NSError *)error<br />{<br /> NSLog(@"%@", error);<br />}<br /><br />- (void)httpFileUploadDidFinishLoading:(NSURLConnection *)connection<br /> result:(NSString *)result<br />{<br /> NSLog(@"%@", result);<br /> UIAlertView *alert = [[UIAlertView alloc]<br /> initWithTitle:@"" <br /> message:@"投稿完了しました。" <br /> delegate:nil <br /> cancelButtonTitle:@"OK" <br /> otherButtonTitles:nil, nil];<br /> [alert show];<br /> [alert release];<br />}<br />@end<br /></pre><br /><br />次にここを参考にxibを作成。アクションシートを追加してください。(コードは上のものにすでに入ってます。)<br /><a href="http://news.mynavi.jp/column/iphone/001/index.html" target="_blank">http://news.mynavi.jp/column/iphone/001/index.html</a><br />同じような感じで、textfieldを追加してください。(codeTextField)<br /><br />次にrails側。<br />こちらをベースに修正します。<br /><a href="https://github.com/face-do/heroku-image-uploader" target="_blank">https://github.com/face-do/heroku-image-uploader</a><br />UsersController.rbを以下の用に修正。<br /><pre name="code" class="ruby"><br /> def photo<br /> @user = User.new(:name => params[:name], :photo => params[:photo] )<br /><br /> respond_to do |format|<br /> if @user.save<br /> format.html { redirect_to @user, notice: 'User was successfully created.' }<br /> format.json { render json: @user, status: :created, location: @user }<br /> else<br /> format.html { render action: "new" }<br /> format.json { render json: @user.errors, status: :unprocessable_entity }<br /> end<br /> end<br /> end<br /></pre><br />config/routes.rbに以下を追記<br />post "users/photo" => 'users#photo'<br /><br />app/controllers/application_controller.rbを以下のように修正。<br /><pre name="code" class="ruby"><br />protect_from_forgery :except => :photo<br /></pre><br /><br />で、herokuにあげて、iosアプリをiphoneに転送すれば、できます。<br />一応今回のファイルをgithubにあげておきました。<br /><a href="https://github.com/face-do/heroku-free-photo-storage" target="_blank">rails アプリのほう</a><br /><a href="https://github.com/face-do/heroku-free-photo-storage-client" target="_blank">iphoneクライアントの方</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-14374103360161568382012-03-18T13:08:00.005+09:002012-03-18T13:20:21.936+09:00herokuで無料のimage uploaderを作るherokuで無料のimage uploaderを作る
<br />
<br />herokuは非常に便利ですが、read onlyなのでアップローダーを作ったりできません。
<br />もしやろうとするとS3を使った方法が一般的のようですが、若干利用料金がかかってしまいます。
<br />なので無料で作れる方法を考えてみました。
<br />
<br />herokuでは画像を直接アップすることはできませんが、DBに直接保存することができます。
<br />しかしherokuのデフォルトのものは、5MBしかありません。
<br />そこでmongolabという、mongodbを240MBまで無料提供してくれるサービスを利用します。
<br />なおmongolabはherokuにadd-onとして提供されているため、セットアップは簡単です。
<br />
<br />githubにファイルをあげておいたので、参考にしてください。
<br /><a href="https://github.com/face-do/heroku-image-uploader" target="_blank">https://github.com/face-do/heroku-image-uploader</a>
<br />
<br />まずはrailsプロジェクトを作成します。
<br />ただしmongodbを使うため、active recordを切るようにしておきます。
<br />
<br /># rails new uploader -O
<br />
<br />次に、gemfileに以下を追記
<br />
<br /><pre name="code" class="ruby">
<br />gem 'mongoid', '~>2.1'
<br />gem 'bson_ext', '~>1.3'
<br />gem 'carrierwave'
<br />gem 'carrierwave-mongoid', :require => 'carrierwave/mongoid'
<br /></pre>
<br />
<br /># bundle install
<br />
<br />で、mongodbに接続するための設定のひな形を作る。
<br /># rails generate mongoid:config
<br />
<br />config/mongoid.ymlのproductionを以下のように修正
<br /><pre name="code" class="ruby">
<br />production:
<br /> uri: <%= ENV['MONGOLAB_URI'] %>
<br /></pre>
<br />
<br />
<br />carrierwaveの設定をする
<br />#vim config/initializers/carrierwave.rb
<br />
<br />以下を記述
<br /><pre name="code" class="ruby">
<br />CarrierWave.configure do |config|
<br /> config.storage = :grid_fs
<br /> config.grid_fs_connection = Mongoid.database
<br /> config.grid_fs_access_url = "/images"
<br />end
<br /></pre>
<br />
<br />アップローダのひな形を作る
<br /># rails g scaffold page title:string
<br /># rails g uploader photo
<br />
<br />app/models/user.rbは以下のように
<br />
<br /><pre name="code" class="ruby">
<br />class User
<br /> include Mongoid::Document
<br /> field :title, :type => String
<br /> mount_uploader :photo, PhotoUploader
<br />end
<br /></pre>
<br />
<br />app/uploaders/photo_uploader.rbは以下のように修正
<br />
<br /><pre name="code" class="ruby">
<br /># encoding: utf-8
<br />class PhotoUploader < CarrierWave::Uploader::Base
<br /> include CarrierWave::RMagick
<br /> storage :grid_fs
<br /> def store_dir
<br /> "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
<br /> end
<br /> version :thumb do
<br /> process :resize_to_limit => [200, 200]
<br /> end
<br />end
<br /></pre>
<br />
<br />app/views/users/_form.html.erbの<div class="actions">の上に以下を追記
<br />
<br /><pre name="code" class="ruby">
<br /> <div class="field">
<br /> <%= f.label :photo %><br />
<br /> <%= image_tag( @user.photo_url ) if @user.photo? %>
<br /> <%= f.file_field :photo %>
<br /> <%= f.hidden_field :photo_cache %>
<br /> </div>
<br /></pre>
<br />
<br />このままだと画像が表示されないので、画像表示用のメソッドを作る。
<br />まずはapp/controllers/users_controller.rbに以下を追記
<br />
<br /><pre name="code" class="ruby">
<br />require 'mongo'
<br />class UsersController < ApplicationController
<br /> def serve
<br /> gridfs_path = env["PATH_INFO"].gsub("/images/", "")
<br /> begin
<br /> gridfs_file = Mongo::GridFileSystem.new(Mongoid.database).open(gridfs_path, 'r')
<br /> self.response_body = gridfs_file.read
<br /> self.content_type = gridfs_file.content_type
<br /> rescue
<br /> self.status = :file_not_found
<br /> self.content_type = 'text/plain'
<br /> self.response_body = ''
<br /> end
<br /> end
<br /></pre>
<br />
<br />config/routes.rbに以下を追記
<br />match "/images/uploads/*path" => "users#serve"
<br />
<br />これでアプリ側の設定は終了。git でcommitしておきます。
<br /># git add .
<br /># git commit -m 'first commit'
<br />
<br />次にheroku側の設定をします。
<br />#heroku create --stack cedar
<br />#heroku addons:add mongolab:starter
<br />
<br />あとはherokuにdeployするだけ
<br />#git push heroku master
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-42437356495309415792012-02-11T14:10:00.002+09:002012-02-11T14:14:23.300+09:00facebookアプリでsessionが維持できないfacebookでiframeを使ったアプリをつくろうとした時に、session内に情報を入れられない時がある。<br /><br /><pre><br /> protect_from_forgery :except => :index<br /></pre><br /><br />そのときは、sessionを使いたいコントローラーだけ、上記のように除外する。Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-40907864016930904662011-12-28T21:54:00.001+09:002011-12-28T21:55:57.880+09:00nginxとunicorn上でrails3.1アプリを動かす。ついでにcapistranoを使ってデプロイかなりハマったので、メモ。<br /><br />まずアプリ側。<br />Gemfileに以下を追加。<br /><pre><br />group :deployment do<br /> gem 'capistrano'<br /> gem 'capistrano_colors'<br />end<br /><br />gem 'therubyracer'<br />gem 'unicorn'<br /></pre><br />で、bundle install。<br /><br />次にcapistrano設定ファイルを作成<br /># capify .<br /><br />#config/deploy.rb<br /><pre><br /># capistranoの出力がカラーになる<br />require 'capistrano_colors'<br /><br /># cap deploy時に自動で bundle install が実行される<br />require "bundler/capistrano"<br /><br />#rvm setting<br />set :rvm_type, :user<br />$:.unshift(File.expand_path('./lib', ENV['rvm_path']))<br />require "rvm/capistrano"<br />set :rvm_ruby_string, '1.9.2@rails3.1' #ここにgemset名を入力<br /><br />set :user, "サーバーのユーザー名"<br />set :port, 22 #サーバーのポート番号<br />set :use_sudo, false #sudoをするかどうか。<br />ssh_options[:forward_agent] = true<br /><br />#repository setting<br />set :application, "sample" #アプリケーション名<br />set :scm, :git #gitを使う<br />set :repository, "ssh://user@example.com:22/home/user/git/sample.git"<br />set :deploy_to, "/home/user/sample/"<br />default_environment["LD_LIBRARY_PATH"] = "$LD_LIBRARY_PATH:/usr/local/lib"<br /><br /><br /><br /># Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`<br /><br />role :web, "example.com" # Your HTTP server, Apache/etc<br />role :app, "example.com" # This may be the same as your `Web` server<br />role :db, "example.com", :primary => true # This is where Rails migrations will run<br /><br />#sqlite3を使う場合、dbをshareフォルダに入れる。<br />task :db_setup, :roles => [:db] do<br /> run "mkdir -p -m 775 #{shared_path}/db"<br />end<br /><br />namespace :deploy do<br /> task :start, :roles => :app do<br /> run "cd #{current_path}; bundle exec unicorn_rails -c config/unicorn.rb -E production -D"<br /> end<br /> task :restart, :roles => :app do<br /> if File.exist? "/tmp/unicorn.pid"<br /> run "kill -s USR2 `cat /tmp/unicorn.pid`"<br /> end<br /> end<br /> task :stop, :roles => :app do<br /> run "kill -s QUIT `cat /tmp/unicorn.pid`"<br /> end<br />end<br /><br />namespace :assets do<br /> task :precompile, :roles => :web do<br /> run "cd #{current_path} && RAILS_ENV=production bundle exec rake assets:precompile"<br /> end<br /> task :cleanup, :roles => :web do<br /> run "cd #{current_path} && RAILS_ENV=production bundle exec rake assets:clean"<br /> end<br />end<br />after :deploy, "assets:precompile" #デプロイ後にassets compileをするように。<br />set :normalize_asset_timestamps, false #rails3.1対策<br /></pre><br /><br />次にunicornの設定<br />#config/unicorn.rb<br /><pre><br />application = 'sample'<br /><br /># ワーカーの数<br />worker_processes 2<br /><br /># ソケット<br />listen "/tmp/unicorn.sock"<br />pid "/tmp/unicorn.pid"<br /><br /># ログ<br />if ENV['RAILS_ENV'] == 'production'<br /> shared_path = "/home/user/#{application}/shared"<br /> stderr_path = "#{shared_path}/log/unicorn.stderr.log"<br /> stdout_path = "#{shared_path}/log/unicorn.stdout.log"<br />end<br /><br /># ダウンタイムなくす<br />preload_app true<br /><br />before_fork do |server, worker|<br /> if defined?(ActiveRecord::Base)<br /> ActiveRecord::Base.connection.disconnect!<br /> end<br /> old_pid = "/tmp/unicorn.pid.oldbin"<br /> if File.exists?(old_pid) && server.pid != old_pid<br /> begin<br /> Process.kill("QUIT", File.read(old_pid).to_i)<br /> rescue Errno::ENOENT, Errno::ESRCH<br /> end<br /> end<br />end<br /><br />after_fork do |server, worker|<br /> if defined?(ActiveRecord::Base)<br /> ActiveRecord::Base.establish_connection<br /> end<br />end<br /></pre><br /><br />environmentsのproduction内で<br />config.serve_static_assets = true<br />にする。<br />※こうしないとcssがロードされない。<br /><br />あとdatabase.ymlのproductionを<br /> database: ../../shared/db/production.sqlite3<br />にする。<br /><br /><br /><br />次はサーバ側。<br />nginxをyumでインストールするために、repoに追加。<br /># sudo vim /etc/yum.repo.d/nginx.repo<br /><br /><pre><br />[nginx]<br />name=nginx repo<br />baseurl=http://nginx.org/packages/rhel/$releasever/$basearch/<br />gpgcheck=0<br />enabled=1<br /></pre><br /><br />で、インストール。<br />#sudo yum install nginx<br /><br />nginxの設定ファイルはこんな感じ。<br />#sudo vim /etc/nginx/conf.d/sample.conf<br /><br /><pre><br />upstream unicorn {<br /> server unix:/tmp/unicorn.sock;<br />}<br /><br />server {<br /> listen 80;<br /> server_name example.com;<br /><br /> root /home/user/sample/current/public;<br /> error_log /home/user/sample/current/log/error.log;<br /><br /> location / {<br /> if (-f $request_filename) { break; }<br /> proxy_set_header X-Real-IP $remote_addr;<br /> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br /> proxy_set_header Host $http_host;<br /> proxy_pass http://unicorn;<br /> }<br /><br />}<br /></pre><br /><br />あとは、capistranoでデプロイして、nginxを起動するだけ。必要があればchkconfigで自動起動設定をする。<br />capistranoでデプロイするときは、<br />#cap deploy:setup<br />#cap db_setup<br />#cap deploy:cold<br />の順で。<br /><br /><br />参考:<br /><a href="http://d.hatena.ne.jp/ntaku/20111112/1321093327" target="_blank">http://d.hatena.ne.jp/ntaku/20111112/1321093327</a><br /><a href="http://aerial.st/archive/2011/06/16/nginx-unicorn-rails-on-mac/" target="_blank">http://aerial.st/archive/2011/06/16/nginx-unicorn-rails-on-mac/</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-55338712471294164712011-12-08T22:36:00.002+09:002011-12-08T23:55:14.960+09:00jQuery UIを使って、オートコンプリート機能を実装してみる@rails3.1facebookなどの検索BOXで途中まで入力すれば、結果の一部が出てくるあれです。<br /><br />rails3.1からjQueryがデフォルトになったのですが、jQuery UIはまだ有効になっていないので有効にする。<br /><br />application.jsの//= require jqueryの下あたりに以下を追記<br />//= require jquery-ui<br /><br />で、ビューに検索BOXをJSで作る。<br /><pre name="code" class="ruby"><br /><input type="text" id="textbox1"></input><br /><script type="text/javascript" charset="utf-8"><br /> $(function(){<br /> $("#textbox1").autocomplete({<br /> source : "/auto_complete"<br /> });<br /> })<br /></script><br /></pre><br /><br /><br />sourceの部分をルーティングで設定する。<br /> get 'auto_complete' => 'api#auto_complete'<br /><br />コントローラーはこんな感じで<br /><pre name="code" class="ruby"><br /><br /> def auto_complete<br /> if request.xhr?<br /> data = Array.new<br /> data_items = Data.where('name like ?', "%#{params[:term]}%")<br /> data_items.each do |f|<br /> data << f.name<br /> end<br /> return render data<br /> end<br /> end<br /></pre><br /><br /><br />検索BOXで入力したキーワードは都度、sourceで設定したアドレスに対して、params[:term]で送られます。<br />で、結果をjsonで返せば動作するのですが、そのまま返すと不必要なデータもそのまま送ってしまうので、必要なカラムのデータだけ送るよう、配列を作りなおしてます。<br />もう少しうまいやり方もありそうですが。。。<br />あと、request.xhr?と指定すると、ajax以外からのアクセスを弾いてくれるようです。<br /><br />ちなみにCSSを使う場合には、assetsのcssフォルダ下にjquery-ui-1.8.16.custom.cssをおいて、jsを呼び出すのと同じように<br /> *= require_jquery-ui-1.8.16.custom<br />をかけばOK<br />画像は、assets/image/jquery-uiの下にimageフォルダごとコピーすればOK。<br /><br />参考:<a href="http://d.hatena.ne.jp/naoty_k/20110925/1316969446" target="_blank">http://d.hatena.ne.jp/naoty_k/20110925/1316969446</a><br /><a href="http://blog.livedoor.jp/satoyansoft/archives/65458957.html" target="_blank">http://blog.livedoor.jp/satoyansoft/archives/65458957.html</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-42448766432491459272011-12-08T02:49:00.003+09:002011-12-08T23:39:42.153+09:00Railsでapiっぽいのを作って、iOSアプリと連携してみるiOS(iphone)アプリで位置情報を取得、それをrailsアプリに送信してDBに登録するようにしてみます。<br />なおiOSについてはまだまだ勉強不足のため、「<a href="http://www.amazon.co.jp/gp/product/4797364629/ref=as_li_tf_tl?ie=UTF8&tag=face-do-22&linkCode=as2&camp=247&creative=1211&creativeASIN=4797364629">まるごと学ぶiPhoneアプリ制作教室</a><img src="http://www.assoc-amazon.jp/e/ir?t=face-do-22&l=as2&o=9&a=4797364629" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />」内に記載してあったコードを参考にしています。<br />またrailsアプリ内には位置情報の取得まで作っておきますが、iOS部分では省きます。<br /><br />まずはiOSアプリの方。<br />ViewController.m<br /><pre name="code" class="c"><br />#import "ViewController.h"<br />#import "Location.h"<br />#import "JSON.h"<br /><br />@implementation ViewController<br />@synthesize codeTextField;<br /><br />- (void)didReceiveMemoryWarning<br />{<br /> [super didReceiveMemoryWarning];<br /> // Release any cached data, images, etc that aren't in use.<br />}<br /><br />#pragma mark - View lifecycle<br /><br />- (void)viewDidLoad<br />{<br /> [super viewDidLoad];<br /> // Do any additional setup after loading the view, typically from a nib.<br />}<br /><br />- (void)viewDidUnload<br />{<br /> [self setCodeTextField:nil];<br /> [super viewDidUnload];<br /> // Release any retained subviews of the main view.<br /> // e.g. self.myOutlet = nil;<br />}<br /><br />- (void)viewWillAppear:(BOOL)animated<br />{<br /> [super viewWillAppear:animated];<br />}<br /><br />- (void)viewDidAppear:(BOOL)animated<br />{<br /> [super viewDidAppear:animated];<br />}<br /><br />- (void)viewWillDisappear:(BOOL)animated<br />{<br /> [super viewWillDisappear:animated];<br />}<br /><br />- (void)viewDidDisappear:(BOOL)animated<br />{<br /> [super viewDidDisappear:animated];<br />}<br /><br />- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation<br />{<br /> // Return YES for supported orientations<br /> return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);<br />}<br /><br />- (NSString *)getCurrentDate {<br /> NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];<br /> NSString *dateFormat = @"yyyy/MM/dd-mm:ss:SSS";<br /> [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"JST"]];<br /> [dateFormatter setDateFormat:dateFormat];<br /> NSString *date = [dateFormatter stringFromDate:[NSDate date]];<br /> return date;<br />}<br /><br />- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {<br /> <br /> <br /> Location *myLocation = [[[Location alloc] init] autorelease];<br /> myLocation.latitude = [NSString stringWithFormat:@"%f", newLocation.coordinate.latitude];<br /> myLocation.longitude = [NSString stringWithFormat:@"%f", newLocation.coordinate.longitude];<br /> myLocation.time = [self getCurrentDate];<br /> myLocation.identificationCode = [codeTextField text];<br /> <br /> NSDictionary *locationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:<br /> myLocation.latitude, @"latitude",<br /> myLocation.longitude, @"longitude",<br /> myLocation.time, @"time",<br /> myLocation.identificationCode, @"identificationCode",<br /> nil];<br /> NSString* jsonString = [locationDictionary JSONRepresentation];<br /> NSLog(@"JSON: %@", jsonString);<br /> <br /> NSURL *serviceURL = [NSURL URLWithString:@"http://0.0.0.0:3000/location.json"];<br /> NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:serviceURL];<br /> [req setHTTPMethod:@"POST"];<br /> [req addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];<br /> [req setHTTPBody:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];<br /> <br /> NSURLResponse *resp= nil;<br /> NSError *error= nil;<br /> NSData *result = [NSURLConnection sendSynchronousRequest:req returningResponse:&resp error:&error];<br /> <br /> if (error) {<br /> NSLog(@"error!");<br /> } else {<br /> NSLog(@"Result:%@", result);<br /> }<br /> <br />}<br />- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{<br />}<br />- (IBAction)logStartButton:(id)sender {<br /> if (locationManager == nil) {<br /> locationManager = [[CLLocationManager alloc] init];<br /> }<br /> locationManager.delegate = self;<br /> [locationManager startUpdatingLocation];<br />}<br />- (void)dealloc {<br /> [codeTextField release];<br /> [super dealloc];<br />}<br />@end<br /></pre><br /><br />ViewController.h<br /><pre name="code" class="c"><br />#import <UIKit/UIKit.h><br />#import "CoreLocation/CoreLocation.h"<br /><br />@interface ViewController : UIViewController <CLLocationManagerDelegate> {<br />@private<br /> UITextField *codeTextField;<br /> UIButton *logStartButton;<br /> CLLocationManager *locationManager;<br />}<br />@property (retain, nonatomic) IBOutlet UITextField *codeTextField;<br />- (IBAction)logStartButton:(id)sender;<br /><br />@end<br /></pre><br /><br />Location.h<br /><pre name="code" class="c"><br />#import <Foundation/Foundation.h><br /><br />@interface Location : NSObject {<br /> NSString *latitude;//緯度<br /> NSString *longitude;//経度<br /> NSString *time;//時間<br /> NSString *identificationCode;//自分を特定するためのIDコード<br />}<br />@property (nonatomic, assign) NSString *latitude;<br />@property (nonatomic, assign) NSString *longitude;<br />@property (nonatomic, assign) NSString *time;<br />@property (nonatomic, assign) NSString *identificationCode;<br /><br />@end<br /></pre><br /><pre name="code" class="c"><br />#import "Location.h"<br /><br />@implementation Location<br />@synthesize latitude;<br />@synthesize longitude;<br />@synthesize time;<br />@synthesize identificationCode;<br /><br />@end<br /><br /></pre><br /><br />Location.m<br /><pre name="code" class="c"><br />#import "Location.h"<br /><br />@implementation Location<br />@synthesize latitude;<br />@synthesize longitude;<br />@synthesize time;<br />@synthesize identificationCode;<br /><br />@end<br /></pre><br />CoreLocationライブラリは別途入れてください。<br />また<a href="https://github.com/stig/json-framework/downloads" target="_blank">ここ</a>から「JSON v2.3.2 (iOS)」をダウンロードして、その中からClassesフォルダを同じプロジェクトファイル内にコピーしておいてください。<br />なおserviceURL = [NSURL URLWithString:@"http://0.0.0.0:3000/location.json"]のドメイン部分は自分なりに。<br />xibも適当にボタンとテキストフィールドを。名称は、それぞれ「logStartButton」「codeTextField」で。<br />わからないときは、「<a href="http://www.amazon.co.jp/gp/product/4797364629/ref=as_li_tf_tl?ie=UTF8&tag=face-do-22&linkCode=as2&camp=247&creative=1211&creativeASIN=4797364629">まるごと学ぶiPhoneアプリ制作教室</a><img src="http://www.assoc-amazon.jp/e/ir?t=face-do-22&l=as2&o=9&a=4797364629" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />」を参考にしてください。<br />サンプルコードが<a href="http://www.sbcr.jp/support/10159.html" target="_blank">ここ</a>にあったりします。<br /><br />次にrailsの方。<br />ApiController<br /><pre name="code" class="ruby"><br />class ApiController < ApplicationController<br /><br /> def post<br /> location = Location.new(params[:api])<br /> respond_to do |format|<br /> if location.save<br /> format.json { head :ok }<br /> else<br /> format.json { render json: location.errors, status: :unprocessable_entity }<br /> end<br /> end<br /> end<br /><br /> def get<br /> @location = Location.where(:identificationCode => params[:identificationCode]).limit(5)<br /><br /> respond_to do |format|<br /> format.json { render json: @location }<br /> end<br /> end<br /><br />end<br /></pre><br />ルーティングとして以下を追加。<br /><pre name="code" class="ruby"><br /> post 'location(.:format)' => 'api#post'<br /> get 'location(.:format)' => 'api#get'<br /></pre><br />データベースに以下のカラムを作る<br />「latitude」<br />「longitude」<br />「time」<br />「identificationCode」<br />で、マイグレして起動して、iPhoneアプリを起動し、ボタンを押せば、1秒ごとにrailsのDBに位置情報とID、時間が登録されていくはずです。<br />ポイントは、jsonデータをpostメソッドで送信するとそれぞれのparams[:項目名]で取得できること。<br />それができれば簡単ではないかと。<br /><br />今回簡易的にするため外のpostメソッドをそのまま受け入れましたが、セキュリティ的には問題あるので、実用にはもうちょい工夫が必要そうです。Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-53126553543970178752011-10-18T13:25:00.001+09:002011-10-18T13:32:21.813+09:00プログラム歴9ヶ月でも1日でサイトが作れる!ハッカソンに参加する3つの理由今年の1月後半からプログラミングを始め、はや9ヶ月。<br />時間をかければ簡単なWEBサービスを作れるところまできましたが、ハッカソンに参加したらなんと1日で(簡単なものとはいえ)WEBサービスを作ることができました。<br />作ったのは<a href="http://www.reblogram.com">reblogram</a>というサービスで、簡単にいうとinstagram上の写真をワンクリックでtumblrにreblogできるサイトです。<br />instagramのPCビューアも兼ねているので、PCでinstagramのTLを眺めつつ、気に入った写真はreblogするという使い方ができます。<br />(本当はスマホ用のデザインもしたかったのですが、時間が足りませんでした。。。)<br /><br />tumblrのAPIとinstagramのAPIを使ったので、非常に作りが簡素化されていますが、自分でもまさか一日で作ることができるとは思いませんでした。<br />そこで、なぜハッカソンならたった一日でもWEBサービスを作ることができるのか、僕なりに気がついたことを3つにまとめました。<br /><br />●不必要なハマリがなくなり、必要なことに集中できる<br />プログラミングを覚えたてのころ、特に独学で勉強している人ほど経験があると思いますが、後から見ると本当にくだらないことではまってしまうことがありますよね?<br />しかしハッカソンなら、まわりにそのことを経験済みの人がいる可能性が高いため、不必要なハマリがなくなります。<br />初心者レベルでハマる程度のことだと、言語に依存するような内容は少ないので、自分の同じ言語の人はいるのか?というのはあまり気にする必要がないと思います。<br />(実際今回は3人でやりましたが、PHP、Ruby、 Object-Cとそれぞれ別の言語でした。それでもお互いのハマリを解決しあえたと思います。)<br /><br />●自分の持ってない知識を活用できる<br />今回reblogramを作るにあたりデザインにはtwitterのBootstrapを利用しました。<br />これがなければデザインまで一日では完成していなかったと思うほど、非常に便利なものでしたが、これは他のメンバーから教えてもらった情報です。<br />ハッカソンでは、問題の解決という側面だけではなく、サービスを作るまでのショートカットの方法も共有しあえるという面でも効果があったと思いました。<br /><br />●集中するしかなくなる<br />これがハッカソンに参加する意味、効果として一番大きいかもしれません。<br />サボりたくても周りではひたすらコードを書いている人しかいないので、自分もサボるわけにはいきませんw<br />食事と一緒に海に休憩しにいった時以外は、ひたすらコードを書くか、詰まったところの相談をしていました。<br />この集中度がなければあったからこその成果だったと思います。<br /><br />●おまけ<br />ただコードをひたすら書くだけでしたが、非常に楽しい体験でした。<br />今回は一旦都内で集合したあと、会場の民宿まで移動したのですが、その移動時間に作るサービスの相談や情報交換などを行えて、移動時間すら有益な時間だったと思います。<br />お試しとして3人くらいで開催したのですが、いい経験だったのでまたやりたいという話をメンバーの人としました。<br />次はもう少しメンバーを増やしてやりたいと思いますので、興味ある方は責任者の<a href="http://twitter.com/#!/masumikawasaki" target="_blank">@masumikawasaki</a>までご連絡ください。<br />(僕じゃないですけど・・・)Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-76906344854296954302011-09-05T23:47:00.001+09:002011-09-05T23:47:54.517+09:00Mac ports からhomebrewへ移行homebrewはmac portsと競合するらしいので、先にmac portsをアンインストールする。<br /><br />へんなところでつまずくと嫌なので、念のためmac portsでインストールしたものをテキストファイルで保存<br />#port installed<br /><br />アンインストール<br /># sudo port -f uninstall installed<br /># sudo rm -rf /opt/local/<br /><br /><br />homebrewのインストール<br />#ruby -e "$(curl -fsSL https://gist.github.com/raw/323731/install_homebrew.rb)"<br /><br />homebrewはgitで更新するらしいのでgitをインストール<br />#brew install git<br /><br />homebrewのアップデート<br />#brew update<br /><br />あとは個別に必要なものをインストールUnknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-11496898146331450742011-09-04T04:34:00.008+09:002011-09-04T04:46:44.725+09:00railsでpaypalを使う方法rails2.3.5の場合です。
<br />ライブラリが用意してあるので、基本的に簡単なのですが、ちょっとはまったので。
<br />
<br />まずはアカウントを用意。
<br /><a href="https://developer.paypal.com/devscr?cmd=_signup-run" target="_blank">sandbox</a>に登録する。
<br />「Create a preconfigured account」で、BuyerとSellerのアカウントをひとつずつ作る。
<br />Buyerの方には残高を入れておくことを忘れないように。
<br />
<br />次にsandbox test siteにsellerのアカウントでログイン。
<br />ProfileからAPI Accessで「API Username」「API Password」「Signature」を取得。
<br />これで準備は完了です。
<br />
<br />ライブラリのインストール。
<br />#sudo gem install activemerchant -v 1.10
<br />わざわざ1.10にしているのは、それ以上だとrails2.3.11以上にしか対応していないから。
<br />
<br />#app/controller/payments_controller.rb
<br /><pre class=”brush:ruby”>
<br />class PaymentsController < ApplicationController
<br /> include ActiveMerchant::Billing
<br /> def index
<br />
<br /> end
<br />
<br /> def confirm
<br /> redirect_to :action => 'index' unless params[:token]
<br />
<br /> details_response = gateway.details_for(params[:token])
<br />
<br /> if !details_response.success?
<br /> @message = details_response.message
<br /> render :action => 'error'
<br /> return
<br /> end
<br />
<br /> @address = details_response.address
<br /> end
<br />
<br /> def complete
<br />
<br />
<br /> purchase = gateway.purchase(100,
<br /> :ip => request.remote_ip,
<br /> :payer_id => params[:payer_id],
<br /> :token => params[:token]
<br /> )
<br />
<br /> if !purchase.success?
<br /> @message = purchase.message
<br /> render :action => 'error'
<br /> return
<br /> end
<br /> end
<br />
<br />
<br /> def checkout
<br /> setup_response = gateway.setup_purchase(100,
<br /> :ip => request.remote_ip,
<br /> :return_url => url_for(:action => 'confirm', :only_path => false),
<br /> :cancel_return_url => url_for(:action => 'index', :only_path => false)
<br /> )
<br /> redirect_to gateway.redirect_url_for(setup_response.token)
<br /> end
<br />
<br /> private
<br /> def gateway
<br /> @gateway ||= PaypalExpressGateway.new(
<br /> :login => 'API Username',
<br /> :password => 'API Password',
<br /> :signature => 'Signature'
<br /> )
<br /> end
<br />
<br />end
<br /></pre>
<br />
<br />#app/paments/index.html.erb
<br /><pre class=”brush:ruby”>
<br />
<br /><h1>Purchase Sprockets</h1>
<br /><p>Thank you for your decision to purchase our sprockets.</p>
<br /><p>Your order total is 100円</p>
<br /><p>
<br /> <%= link_to image_tag('https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif'), :action => 'checkout' %>
<br /></p>
<br /></pre>
<br />
<br />#app/paments/confirm.html.erb
<br /> <pre class=”brush:ruby”>
<br /><h1>Please Confirm Your Payment Details</h1>
<br />
<br /><table>
<br /> <tr><td>Name</td><td><%= @address['name'] %></td></tr>
<br /> <tr><td>Company</td><td><%= @address['company'] %></td></tr>
<br /> <tr><td>Address 1</td><td><%= @address['address1'] %></td></tr>
<br /> <tr><td>Address 2</td><td><%= @address['address2'] %></td></tr>
<br /> <tr><td>City</td><td><%= @address['city'] %></td></tr>
<br /> <tr><td>State</td><td><%= @address['state'] %></td></tr>
<br /> <tr><td>Country</td><td><%= @address['country'] %></td></tr>
<br /> <tr><td>Zip</td><td><%= @address['zip'] %></td></tr>
<br /></table>
<br />
<br /><% form_tag :action => 'complete', :token => params[:token], :payer_id => params[:PayerID] do %>
<br /> <%= submit_tag 'Complete Payment' %>
<br /><% end %>
<br /></pre>
<br />
<br />#app/paments/confirm.html.erb
<br /> <pre class=”brush:ruby”>
<br /> <p>Thank you for your purchase</p>
<br /></pre>
<br />#app/paments/confirm.html.erb
<br /> <pre class=”brush:ruby”>
<br /><h1>Error</h1>
<br /><p>Unfortunately an error occurred: <%= @message %></p>
<br />The confirm.html.erb templates displays the customer's PayPal address and asks them if they want to complete the payment. Displaying the review page represents Integration Point 3a from the Integration guide. This is the customer's opportunity to review the details of their order, change shipping methods, etc. It looks like this:
<br /></pre>
<br />
<br />#config/enviroment.rb
<br /> config.gem "activemerchant"
<br />を追記
<br />
<br />#config/enviroments/development.rb
<br />config.after_initialize do
<br /> ActiveMerchant::Billing::Base.mode = :test
<br /> ActiveMerchant::Billing::PaypalExpressGateway.default_currency = "JPY"
<br />end
<br />を追記
<br />
<br />これでpaypalのテストサイトで課金のテストができます。
<br />本番サーバでやるなら、本番サーバ用にアカウントを用意して、
<br />#config/enviroments/production.rb
<br />config.after_initialize do
<br /> ActiveMerchant::Billing::Base.mode = :production
<br /> ActiveMerchant::Billing::PaypalExpressGateway.default_currency = "JPY"
<br />end
<br />
<br />で、行けるはず。
<br />試してませんが。。。
<br />
<br />テスト環境と本番環境でかなり動作が違うらしい。
<br />日本じゃpaypalアカウント持っている人少ないから、クレジットカードの欄を優先させたいんだけど、どうやるんだろう?
<br />本番環境なら優先されるのかな?
<br />
<br />あと、定期的な支払い請求もできるらしいけど、それもどれかわからず・・・Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-40040513171357269152011-08-05T14:05:00.000+09:002011-08-05T14:08:00.389+09:00rubyでfacebookをいじってみるfacebookアプリに登録して、自分のlikeデータを取得してみます。<br /><br />まずはここから適当にアプリを登録する<br />https://developers.facebook.com/apps<br /><br />で、Access Tokenが必要なので、<br />上部の「アプリ→アプリ名」部分のアプリ名を選択。<br />真ん中くらいにAccess Tokenって欄があるので、そこのリンクをクリックして発行する。<br /><br /><br />次にライブラリのインストール<br />#sudo gem install rest-fraph<br /><br />でこんな感じのものを書く。<br />access_tokenのところは、さっき取得したaccess_tokenを入れてください。<br /><br /><br />require 'rubygems'<br />require 'rest-graph'<br /><br />rg = RestGraph.new(:access_token => 'access_token')<br />like = rg.get('me/likes')<br /><br />like.values.first.each do |f|<br /> puts f['name']<br />end<br /><br /><br />一覧でlikeしたものの名前が出てきます。Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-89538655337887010962011-08-02T23:49:00.001+09:002011-08-02T23:49:47.853+09:00hamlを使ってみる。ruby1.8.7 rails2.3.5 Netbeans6.9.1のケースです。<br /><br />まずはhamlのインストール<br />#sudo gem install haml<br /><br />あとnetbeansを使って開発してるので、専用のプラグインも入れます。<br />ここからプラグインをダウンロード。<br />http://code.google.com/p/postcomment/downloads/detail?name=org-netbeans-modules-haml.nbm&can=2&q=<br /><br />で、Netbeansを起動して、ツール→プラグインからインストール。<br /><br />railsの新規プロジェクトを作成したら、<br />environment.rbに config.gem "haml"<br />を記述。<br /><br />あとは、index.html.hamlみたいなやつを読むようになってくれます。<br /><br />使ってみた雑感としては、IDEが対応してないので、逆に開発速度が遅くなるかも。<br />ただ単体としてみればerbより、記述するコードが少ないので早そう。<br /><br />むしろSassのほうが独立しているし、簡単に導入できるのではないかと思いました。Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-298818705239509590.post-35924671635867538782011-07-17T00:20:00.004+09:002012-02-28T02:04:59.674+09:00face.comのAPIを使って、類似の顔を検索するサービスを作ってみる。このへんで使った技術を使って、実際にサービスを作ってみる。<br /><a href="http://face-do.blogspot.com/2011/07/facecomapi.html">face.comのAPIを使って、似た顔を判別させる方法</a><br /><a href="http://face-do.blogspot.com/2011/06/facecomapiruby.html">face.comのAPIをrubyのライブラリを使って遊んでみる</a><br /><br />今回はface.comにAKB48の顔写真DBを作り、twitterのアイコンがどれだけAK48のメンバーに似てるか、表示させます。<br />DBは予め登録してある前提で。<br /><br />コントローラー<br />class IndexController < ApplicationController<br /><br /> def index<br /> end<br /><br /> def show<br /> require 'face'<br /> require 'open-uri'<br /> require 'uri'<br /> require 'net/http'<br /> @entries = Array.new<br /> http = Net::HTTP.new( 'api.twitter.com', 80 )<br /> req = Net::HTTP::Get.new( "http://api.twitter.com/1/users/profile_image/#{params[:user]}.json?size=original" )<br /> res = http.request( req )<br /> img_url = URI.parse( res['location'] ).to_s<br /><br /> client = Face.get_client(:api_key => '' , :api_secret => '')<br /><br /> data = client.faces_recognize(:urls => img_url , :uids => 'all@akbtter')<br /> photos = data['photos']<br /> photos.each do |photo|<br /> photo['tags'].each do |tags|<br /> unless tags['uids'] == []<br /> confidence = tags['uids'][0]['confidence']<br /> uid = tags['uids'][0]['uid']<br /> member = Member.find_by_uid( uid )<br /><br /> hash = {"name" => member.name, "confidence" => confidence }<br /> @entries << hash<br /> end<br /> end<br /> end<br /> end<br />end<br /><br />ビュー<br />#index/index.html.erb<br /><h1>AKBったー</h1><br />twitterのIDを入力すれば、そのユーザーのアイコンがAKBの誰に似ているか判定してくれます。<br /><br />※現在は神7にのみ対応<br /><% form_tag :action => 'show' do %><br /> <%= text_field_tag 'user' %><br /> <%= submit_tag 'チェック' %><br /><% end %><br /><br /><br />#index/show.html.erb<br /><% unless @entries.count == 0 %><br /> <% @entries.each do |f| %><br /> <%= f["name"] %>に似ています。<br /><br /> 似ている度:<%= f["confidence"] %>%<br /> <% end %><br /><% else %><br /> 似ているメンバーはいません。<br /><% end %><br /><br />マイグレーション<br />class CreateMembers < ActiveRecord::Migration<br /> def self.up<br /> create_table :members do |t|<br /> t.string :name, :uid<br /> t.timestamps<br /> end<br /> end<br /><br /> def self.down<br /> drop_table :members<br /> end<br />end<br /><br />で、デザインとか整えたりすると、こんな感じのサービスになります。<br /><a href="http://akb.heroku.com">http://akb.heroku.com</a>Unknownnoreply@blogger.com0