require と require_relative

Rubyの話。

これまで
require で相対パスを指定することで別ファイルのRuby スクリプトを読み込んでいた。

発生した問題
あるスクリプトを実行したら、別のディレクトリにあるRuby スクリプトに対してloadError が発生した。

エラーメッセージ
D:/Ruby193/lib/ruby/site_ruby/1.9.1/rubygems/[ファイル名].rb:[行番号]:in `require': cannot load such file -- ./[Ruby スクリプト] (LoadError)

原因

parent/scrA.rb
parent/child1/scrB.rb
parent/child2/scrC.rb

が存在するとき。

# scrB.rb
require '../scrA'

でscrB はscrA.rb を読み込んでいる。

# scrA.rb
require './child2/scrC'

でscrA はscrC.rb を読み込んでいる。

この時、scrB.rbを実行すると、カレントディレクトリはchild1 であるので、./child2/scrC.rb は見つからない。

解決法
require_relative を使う。
require_relative は、呼び出したスクリプトの存在するディレクトリから相対パスを辿る。

# scrA.rb
require_relative './child2/scrC'

とすればいい。
しかし、どこから参照されるか分からないスクリプトは基本的にrequire_relative を使ったほうがいいと思われる。

VMware Player 上のOSからホストOS Windows7 との共有フォルダにSubversion で checkout できない件

できなかった。

ホストOS: Windows 7 Proffessional 32bit
ゲストOS: Ubuntu 11.10

やりたかったこと
ゲストOSのUbuntu からホストOS Windows との共有フォルダにソースコードをcheckout する

起きたこと
こんなメッセージが出て、できなかった。

svn: '○○/.svn/tmp/entries' から '○○/.svn/entries' にファイル名を変更できません: 許可がありません

原因
svnクライアントは、

mv .svn/tmp/entries .svn/entries

というコマンドをReadOnlyなファイルに対して実行するようだが、
既存のReadOnlyなファイル名にファイルを上書きするのは、Unixファイルシステムでは可能だが、Windows系のそれだと禁止とのこと。

分かりにくい。

VMware Player を使ってホストOSでWebアプリ開発、ゲストOSでサーバを立てて、ホストOSから閲覧する。

何を言っているかわか(ry

いきさつ
a. VMware Player 上で eclipse 使って開発すると重い。
b. Ubuntu(ゲストOS)はサーバとしてだけ使って、Windows(ホストOS)上で開発すればいいんじゃね?

やりたいこと
a. ホストOSとゲストOSでソースコードを共有する
b. ゲストOSで用意したWebアプリにホストOSのブラウザからアクセスする

環境
Ubuntu 11.10 in VMware Player 4.0.3 on Windows7 Proffesional 32bit

作ったWebアプリの開発言語その他
Ruby 1.9.3
Ruby on Rails 3.2.9


やったこと

1. 二つのOSの共有ディレクトリにソースコードを置く。
仮想マシンの設定で用意した共有ディレクトリに、ソースコードを置く。

2. サーバを立てる。
ゲストOS側からソースコードのあるディレクトリにアクセスし、サーバを立てる。

3. ホストOSのブラウザでアクセスする。
ここで詰まった。
NAT接続だからとホストOSのIPアドレスにアクセスしてもうまくいかない。

ちょっと考えて、ゲストOS側のIPアドレスを調べたら、別のIPが割り振られてた。
ホストOS側でIPアドレスを変えていて、それをホストOSのIPアドレスとしてアクセスしていた。

ゲストOS側のIPアドレスにアクセスしたら解決。めでたし。

ERBのハイフンパーセントの話。

"-%"で検索しても引っかからないんだよね。

ERBの話。

<%= "文字列" %> と
<%= "文字列" -%> の違い。

端的に言うと改行されるかどうかの違い。"-"があると改行がなくなる。

<%= "Hello " %>
World

でも、

<%= "Hello " -%>
World

でも、ブラウザに表示されるのは

Hello World

だけど、HTMLを見てみると

<%= "Hello " %>
World
だと

Hello
World

と改行され、

<%= "Hello " -%>
World
だと

Hello World

と改行されないという違いが出ている。

どうやらこれ、"trim_mode"というらしい。

参考
Ruby On Rails ピチカート街道 - -%> ハイフンパーセントで閉じる -
Rubyist Magazine - 標準添付ライブラリ紹介 【第 10 回】 ERB

deviseでユーザ名でログインできるようにする。

deviseのログインidはデフォルトだとメールアドレスだが、それをユーザ名でログインできるようにしようというお話。

環境: 環境: Ubuntu11.10, RVM1.13.4, Rails3.2.3, devise2.1.2


1. マイグレーションファイルにユーザ名の項目を追加する。

ログイン用のテーブルusersにユーザ名のカラムを加える。
db/migrate/2012(中略)_devise_users_create.rbに以下を追加。

t.string :username, :null => false

また、ユーザ名がかぶると問題なので、以下も追加。

add_index :users, :username, :unique => true


2. テーブルを更新する。

% rake db:migrate

(注: 私の環境だとうまくいかなかったけど、一度rake db:dropしてテーブルを削除してから実行したらうまくいった。)


3. usernameへのアクセスを可能にする。

app/models/user.rbのattr_accessibleの行を以下のように変更。

attr_accessible :email, :password, :password_confirmation, :remember_me, :username

これで、railsアプリケーションでユーザ名を扱えるようになった。


4. usernameを認証キーとして使用できるようにする。

config/initializers/devise.rbの

# config.authentication_keys = [ :email ]

config.authentication_keys = [ :username ]

と改変。(非コメント化して値を変えた)


5. deviseのビューを編集できるようにする。

deviseのビューはデフォルトでは作られていない。

% rails generate devise:view users

を実行し、ビューを編集できるようにする。


6. ログイン画面の改変

app/views/users/sessions/new.html.erbを改変。

<div><%= f.label :email %><br />
<%= f.email_field :email %></div>

<div><%= f.label :username %><br />
<%= f.text_field :username %></div>

にする。


7. サインアップ画面の改変

app/views/users/registrations/new.html.erbに以下を追加。

<div><%= f.label :username %><br />
<%= f.text_field :username %></div>

場所はご自由に。


これで登録、ログインにユーザ名が加わった。
このままだとユーザ名の属性指定ができていないけど、それはまた機会があれば。

参考: ASCIIcasts - “Episode 210 - Deviseのカスタマイズ”

Ruby on Rails: ルーティングがうまくいかない。

Railsでルーティングがうまくいかなくてひっかかった話。

環境: Ubuntu11.10, RVM1.13.4, Rails3.2.3

articlsコントローラ内のcategoryアクションを呼び出そうとしたが、うまくいかない。

取りあえず

% rake routes

で確認してみると、

article  GET    /articles/:id(.:format)                 articles#show
         PUT    /articles/:id(.:format)                 articles#update
         DELETE /articles/:id(.:format)                 articles#destroy
root            /                                       articles#index
category GET    /articles/category/:category(.:format)  articles#category

エラーメッセージを読んでみると、どうやら show アクションが id = category で実行されているのが問題らしい。

調べてみると、ルーティング設定は上から行われるようなので、category のルーティング設定を config/routes.rb のもっと上に書いてあげればよかったようだ。