link_to、url_forでアンカーリンクを作る

INDEX PAGE


例えば「http://hoge/hogehoge/index#fuga」というような
アンカーリンクを作成したいときに
Railsでどう書けばよいのかという話しです。

link_to、url_forのソースを読めばわかりますが、
下記のように書くとそういうURLが出力されます。

 <%= link_to 'ほげ', :controller => '/hogehoge', :action => 'index', :anchor => 'fuga' %>

url_forも基本的には同じように書けば同じように使えます。

ERBの中でも、controllerの中でも同じように利用できました。

INDEX PAGE

Railsでシステムカラムを用意する


INDEX PAGE


Railsでシステムカラムを用意する


業務系のシステムでは、システムカラムなるものを用意している場合が多いです。
良く見られるのはこんなカラム。


・作成日時:レコードを作製した日時
・作成ユーザーID:レコードを作製したシステム上のユーザーID
・作成プログラムID:レコードを作製したプログラムID
・作成IPアドレス:レコードを作製したクライアントのIPアドレス
・作成MACアドレス:レコードを作製したクライアントのMACアドレス
・更新日時:レコードを更新した日時
・更新ユーザーID:レコードを更新したシステム上のユーザーID
・更新プログラムID:レコードを更新したプログラムID
・更新IPアドレス:レコードを更新したクライアントのIPアドレス
・更新MACアドレス:レコードを更新したクライアントのMACアドレス
・削除日時:レコードを削除した日時
・削除ユーザーID:レコードを削除したシステム上のユーザーID
・削除プログラムID:レコードを削除したプログラムID
・削除IPアドレス:レコードを削除したクライアントのIPアドレス
・削除MACアドレス:レコードを削除したクライアントのMACアドレス
・削除フラグ:レコードが論理削除状態にあるかどうかを表すフラグ


もちろん、こんなに沢山あるとわけがわからなくなるし
データ量も多くなるので、必要に応じてまとめたり削除したりします。
なお、削除XXXというのは、論理削除を行う場合に必要なカラムです。
物理削除を行うシステムでは必要ないです。


さて、Railsではこの一部のカラムについては
自動で設定してくれる機能を持っています。


作成日付:created_at
更新日付:created_at
作成日:created_on
更新日:created_on


これらのカラムについては
テーブルに作成しておくとActiveRecordの機能として
データを設定してくれます。



また、論理削除機能を実装するような場合には
論理削除用のプラグインがでているのでこれを使えばよいです。
acts_as_paranoidというプラグインが有名なようです。
下記のブログが参考になりました。
http://d.hatena.ne.jp/fujisan3776/20080912/1221234453


この場合も、プラグインを導入して
対応するテーブルに


削除日付:deleted_at


というカラムを追加して
モデルクラスをちょっといじるだけで対応できるようです。


上で書いたような、これ以外のシステムカラムについては
個別に実装する必要がありますが、
かなりすっきりシステムカラムを実装することができます。


また、後からシステムカラムを追加したいという場合要件にも対応可能となります。



INDEX PAGE

ERBを部品化する

INDEX PAGE


ERBを部品化する


以前、HTMLソースをINCLUDEする方法を開発してみましたが
静的なHtmlをインクルードする
今回はERBをインクルードする方法です。

入力フォームや、エラー表示の出力を行う為に、ERBの中で

<%= render :partial => 'form', :locals => { :form => form } %>

こんな記述をします。
すると"_form.html.erb"というファイルが読み込まれて
登録画面と更新画面でフォームを共通利用できたりします。

このような"render :partial"は上の例で言うと、フォームの名称など
外部からパラメーターを渡したい時に利用する方法です。


一方、例えば画面ヘッタ・フッタ、ログインバナーのような
様々な画面で利用されるような画面部品を呼び出したいような場合には
ERBのなかで下記のように記述します。

<%= render :file => '/hoge/header' %>

"app/views/hoge/header.html.erb"を画面のその箇所に取り込んでくれます。
注意点としては、この画面で必要とするコントローラー処理は
呼び出した画面のコントローラー処理に書いておく必要があります。


そこらへんは、かなりダサいので
是非ERBを取り込んだらコントローラー処理も取り込まれるような
そんな仕組みが作れればなぁと思っていますが
そんなやり方ってご存知のかたいれば教えていただけると助かります。


INDEX PAGE

日本語の文字列を部分抽出

INDEX PAGE

日本語の文字列を部分抽出


RubyのStringには

str[0,10]

というように、文字列を切り取る関数が存在します。
しかし、この関数はマルチバイト文字には対応していないので
日本語フォントを切り取る時には運が悪いと一番最後の文字で文字化けを起こしてしまいます。

というわけで、今回は日本語の文字を文字数で切り取る方法を作りました。
まずは、日本語文字数の数える関数を作ってみます。

