#rails #ruby #postgresql #rspec

PostgresSQLでrake specするとNOTICEがいっぱいでるが大変参考になった。

NOTICE: CREATE TABLE will create implicit sequence “peroperos_id_seq” for serial column “peroperos.id” NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index “peroperos_pkey” for table “peroperos” ~略~

の警告をシャットダウンする方法です。

#rails #ruby #rack #troubleshooting

Rails 3.1以前のバージョンなら多分テスト実行時にこういう警告が出ることがあるかもしれません。

gems/rack-1.2.5/lib/rack/utils.rb:16: warning: regexp match /.../n against to UTF-8 string

このうるさい警告を消す方法を紹介します。

解決方法

rspecを使う場合はspec/spec_helper.rbに下記コードを最後に追記してください。

原因

Rack1.3からは解決できたらしいですが、Rails 3.1以前を使うならとりあえずこの方法で回避してもいいかと。 詳しくは:https://github.com/rack/rack/issues/41

#rails #ruby #asset

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

asset hostを指定

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

ActionController::Base.asset_host = "assets.example.com"
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つのコネクションができます。

ActionController::Base.asset_host = "assets%d.example.com"
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パラメータを使えます。

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を特定のホストに指定する例:

ActionController::Base.asset_host = Proc.new { |source|
   if source.starts_with?('/images')
     "http://images.example.com"
   else
     "http://assets.example.com"
   end
 }
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の動作も制御できます。

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

#actionview #rails #ruby #partial

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

調べてみたら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

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

Resources

http://stackoverflow.com/questions/238615/defined-method-in-ruby-and-rails http://api.rubyonrails.org/classes/ActionView/Base.html

#rails #ruby #capybara #rspec #webkit

Goal

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

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

javascriptのテストを書く

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

ただデフォルトでは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.

のように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に設定します。

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

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

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

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

database_cleanerを使う

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

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

Resources

目的

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

方法

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

解説

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

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

#rails #ruby #log

Overview

rails serverで起動する時に盛りだくさんの情報がログに出力されるので、別ファイルで自分がデバッグしたい情報だけをそこに出力する方法です。この方法でtail -f log/custom.logで監視できます

ソースコード

参考

http://robaldred.co.uk/2009/01/custom-log-files-for-your-ruby-on-rails-applications/ http://ianma.wordpress.com/2009/04/08/custom-logging-in-ruby-on-rails/

#rails #ruby #heroku #rails3.1

この前Herokuのドキュメントを見ましたが、まだRails3.0.7しか正式にサポートされているようです。でも実はRails 3.1rcもherokuで実行できますよ。

上記snippetはgistで保管しJavaScriptで表示しています。RSSでご覧の方は見れないと思います。お手数ですが、直接アクセスしてください。

#rails #ruby #rails3.1

Rails3.1.0 beta1をインストールするときにあったトラブルです。

インストール

// 3.1.0 betaに更新
sudo gem install rails --pre

// バージョン確認
rails -v

// ダミープロジェクト作成
rails new railsfoo

// 必要なGemをインストール
cd railsfoo
bundle install

// サーバ起動
rails s

トラブル

ここまで順調でしたが、http://127.0.0.1:3000にアクセスしたときにundefined method `context’ for #<Sprockets::Environment:>のトラブルに会いました。

Sprockets trouble

どうやらこのSprocketsというのがポイントのようです。 ぐぐってみたらgithubでこのようなコメントがありました。

Just to save someone else the 2 minutes waiting for a bundle update sprockets that will fail, beta.2 is required by rails 3.1.0beta1. You want gem ‘sprockets’, ‘2.0.0.beta.2’ in your Gemfile. github https://github.com/rails/rails/issues/453

のようでGemfileに下記を追記し再度bundle update。

gem 'sprockets', '2.0.0.beta.2'

解決〜

rails server running

全文: http://iain.nl/2011/01/cucumber-vs-steak

Also, the natural language is closer to your understanding of the problem you’re trying to solve. When I write in code, my programmer side becomes active. My programmer side is focussed on solutions. But I want to delay the solution as long as I can, until we have a decent understanding of the problem. So by not writing in code, you can focus more on the problem, rather than on the solution.

ここの「ソリューションをディレー」するところに共感しました。 Cucumberでは自然言語で書けるため、実装から離れた視点でいろんな「Problem」にぶつかりやすい!というのが最もの魅力ですね。 時には本当に実装から離れてプロデューサの目でやりたいことをを考えたいです。そうできないと、いつも「ソリューション」だけに力入れて考えて、もっと重要な「目的」を失うかもしれませんと思います。 もしSteakのような実装の観点から書いたテストコードだとnullとかblankとか、書いてるうちに視野がどんどん狭くなりがちかなと。もちろんそういうテストも重要ですが、「そもそもこんな仕様で大丈夫?ここで何をすべきか?」のような問題にぶつかるためには、やはりCucumberのような自然言語が有利ですね。

