Kinopyo Blog

プログラマとしてRuby, Rails, iPhone, iPad,Macなどなどと向き合う日々のログポース

Archive for the ‘Ruby’ Category

Ruby URLをエンコード

2011年12月08日
require 'cgi'
CGI.escape(url)
view raw escape_url.rb This Gist brought to you by GitHub.

Rails Append class if condition is true in Haml

2011年11月22日
Append class if condition is true in Haml (with Rails) - Stack Overflow http://t.co/7pyL7pNn

HAMLである条件がtrueの時だけあるclassをタグに追加したい場合


.post{:class => ("gray" unless post.published?)}

Rails asset hostsについて

2011年11月09日

ActionView/Helpers/AssetTagHelper、asset(画像、CSSなど)ホストのチューニングについての勉強メモです。

Gistのmarkdownはembedする時にうまくスタイルをレンダリングしてくれないようです。。。

orz….https://gist.github.com/1350279で見たほうがいいかも知れません。

## asset hostを指定
image_tag("rails.png")のhelper methodで生成するリンクはデフォルトでは同じホストのpublicフォルダを指しています。それを変更したい場合は`config/environments/production.rb`の`ActionController::Base.asset_host`をいじります。

```ruby
ActionController::Base.asset_host = "assets.example.com"
```

```erb
image_tag("rails.png")
# => <img alt="Rails" src="http://assets.example.com/images/rails.png?1230601161" />
```

## asset hostを複数指定
ブラウザが一度に同一サーバには2つのコネクションしかできないそう(これは初めて知りました)で、asset同士のダウンロード完了するのを待たなければなりません。もし複数台のassetサーバがある場合は`assets%d.example.com`を使ってそれをコネクション数を増やせることができます。`%d`が指定されればRailsは0~3の4つの番号を付けて、並行して8つのコネクションができます。

```ruby
ActionController::Base.asset_host = "assets%d.example.com"
```

```erb
image_tag("rails.png")
# => <img alt="Rails" src="http://assets.example.com/images/rails.png?1230601161" />
stylesheet_link_tag("application")
# => <link href="http://assets2.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
```

### カスタマイズ
もっと自分でカスタマイズしたい場合は`source`のprocパラメータを使えます。

```ruby
ActionController::Base.asset_host = Proc.new { |source|
  "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
}
image_tag("rails.png")
# => <img alt="Rails" src="http://assets1.example.com/images/rails.png?1230601161" />
stylesheet_link_tag("application")
# => <link href="http://assets2.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
```

特定のパスで始まるassetを特定のホストに指定する例:
```ruby
ActionController::Base.asset_host = Proc.new { |source|
   if source.starts_with?('/images')
     "http://images.example.com"
   else
     "http://assets.example.com"
   end
 }
```

```erb
image_tag("rails.png")
# => <img alt="Rails" src="http://images.example.com/images/rails.png?1230601161" />
stylesheet_link_tag("application")
# => <link href="http://assets.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
```
さらに`request`の第二パラメータもあります。これでHTTPSの動作も制御できます。

```ruby
ActionController::Base.asset_host = Proc.new { |source, request|
  if request.ssl?
    "#{request.protocol}#{request.host_with_port}"
  else
    "#{request.protocol}assets.example.com"
  end
}
```

## Resources
http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html
view raw gistfile1.md This Gist brought to you by GitHub.

Rails オプション(省略可)local variablesをpartial viewに渡す方法

2011年11月07日

例えば省略可能なフラグみたいなローカル変数をpartial viewに渡した時、そのデフォルト動作をpartial viewでハンドリングしたいですね。

<%= render 'article', :show_author => false %>
<%= render 'article' %>

調べてみたらdefined? local_assigns.has_key?が見つかりましたが、前者のほうはオススメできなさそうです。

Testing using defined? headline will not work. This is an implementation restriction.

http://api.rubyonrails.org/classes/ActionView/Base.html

# http://api.rubyonrails.org/classes/ActionView/Base.html

# If you need to find out whether a certain local variable
# has been assigned a value in a particular render call,
# you need to use the following pattern:

<% unless local_assigns.has_key? :show_author %>
  <% show_author = true %>
<% end %>

<% if show_author %>
  Author: <%= @article.author %>
<% end %>

# Testing using defined? headline will not work. This is an implementation restriction.

