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 のもっと上に書いてあげればよかったようだ。

deviseを使ってログイン処理をしてみる。

ログイン処理を作るのでdeviseのメモ。

Deep valley まとめ版 - RailsでDeviseを使ってみたを参考にやってみる。

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

1. deviseをインストールする

% rvmsudo gem install devise

2. deviseをrailsで使えるようにする。

% rails generate devise:install

このコマンドを実行すると、設定用ファイルが作成される。
さらに、以下のメッセージ。

===============================================================================

Some setup you must do manually if you haven't yet:

1. Ensure you have defined default url options in your environments files. Here
is an example of default_url_options appropriate for a development environment
in config/environments/development.rb:

config.action_mailer.default_url_options = { :host => 'localhost:3000' }

In production, :host should be set to the actual host of your application.

2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:

root :to => "home#index"

3. Ensure you have flash messages in app/views/layouts/application.html.erb.
For example:

<%= notice %>


<%= alert %>

4. If you are deploying Rails 3.1 on Heroku, you may want to set:

config.assets.initialize_on_precompile = false

On config/application.rb forcing your application to not access the DB
or load models when precompiling your assets.

===============================================================================

どうやらいくつか設定が必要なようだ。

3. 手動でdevise用の設定を行う。

  • development.rbに追加。

config/environmets/development.rbに以下の文を追加。

config.action_mailer.default_url_options = { :host => 'localhost:3000' }

  • routes.rbに追加。

deviseではログイン処理を行うと、rootに設定されたページにリダイレクトするようになっている。

config/routes.rbを編集する。なお、homeコントローラとindexアクションが定義されているものとする。

root :to => "home#index"

  • application.html.erbに追加。

app/view/layouts/application.html.erbに以下の文を追加。

<%= notice %>


<%= alert %>

  • 認証用のモデルを作成する。

% rails generate devise user

4. ログイン画面へのリンクを作成する。

app/view/home/index.html.erbに以下の文を追加。

<% if user_signed_in? %>
<%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to "ログイン", new_user_session_path %>
<% end %>

これでログイン画面へのリンクが貼られる。



☆私がはまったところ
先述のように、deviseではログイン処理を行うと、rootに設定されたページにリダイレクトするようになっている。しかし、私の場合はrootの設定を行っていてもそこにリダイレクトされず、localhost:3000にリダイレクトされていた。
調べてみたところ、ルーティングの設定を行っても静的なHTMLページの方が優先されて表示されてしまうとのこと。今回のケースでは「public/index.html」が存在しており、こちらが表示されていた。リネームしたらうまくいった。

参考: ルート(/)へのルーティング設定 - Ruby on Rails入門