あ~いつRoRの仕事ができるかなー

#rails #ruby #mac #環境構築

MacにはデフォルトでRubyが入ってそうです。 ターミナルを開いてrails -vを叩いたらバージョン情報が出てきました。

ruby 1.8.7 (2009-06-08 patchlevel 173) *universal-darwin10.0*

そしてRubyだけじゃなくRailsも入ってましてびっくりしました。 すごいですねMacは。。。 て、railsのバージョンもrails -vで確認できますが、 デフォルトのバージョンは古いそうで下記のコマンドでアップグレードできます。

sudo gem update rails

するとこんなログ情報が出ます。

Updating installed gems
Updating rails
WARNING:  Installing to ~/.gem since /Library/Ruby/Gems/1.8 and
	  /usr/bin aren't both writable.
WARNING:  You don't have /Users/zolo/.gem/ruby/1.8/bin in your PATH,
	  gem executables will not run.
Successfully installed activesupport-2.3.8
Successfully installed activerecord-2.3.8
Successfully installed rack-1.1.0
Successfully installed actionpack-2.3.8
Successfully installed actionmailer-2.3.8
Successfully installed activeresource-2.3.8
Successfully installed rails-2.3.8
Gems updated: activesupport, activerecord, rack, actionpack, actionmailer, activeresource, rails
Installing ri documentation for activesupport-2.3.8...
Installing ri documentation for activerecord-2.3.8...
Installing ri documentation for rack-1.1.0...
Installing ri documentation for actionpack-2.3.8...
Installing ri documentation for actionmailer-2.3.8...
Installing ri documentation for activeresource-2.3.8...
Installing ri documentation for rails-2.3.8...
Installing RDoc documentation for activesupport-2.3.8...
Installing RDoc documentation for activerecord-2.3.8...
Installing RDoc documentation for rack-1.1.0...
Installing RDoc documentation for actionpack-2.3.8...
Installing RDoc documentation for actionmailer-2.3.8...
Installing RDoc documentation for activeresource-2.3.8...
Installing RDoc documentation for rails-2.3.8...

多少時間がかかります。 これでMacでのRuby開発の準備は完了です。

更新

gem update railsにsudoを付けないとこんなエラーが出るかも

WARNING:  Installing to ~/.gem since /Library/Ruby/Gems/1.8 and
	  /usr/bin aren't both writable.
WARNING:  You don't have /Users/paku-k/.gem/ruby/1.8/bin in your PATH,
	  gem executables will not run.
ERROR:  Error installing rails:
	bundler requires RubyGems version >= 1.3.6
#rails #uncategorized #font #new

Compass

A Sass-based CSS Meta-Framework that allows you to mix and match any of the following CSS frameworks:

Compass Core Blueprint 960 Susy YUI

New frameworks and extensions are tracked on the wiki as they are created. Other frameworks can be added relatively easily. Create your own!

http://github.com/chriseppstein/compass/tree#readme http://compass-style.org/docs/

Rails Rumble

The Rails Rumble is an annual 48 hour web application development competition in which teams of skilled web application developers get one weekend to design, develop, and deploy the best web property that they can, using the power of Ruby and Rails.

http://railsrumble.com/

Monospaced font

A monospaced font, also called a fixed-pitch or non-proportional font, is a font whose letters and characters each occupy the same amount of horizontal space.1 This contrasts to variable-width fonts, where the letters differ in size to one another. The first monospaced typefaces were designed for typewriters, which could only move the same distance forward with each letter typed. This also meant that monospaced fonts need not be typeset like variable width fonts and were, arguably, easier to deal with.

http://en.wikipedia.org/wiki/Monospaced_font

#linux #rails #ruby #sqlite

経緯

何も考えずにGemfileにsqlite3を定義してbundleを流したらこんなエラーが出ました。

$ gem install sqlite3-ruby
Building native extensions.  This could take a while...
ERROR:  Error installing sqlite3-ruby:
        ERROR: Failed to build gem native extension.

/home/user/.rvm/rubies/ruby-head/bin/ruby extconf.rb
checking for sqlite3.h... no
sqlite3.h is missing. Try 'port install sqlite3 +universal' or 'yum install sqlite3-devel'
###  extconf.rb failed ###
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/home/user/.rvm/rubies/ruby-head/bin/ruby
        --with-sqlite3-dir
        --without-sqlite3-dir
        --with-sqlite3-include
        --without-sqlite3-include=${sqlite3-dir}/include
        --with-sqlite3-lib
        --without-sqlite3-lib=${sqlite3-dir}/lib