def jp_chr_num(strng)

 jp_strng_chrs = Array.new
 jp_strng_chrs = strng.split(//)

 jp_chr_num = jp_strng_chrs.length

 return jp_chr_num

end

このように、文字列を"//"でsplitすることで
文字を日本語の文字単位で分割することができます。

さらに、これを応用して
指定した開始位置から、指定した文字数分文字を取り出すような関数が下記の関数です。

def cut_strng(strng, cut_num, strt_pnt = 0)

 if cut_num == nil || cut_num == 0 then
  return ''
 else
  end_pnt = strt_pnt + cut_num
 end

 if end_pnt >= jp_chr_num(strng) then
  end_pnt = jp_chr_num(strng)-1
 end

 if strt_pnt > end_pnt then
  return ''
 end

 strng_chrs = Array.new

 strng_chrs = strng.split(//)

 cut_strng = ''

 strt_pnt.upto(end_pnt) do |x|
  cut_strng += strng_chrs[x]
 end

 return cut_strng

end

一旦、配列に格納して
後はLoopを使いながら文字を切り出していきます。
これで、マルチバイト文字にも対応して
文字数で文字列の切り出しを行うことが可能です。


INDEX PAGE

戻るボタンの実装方法

INDEX PAGE


戻るボタンの実装方法


戻るボタンの実装方法は何がただしいのかということを悩みました。
Webでは一般的にどういう方法が正しいのでしょうか?


①HTTP Requestから"REQUEST_URI"を取得して、セッションに詰め込む
 Rubyでやる場合にはApplicationControllerのbefore_filterで
 このリクエストパラメーターをセッションにキュー配列を作って詰め込んで行き
 戻るボタンではこの値を利用する。
 ↓
 欠点
  ・自分のサイト以外にはもどれない。
  ・ドメインがまたがるサイトに戻ることが難しい
  ・flashなどの非同期通信に間違って戻ってしまう
  ・実装がメンドクサイ


②HTTP Requestから"HTTP_REFERER"を取得して、ここにリンクする

 < input type=button alt="ほげほげ" onclick="location.href='#{request['HTTP_REFERER']}'" / >

 かなりシンプルにかけるようになりました。
 自分のサイト以外にはももどれますし
 ドメインがまたがるサイトにも戻れます。
 ↓
 欠点
  ・flashなどの非同期通信に間違って戻ってしまう
  ・たまにrequest['HTTP_REFERER']が取得できない


JavaScriptのhistorybackを利用する

 < input type=button alt='戻る' onclick='history.back();' / >

 とっても簡単にかけて素敵な感じです。
 ↓
 欠点
  ・Javascriptが使えないブラウザに対応しない


というわけで、現状③が一番よいなと思っていますが
ほんとのところ何かもっと素敵な方法はないのでしょうか?


INDEX PAGE

FireFoxでActionController::InvalidAuthenticityToken

INDEX PAGE

FireFoxActionController::InvalidAuthenticityToken


Rails2.0移行ではデフォルトでセッションがCookieとなったことから
CSRF対策がデフォルトで行われています。
get以外のリクエストについて、チェックを行っています。


具体的には"form_for"メソットがauthenticity_tokenというhiddenの情報をHTMLに生成し
こちらをチェックすることによって、正しいクライアントからのリクエストであることを確認しています。


この時に、authenticity_tokenについては
http://d.hatena.ne.jp/zariganitosh/20080207/1202373997
こちらのページに詳しく書いてありましたので参考にしてほしいのです。


そして、本題ですが
ApplicationControllerにおいて

class ApplicationController < ActionController::Base

protect_from_forgery #:secret => 'b80465322633a10f76a0e67dc7bfde1f'

この"secret"の後ろの気になるコメントを取ってみると
何が発生するのかと試してみたところ
IE7では問題なく実行できたのですが、
FireFoxにおいて"ActionController::InvalidAuthenticityToken"が発生しました。


正直原因までは良くわからないのですが
この値が指定されていると"authenticity_token"にこの値が指定され
ない場合はcookie_idが使用されるようなのですが
前者はセキュリティレベルが低いということでFireFoxではNGなのかなと?
へ、でもそんなことあるの?


と思った状態です。


もし詳しい方がいたら教えてください。


INDEX PAGE

ドメインの異なるサイトでセッションを共有する

INDEX PAGE

ドメインの異なるサイトでセッションを共有する


Railsの1.2移行では、セッションはデフォルトではCookieを使用しているので
サーバーが分散していてもセッション共有することができます。

※携帯サイトなどでは方式を検討する必要がありますが。

さてー実際には一つのサイトだけど
サイトの趣旨によってドメインを分割しているということもあると思います。

http://a.xxxx.co.jp/hoge.html
http://b.xxxx.co.jp/hoge.html
http://c.xxxx.co.jp/hoge.html

どれかでログインした情報を全てで利用したいなどです。

TOMCATなどでは、ドメインが異なるとセッションの共有は不能でしたが
Railsでは設定次第では可能なようです。

config/enviroments.rbにて45行目付近に

 config.action_controller.session = {
  :session_key => '_hoge_session',
  :secret  => 'e6531e28b332542b22beede1a848a83b487'
 }

この記述を下のように追記すると

 config.action_controller.session = {
  :session_domain => 'xxxx.co.jp',
  :session_key => '_hoge_session',
  :secret  => 'e6531e28b332542b22beede1a848a83b487'
 }

このドメインの間でセッションを共有利用でき増した。


HTTPSのサイトとの間に関しても

 config.action_controller.session = {
  :session_secure => false,
  :session_domain => 'xxxx.co.jp',
  :session_key => '_hoge_session',
  :secret  => 'e6531e28b332542b22beede1a848a83b487'
}

この用に記述することでセッションを共有できますが
セキュリティー的によろしくないので、別途対応を実装することが推奨されます。

INDEX PAGE