view raw solution.erb This Gist brought to you by GitHub.

実際やってみて、defined?でも動けるパターンはありますが、if/unless文で一行にしたらバグりました。なのでやはり local_assigns.has_key?を使いましょう。

# this will work
<% unless defined?(:show_author) %>
  <% show_author = true %>
<% end %>

# NOT work
<% show_author = true unless defined?(:show_author) %>

# this will work
<% show_author = true unless local_assigns.has_key? :show_author %>

Resources

http://stackoverflow.com/questions/238615/defined-method-in-ruby-and-rails

http://api.rubyonrails.org/classes/ActionView/Base.html

Rspec Capybara_webkitを使ってjavascriptをテストする

2011年11月06日

Goal

ゴールと言うか目標はrspecのrequest(integration) testでjavascriptのテストをしたいです。が、いろいろハマってその問題と解決策を時間軸でメモしておきます。

Capybaraについてはある程度知ってる前提です。

javascriptのテストを書く

:js => trueでrspecのintegration testでjavascriptを有効に設定できます。

例:

# in your view erb file
<%= link_to_function "test js", '$(this).html("js works")' %>

# in test spec
it "supports js", :js => true do
  visit tasks_path
  click_link "test js"
  page.should have_content("js works")
end

ただデフォルトではjavascriptをサポートしないので、このspecは失敗します。解決の鍵はcapybara driverというものです。

capybara_webkit driver

なぜcapybara_webkit driver使う

Capybara … currently comes with Rack::Test and Selenium support built in.

By default, Capybara uses the :rack_test driver, which is fast but does not support JavaScript. You can set up a different default driver for your features.

The capybara-webkit driver is for true headless testing. It uses QtWebKit to start a rendering engine process. It can execute JavaScript as well. It is significantly faster than drivers like Selenium since it does not load an entire browser.

https://github.com/jnicklas/capybara

のようにcapybaraは Rack::TestSeleniumのdriverがbuilt-inされて、デフォルトdriverは前者の:rack_testでjavascriptをサポートしないです。Seleniumはサポートしますが、それよりも速いのがcapybara-webkitなのでそれを採用しました。

capybara_webkit driverをインストール

Gemfileにcapybara_webkitを追記、bundle installします。webkitはQTが必要なので、もしそれがないとbundle installで失敗(エラー)します。後はspec_helper.rbにdefault driverをwebkitに設定します。

# webkit-dependency
# if you don't have homebrew installed
/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"
# if you don't have QT installed
brew install qt

# Gemfile, add capybara-webkit
group :test, :development do
  ...
  gem "capybara-webkit"
end

# in Terminal
bundle install

# set default capybara driver to webkit.
# I put this into spec_helper.rb
Capybara.javascript_driver = :webkit

# In RSpec, use the :js => true flag
it "supports js", :js => true do
  ...
end

これで最初のサンプルspecは通るはずです。

データベースと絡んだテスト

上記のままだとデータベースと絡んだテストはまた失敗します。

例:

it "displays tasks", :js => true do
  Task.create!(:name => "foo")
  visit tasks_path
  click_link 'some link'
  page.should have_content("some text")
end

自分で確認してみたら、テスト時に作成したデータはjavascriptのテストで使えないっぽいです。Railscastsの記事によりますとrspecのテストではデータベーストランザクションを使うが、それがselenium或いはwebkitでは使えないそうです。そのためにdatabase_cleanerというgemを使います。

database_cleanerを使う

# in Gemfiile
group :test, :development do
  ...
  gem "database_cleaner"
end

# in Terminal
bundle install

# in spec_helper.rb
RSpec.configure do |config|
  # ...
  config.use_transactional_fixtures = false
  
  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end
end

config.use_transactional_fixturesをfalseにした時点でもうテスト自体は通るはずですが、データはずっとそのまま残ってしまうんです。database_cleanerは名の通りデータベースをテスト前後で綺麗な状態に保つことができます。

これでもう環境面の設定は完了です!

Resources

Rails OmniauthでTwitter認証ログイン後のcallback urlをカスタマイズ

2011年11月05日

目的

OmniauthでTwitterに認証ログイン後、ログイン前と同じページにリダイレクトしたい

方法

# config/application.rb

config.middleware.use 'StoreRedirectTo'

# and make sure you autoload the contents of /lib


# lib/store_redirect_to.rb