Gem files will remain installed in /home/user/.rvm/gems/ruby-head/gems/sqlite3-ruby-1.3.0 for inspection.
Results logged to /home/user/.rvm/gems/ruby-head/gems/sqlite3-ruby-1.3.0/ext/sqlite3/gem_make.out

キーのメッセージは「sqlite3.h is missing. Try ‘port install sqlite3 +universal’ or ‘yum install sqlite3-devel’」なのでそのとおりコマンドを流しましたが、portはそのコマンドがないと、yumはsqlite3-develを見つからないと返事したんです。。。

なのでsqlite本家でソースをダウンロードしビルドしてインストールする必要があります。

sqlite3のインストール

http://www.sqlite.org/download.htmlからsqlite-amalgamation-x.x.x.tar.gz(この記事を書いてる時点では3.7.3)のTarballバージョンのファイルをダウンロードします。上から二番目のリンクです。

$ wget http://www.sqlite.org/sqlite-amalgamation-3.7.3.tar.gz
$ tar vxzf sqlite-amalgamation-3.7.3.tar.gz
$ cd sqlite-amalgamation-3.7.3
$ ./configure --prefix=/usr/local
$ make
$ sudo make install

sqlite-ruby gemのインストール

後は普通にgem installでもいいしbundle installでもOKです。

$ gem install sqlite3-ruby
#rails

This is about how to customize the url to the form like “id + post.title”, which can be simply overriding the* to_param* method in your model class.

Here is the example.

  class Person
    def to_param
      "#{id}-#{name.parameterize}"
    end
  end

  @person = Person.find(1)
  # => #<Person id: 1, name: "Donald E. Knuth">

  <%= link_to(@person.name, person_path(@person)) %>
  # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>

The parameterize is a method that replaces special characters in a string so that it may be used as part of a ‘pretty’ URL. Rails is smart enough to extract this back into the plain id when you access your controller action. You can access the url ‘/person/1-kinopyo’ or ‘/person/1’, both ok.

If you want to know more, here is a good article: http://augustl.heroku.com/blog/styling-rails-urls.

日本語

slugはurlをより綺麗に表示するためのものです。例えばこの記事のpermanent urlは”rails-id-slug-name-in-url”にしています。英語世界になるんですが、これのようにurlを見ただけでそのurl先の内容が大体わかるようにするのがslugです。

この記事ではRailsで”id + post.title”のような形のURLを作る方法を紹介します。

方法

モデルクラス内にto_paramメソッドをオーバーライドするだけです。 例として

  class Person
    def to_param
      "#{id}-#{name.parameterize}"
    end
  end

  #controller
  @person = Person.find(1)
  # => #<Person id: 1, name: "Donald E. Knuth">

  #view
  <%= link_to(@person.name, person_path(@person)) %>
  # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>

上記のようにmodelクラスを修正するだけで、他の影響はないです。URL: ‘/person/1-kinopyo’と’/person/1’はどっちでも使えます。 parameterizeはRailsのビルトインのメソッドでurlに使う文字列に変換してくれるんです。しかし日本語などは完全にブランクに変換するので要注意です。

もしurlを”/person/kinopyo”のようにperson.nameにカスタムしたい場合はこれより少し複雑になります。興味のある方は下記リンク(英語)を参照してください。 http://augustl.heroku.com/blog/styling-rails-urls.

#rails

一つのHelperメソッドを作って、Modelに必須チェックが入ってるプロパティに対して必須マークの”# “を出力します。

まずapplicaton_helperにmark_requiredのメソッドを作ります。第一引数にはオブジェクト、第二引数はそのクラスのプロパティを渡します。

# application_helper.rb
def mark_required(object, attribute)
  "# " if object.class.validators_on(attribute).map(&:class).include? ActiveModel::Validations::PresenceValidator
end

viewのerbには下記のように@userインスタンス変数と:nameを渡します。もしUserモデルに:nameに対して必須バリデーションが存在すれば必須マークが出力されます。

  <div class="field">
    <%= f.label :name %><%=mark_required(@user, :name) %><br />
    <%= f.text_field :name %>
  </div>

参考リンク:http://railscasts.com/episodes/211-validations-in-rails-3

20110704更新

もしhtmlタグも一緒に出力したいときは、タグがエスケープされてしまいます。


module ApplicationHelper
  def mark_required(object, attribute)
    mark = "<span class='require_mark'># </span>"
    mark if object.class.validators_on(attribute).map(&:class).include? ActiveModel::Validations::PresenceValidator
  end
end

  <div class="field">
    <%= f.label :name %><%=raw mark_required(@user, :name) %><br />
    <%= f.text_field :name %>
  </div>

この場合はrawを書けばエスケープされずにちゃんとHTMLタグが出力します。

中文

我们将创建一个Helper方法来输出”# “表示必须项目。 (原谅我这蹩脚的汉语,实在是不知道这些术语用中文该怎么叫)

首先在application_helper里创建一个叫mark_required的方法。他的第一个参数为对象,第二个参数接收的是对象的属性。

# application_helper.rb
def mark_required(object, attribute)
  "# " if object.class.validators_on(attribute).map(&:class).include? ActiveModel::Validations::PresenceValidator
end

然后在View里我们只要把@user和:name传过去即可。如果你的User Model对:name进行了必须验证(presence validator),”# “就会显示出来。

  <div class="field">
    <%= f.label :name %><%= mark_required(@user, :name) %><br />
    <%= f.text_field :name %>
  </div>

链接:http://railscasts.com/episodes/211-validations-in-rails-3

English

Let’s make a helper method that shows a required mark “# “ when the attribute of the object has a presence validator.

First, create a mark_required method in the application_helper, pass the object as 1st parameter, the attribute as the second one.

# application_helper.rb
def mark_required(object, attribute)
  "# " if object.class.validators_on(attribute).map(&:class).include? ActiveModel::Validations::PresenceValidator
end

Then, just call the custom method in the erb view file. In this sample we pass the @user instance variable and the :name attribute symbol. So if your User model has a presence validator on the :name attribute, the required-mark “# “ will show up.

  <div class="field">
    <%= f.label :name %><%= mark_required(@user, :name) %><br />
    <%= f.text_field :name %>
  </div>

I learned from this site:http://railscasts.com/episodes/211-validations-in-rails-3

#rails

RAILS_ENV

現在動作している環境。開発終わって、テスト環境でテストしたい場合、この変数を修正すればOKです。 ‘development’,’test’または’production’があります。  

RAILS_ROOT

ルートフォルダのパスです。

#rails

Railsのvalidateチェックはすばらしいです。 使いかた非常便利だし、機能が強いです。 それでは、一緒に見てみましょう。

validate

validateを使って、カスタマイズのvadidationチェックを定義できます。 例:

def validate
  errors.add(:content, "を入力してください") if content =~ /^(ここに感想を書いてください。|ここに感想を書いてください)$/
end

validates_acceptance_of

チェックボックスがチェックされたかを確認。 チェックされていない場合、エラーが起こリます。

validates_confirmation_of

再入力を確認します。 詳細の使い方は、「validates_confirmation_of の使い方」を参照してください。

validates_exclusion_of

指定した値に含まれていないかをチェックします。 例:

validates_exclusion_of :sex,:in => ['female','male']

validates_inclusion_of

指定した値に含まれているかをチェックします。 validates_exclusion_ofの逆です。 例:

validates_inclusion_of:sex, :in => ['female','male']

validates_format_of

正規表現を使って、値をチェックします。 例:

validates_format_of :code,:with => /^[0-9A-Za-z]/, :message =>"は半角英数字で入力してください。"

validates_length_of

値の長さをチェックします。 例:

validates_length_of :name, :maximum => 30

validates_numericality_of

値は数字かどうかをチェックします。数字ではない場合、エラーを表示します。 例:

validates_numericality_of :code

validates_presence_of

必須値のチェック。値が入力されていない場合、エラーを表示します。 例:

validates_presence_of :code

validates_uniqueness_of

値の重複チェック。DBに既に同じ値が存在した場合、エラーを表示します。 例:

validates_uniqueness_of :id

validates_size_of

validates_length_ofと同じ。

#rails

システムを作る時に、パスワードを2回入力してもらって、確認処理をおこなうことが多いですね。 そんなめんどな仕事には、Railsはvalidates_confirmation_of メソッドを用意してくれました。 それでは、使い方を見てみましょうか。

まず、モデルで以下のチェックを行います。

validates_confirmation_of :password  #カラム名
attr_accessor :password_confirmation #カラム名に_confirmation

そして、関連のビューで、以下の処理を書きます。

= password_field :user, :password
= password_field :user, :password_confirmation

これで、自動的に入力されたパスワードは同じかどういかを確認してくれます。

※attr_accessorは、再入力フィールドの値を保存するための仮想カラムです。

#rails

セッションを使って、データを保存する時、 以下のエラーが表示されました。

Status: 500 Internal Server Error
ActionController::Session::CookieStore::CookieOverflow

原因:Railsのセッションに保存できるデータの長さは4KBしかないです。

保存するデータは4KBをオーバーした場合、CookieOverflowエラーが表示されてしまいます。

解決方法:

セッションデータをDBに保存します。

  • セッションデータを保存用テーブルを作成します。 以下のコマンドを実行します。
rake db:sessions:create
rake db:migrate
  • config/environment.rbで以下の行をコメントアウトします。
config.action_controller.session_store = :active_record_store
  • サーバーを再起動します。

これで、解決です。