class StoreRedirectTo
  def initialize(app)
    @app = app
  end

  def call(env)
    request = Rack::Request.new(env)
    path = request.path
    signin = path.match(%r(^/auth/[^/]+$)) && path != '/auth/failure'
    signout = path == '/users/signout'
    if signin || signout
      redirect = request.params['redirect_to'] || request.referer
      request.session['redirect_to'] = redirect if redirect
    end

    @app.call(env)
  end
end
# after successful sign-in or sign-out
redirect_to session[:redirect_to] || root_path
session[:redirect_to] = nil

libディレクトリのautoloadはRails libディレクトリのファイルをautoloadを参考してください。

解説

redirect_toパラメータ或いはrefererをログイン直前のリクエストから取ってセッションに保存するRack middwareの手法です。そしてsessions_controllerではセッション内に保存されたurlにリダイレクトし、セッションクリアしています。

もちろんTwitter以外のproviderでの認証&ログイン処理にも対応できます。

Rails libディレクトリのファイルをautoload

# application.rb

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

サブディスプレイのautoloadが必要ない場合は一行目だけでOK.

Ruby 1.9.3-p0 をRVMでインストール

2011年11月02日

インストール

rvm get head
rvm reload
rvm install 1.9.3-p0
rvm use 1.9.3
view raw gistfile1.sh This Gist brought to you by GitHub.

リリースノート

http://www.ruby-lang.org/ja/news/2011/10/31/ruby-1-9-3-p0-is-released/

速度

結構速くなったらしいです。

この記事を参考:http://stjhimy.com/posts/24-ruby-1-9-3-freaking-fast-bro

SinatraでStaticなHTMLファイルをrenderするには

2011年10月21日

目的

Sinatraで静的なhtmlファイルをrenderする方法です。

現状

Sinatraでは色々なビューテンプレートをレンダリングできます。Haml、Erb、Sass、Markdown、CoffeeScript…が対応されていますが、HTMLは対応してないようです。html :indexで書いてもダメですね。

Sinatraのビューテンプレート

解決方法

require 'sinatra'

get '/' do
  File.read(File.join('public', 'index.html'))
  # or
  # send_file File.join(settings.public, 'index.html')
end

File.readでファイルとして読み込むことですね。Sinatraはデフォルトの設定だとpublicフォルダ内のものをassetsとするそうです。

でちょっとリファクタリングしてhtml :indexのシンタックスでいけるようにしました。

require "sinatra"

get '/' do
  # File.read(File.join('public', 'index.html'))
  html :index
end

def html(view)
  File.read(File.join('public', "#{view.to_s}.html"))
end

参考

http://stackoverflow.com/questions/2437390/serving-static-files-with-sinatra

ruby: nil? empty? blank? どれも0をチェックしない

2011年10月18日

よくつかうメソッドの nil? empty? blank? のまとめ。

nil? すべてのオブジェクトにある。nilのときにTrueを返す。

empty? 文字の長さが0のとき、配列が空のときにTrueを返す。

blank? railsの拡張。nil, “”, ” “, [], {} のいずれかでTrueを返す。

http://ameblo.jp/ootokage/entry-10314565693.html

素晴らしいまとめですね!ootokageさんに感謝。

PHP使うときはempty(0)でtrueになりますが、上記のメソッドどれも0をチェックしないですね。。.zero?というのメソッドは一応あるようですが。

迷ったらここにいっぱいサンプルがあります。

0.nil? #=> false

0.zero? #= true

0.empty? #=> NoMethodError

0.blank? #=> false

0 == false #=> false

“”.nil? #=> false

“”.zero? #=> NoMethodError

“”.empty? #=> true

“”.blank? #=> true

“” == false #=> false

{}.nil? #=> false

{}.zero? #=> NoMethodError

{}.empty? #=> true

{}.blank? #=> true

{} == false #=> false

[].nil? #=> false

[].zero? #=> NoMethodError

[].empty? #=> true

[].blank? #=> true

[] == false #=> false

nil.nil? #=> true

nil.zero? #=> NoMethodError

nil.empty? #=> NoMethodError

nil.blank? #=> true

nil == false #=> false

false.nil? #=> false

false.zero? #=> NoMethodError

false.empty? #=> NoMethodError

false.blank? #=> true

false == false #=> true

http://underrails.seesaa.net/article/135698039.html