<< >>

2007-11-10 優しいRailsの育て方 [長年日記]

[Rails] ActiveScaffold プラグイン

AjaxScaffold までは知ってたけど、これは知らなかった。凄いねこれ。スペジェネでやりたかったことが殆ど実装されているよ。あとは ViewProperty 周りの機能が足りないけど、今からスペジェネを頑張るよりもこっちにそれを入れ込む方が早そうだ。Rails1.2 だとスペジェネの動作が微妙な部分もあるし。てことで、Rails1.2〜の現代では、スペジェネでなくて ActiveScaffold を使うのがよいと思われ。テンションあがったので、一気に調べて舞波本のスペジェネの部分(pp.288-295)を差し替えよう計画。検証や校正をする時間がないと思うので、誤字脱字、疑問点、些細な間違い、ActiveScaffold で知りたい事、本に載せて欲しい内容等、何でもどんどんツッコミお願いします。

ActiveScaffold プラグイン (p.288)

以前は AjaxScaffold と呼ばれていた Scaffold プラグインの後継です。その名の通り Ajax ベースで高機能で見栄えもよいScaffoldです。これだけでCRUD系のアプリケーションとしては十分実用レベルになります。

■ 特徴

  • scaffold 機能
  • Ajax ページおよび通常(非 Ajax)ページとして動作(自動認識)
  • ページとソート機能
  • 検索機能
  • カラムの表示設定
  • ARの関連サポート
  • ビューテンプレートの差替機能

■■ 配布元

http://activescaffold.googlecode.com/svn/tags/active_scaffold

■■ 準備

まず、プラグインをインストールします。css, js 等のリソースが public にコピーされますので、svn co ではなく install コマンドを利用して下さい。

./script/plugin install http://activescaffold.googlecode.com/svn/tags/active_scaffold

次に、コピーした css,js 等を読み込む設定を、レイアウトまたは利用するビューテンプレートに記述します。

<%= javascript_include_tag :defaults %>
<%= active_scaffold_includes %>

■■ scaffold 機能 (p.289)

まずは、オリジナルの scaffold の代用として使ってみましょう。ここではユーザ情報(Userモデル)を管理する UserController を想定します。コントローラの定義で、scaffold の代わりに active_scaffold と記述してみて下さい。

▼コード : UserController 定義

class UserController < ApplicationController
  active_scaffold :user
end

ページへアクセスすると、以下のような画面が現れます。

1.jpg

右側には各レコードの操作リンクが、右上には検索と新規作成のリンクが準備されています。見栄えのよい上に、これらは全てAjaxで動作します。

■■ ページ機能 (p.289)

ページ機能もデフォルトで準備されています。このままではわかり辛いので、1ページあたりの表示件数を2にしてみましょう。ActiveScaffold の設定を変更するには、コントローラ内の定義部分にブロックを追加します。設定には、コントローラ内で共通な「グローバル設定」と各アクション毎の「ローカル設定」の2種類があります。

  active_scaffold :user do |config|
    config.xxx = ...      # グローバルな設定
    config.list.xxx = ... # ローカル(listアクション)用の設定
    config.show.xxx = ... # ローカル(lhowアクション)用の設定
  end

リスト表示は "list" アクションですので config.list に対する設定になります。

▼コード : ページ化とソートの設定

  active_scaffold :user do |config|
    config.list.per_page = 2
    config.list.sorting = {:name => :asc }
  end

この設定では、2行目ではデフォルトのソート順序を指定しています。

2.jpg

2件ずつページ化され、ソートで指定したカラムが色付けされました。ページリンクや、カラムの見出し部分のソートリンクも全て Ajax です。

■■ 設定と日本語化 (pp.290-291)

グローバル設定(config 直下の設定)は全アクションへのデフォルト設定となり、ローカル設定は指定したアクションにのみ影響を与える設定になります。

▼表 : グローバル・ローカル共通設定

名前説明
label左上のモデル名String
columns表示するカラムを指定Array

また、columns の各要素に対して、さらに以下の設定が可能です。

▼表 : カラム用の設定

名前説明
labelカラム名String
description補足説明(編集時)String
required必須項目true|false
ui_type関連の選択設定:crud|:select
search_sqlSQLの条件節true|String

これらの設定を元に日本語化してみましょう。

▼コード : 日本語化と表示カラムの設定

config.label = "ユーザ"
config.columns = [:name, :birthday]
config.columns[:name].label = "名前"
config.columns[:name].required = true
config.columns[:birthday].label = "誕生日"
config.columns[:birthday].description = "西暦です"

3.jpg

グローバル設定ですので、「Edit」画面にも反映されています。また、name カラムの required と birthday カラムの description の設定も反映されています(補足1)。

  1. 編集注:フットノートに以下を追加
  2. (補足1) css に ".active-scaffold .required label {color:red;}" を追加しています

4.jpg

ActiveScaffold ではローカライズ機能としてラベル系は全て Object#as_(string) を通すことになっていますので、残りの部分の日本語化はそれを利用します。以下のコードを config/environment.rb の最後に追加して、その影響範囲を確認してみましょう。

▼コード : ActiveScaffoldのローカライズ機能の確認

class Object
  def as_(string, *args)
    "[#{string}]"
  end
end

5.jpg

日本語化したい部分が全て被覆されてますね。後は自分で好きなように置換するだけで日本語化が完了です。もし、GetText 等のローカライザを使っていれば、"as_" をそのまま委譲するのもよいでしょう。

  1. 編集注: 以下をフットノートに入れる
  2. GetText の使用例 http://dev.rakusui.jp/diary/?date=20071109
  3. 日本語化の例 http://d.hatena.ne.jp/urekat/20071110/

■■ 表示設定 (p.292)

表示内容を変更する場合は、ヘルパにメソッドを追加します。

▼表 : 表示内容とメソッド

表示箇所参照メソッド
カラム表示(カラム名)_column
フォーム(カラム名)_form_column

▼コード : 誕生日(birthday)をYYYYMMDD形式に

module UserHelper
  def birthday_column(record)
    record[:birthday].strftime("%Y-%m-%d")
  end

  def birthday_form_column(record, name)
    input(:record, :birthday, :name=>name, :order=>[:year,:month,:day], :use_month_numbers=>true, :start_year=>1970)
  end

6.jpg

■■ 関連設定 (p.293)

has_one や has_many といった関連にも対応しています。デフォルトでlistアクションに追加されていますが、カラム名にARの関連名を指定することで、他の実カラム同様に表示項目として扱うことができます。

▼コード : user の所属情報を追加(:companyは関連名)

config.columns = [:name, :birthday, :company]
config.columns[:company].label = "所属"

第一章で解説したように、関連名(:company)で参照されるものは AR オブジェクトです。ActiveScaffold はその表示名として、同オブジェクトに対して以下の順序でメソッドサーチを行います。

to_labelnamelabeltitleto_s

▼コード : Company クラスに表示用メソッドを追加

class Company < ActiveRecord::Base
  has_many :users
  def to_label
    "(#{kind})#{name}"
  end

7.jpg

編集時には自動的に、関連先がプルダウンで選択できるようになっています。デフォルトでは新規登録も可能になっていまので、望まない場合は ui_type を :select にして下さい。

▼コード : 所属の新規登録を禁止する

config.columns[:company].ui_type = :select

8.jpg

■■ 検索設定 (p.294)

検索は現在のところ、テキスト検索のみです。カラムを指定した絞込み検索もできませんが、検索対象にカラムを追加することは可能です。(デフォルトでは文字列カラムだけが検索対象になっています)

▼コード : 誕生日を文字列検索に加える

config.search.columns << :birthday
config.columns[:birthday].search_sql = 'birthday'

9.jpg

この場合、以下のような条件節が作成されます。

LOWER(users."name") LIKE '%1994%' OR LOWER(birthday) LIKE '%1994%'

関連先を検索に含めたい場合は、search_sql にテーブル名まで考慮した部分クエリを記述します。

▼コード : 関連先の所属名称を検索に含める

config.search.columns << :company
config.columns[:company].search_sql = 'companies.name'

10.jpg

空白で区切ると&検索になります。デフォルトでは "LIKE" を用いた部分一致検索になります。"=" による一致検索を行う場合は "config.search.full_text_search" の値を false にして下さい。

■■ セキュリティ設定 (p.295)

Edit や Delete 等のリンクを望まない場合は、グローバル設定の actions から削除します。

config.actions.exclude :update, :delete

(※ Edit リンク用のアクション名は :edit でなくて :update が正解です(修正:20071213))

アクション設定とリンク (追加:20071214)

動作アクション名影響箇所
一覧:listlist アクション
参照:show一覧の右側の Show リンク、および show アクション
修正:update一覧の右側の Edit リンク、および edit, update アクション
削除:delete一覧の右側の Delete リンク、および delete アクション
作成:create右上の Create リンク、および create アクション
検索:search右上の Search リンク、および search アクション

■ ビューテンプレートの差し替え

また、テンプレートの継承機能を利用することで、テンプレート自体を置き換える方法もあります。

▼表 : テンプレートの参照順位

順位配置場所
1app/views/xxx/ (※ 実行中のコントローラ用のビューフォルダ)
2app/views/active_scaffold_overrides/
3vendor/plugins/active_scaffold/frontends/default/views/

システム全体に反映させたい場合は2に、コントローラ毎に変更したい場合は1に配置します。

■ アクション単位のセキュリティ設定

コントローラの #{action_name}_authorized? メソッドを定義することで、各アクションレベルでの利用設定が可能です。

class UserController < ApplicationController
  def delete_authorized?
    request.remote_ip == '127.0.0.1'
  end

■ リソース単位のセキュリティ設定

モデルの authorized_for? メソッドを定義することで、特定のデータだけ保護することが可能です。

class Service
  def authorized_for?(options = {})
    not (options[:action] == :delete and port < 1024)
  end

"authorized_for_#{crud_action}?" で定義することも可能です。

■ 利用者単位のセキュリティ設定

モデルの current_user メソッドによって、コントローラ実行中の(ログインしている)ユーザ情報を取得可能です。前提として、コントローラの current_user メソッドでそのログイン情報を返す設定が必要ですが、acts_as_authenticated などと親和性が高いです。

class Company
  def authorized_for_delete?(options = {})
    current_user.login == 'admin'
  end

SEO: active_scaffold

本日のツッコミ(全25件) [ツッコミを入れる]
_ shachi (2007-11-09 20:04)

大体さくっと日本語化できる感じですかねぇ。<br>最初から、ではなくて途中でカラム追加とかすると、崩れるとかそういうのは無さそう??

_ 舞波 (2007-11-09 20:13)

基本的に localization も考えられてるぽいので大丈夫かと。<br>ラベル系は "as_(xxx)" で参照されてるので、GetText との親和性も高し。<br><br>class Object<br> def as_(string, *args)<br> _(string, ` *args)<br> end<br>end<br><br>generator ではないのでカラムの変化にも強いはず。

_ inoue (2007-11-09 21:45)

とっても雑ですが、ActiveScaffoldのWikiにあるGetTextを使った場合のやり方を訳してみました。というか、GetTextのルールにあわせてカラム名を書き換えるよう、メソッドを書き換えたのは私ですがw<br>ttp://dev.rakusui.jp/diary/?date=20071109<br>何かの参考に。

_ 舞波 (2007-11-10 05:37)

貢献者かよー!inoue乙!!<br>ページの都合で GetText の詳細は書かないので、↑のURLをそのまま書くかも。<br>というか、まだ GetText 使ったことないので書けなかったり。<br>このまま触らずに生き抜いてみせる!

_ takeru (2007-11-10 11:53)

もともとのUI(CreateとかNewとか)を日本語にするテーブルを作ってます。<br>GetTextなしです。<br>http://d.hatena.ne.jp/urekat/20071110/1194662786

_ 舞波 (2007-11-12 22:27)

GetText 使ってない派なので力技のこういうの好きです。助かります。<br>もう編集に原稿出しちゃってるのであれだけど、修正する機会があったら追加しちゃうかも。<br>そのときはよろしく!

_ hiroshi (2007-11-13 15:00)

listで"Create New"をクリックすると500エラーが出てしまいます.<br>ActionView::TemplateError (wrong number of arguments (0 for 1)) on line #7 of vendor/plugins/active_scaffold/frontends/default/views/_form_attribute.rhtml:<br>とのことですが,皆さん出ませんよね?<br>Rails 1.2.5です

_ hiroshi (2007-11-13 23:49)

解決しました.<br>ActiveRecordのカラム名にattributeを使っていたからでした.<br>http://wota.jp/ac/?date=20070925#p01<br>http://lists.rubyonrails.org/pipermail/rails/2006-May/038922.html<br>が参考になりました.失礼しました.

_ 舞波 (2007-11-14 03:35)

あぁ、ありがちだ。予約語がカラム名に使われた場合、ARが例外を出してくれると親切なんですけどねぇ。

_ yamaz (2007-11-16 00:27)

ui_typeで:crudって指定できますか?手元で試した限りではできなかったです.

_ 舞波 (2007-11-16 08:30)

:crud は指定するというよりデフォルト値。:select を指定すると選択のみのUIになる

_ papi2 (2007-11-28 18:37)

ActiveScaffoldを探してここにきましたが、、、ツッコミどころが多すぎるが、とりあえず2007-11-10の範囲内でつっこみます。<br>まずActiveScaffoldの最初の画面をだすところからしてここに書いてある情報だけではできませんでした。<br>>次に、コピーした css,js 等を読み込む設定を、レイアウトまたは利用するビューテンプレートに記述します。<br>><%= javascript_include_tag :defaults %><br>><%= active_scaffold_includes %><br><br>たしかにこれはいろんな方法はありそうですが、以下のような..\app\views\layouts\activescaffold.rhtmlを自分でつくり<br><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"<br>"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><br><html><br><head><br><title>My Application</title><br><%= javascript_include_tag :defaults %><br><%= active_scaffold_includes %><br></head><br><body><br><%= yield %><br></body><br></html><br>かつ、..\app\controllers\(プロジェクト)_controller.rbを<br>class (プロジェクト)Controller < ApplicationController<br> active_scaffold :asuser do |config|<br> end<br><br> layout "activescaffold"<br>end<br>としてやっとでました。<br><br>本「Ruby on Rails入門優しいRailsの育て方」もかってみましたが、ここも本もそうですが変更すべきファイルがなんなのかどれも書いてないといのはどうかと思います。<br><br>そして、わからないのは■■ 関連設定 (p.293)の部分。<br>Company クラスに表示用メソッドを追加 のファイル名はあいからわず書いてないし、最悪なのはプルダウンででるはずの(有)ぴかぴか、(個)みかん、(株)ほのぼのをどこにセットするのか書いてない!<br>本で使っているスペジェネ(http://wota.jp/svn/rails/plugins/branches/stable/special)であれば見当はつくが、たぶんここではActiveScaffoldしか使っていないはずで、どこなんでしょうね?<br>それとたぶんDBにcompanyを項目追加しなければならないはず。。。<br>というか使うDBの構造がはっきり書いてないというのは???<br>本やWebをみる人間が自分と同じ環境、同じレベルであるなんて、、、ありえん。

_ 舞波 (2007-12-04 05:05)

確かに全体的に説明不足ですね。特に今回は既存部分の差し替えのためにページ制限というのが大きいため、さらに説明が不足してる気がします(自分でも)。レイアウトやビューの指定方法に関しては、プラグインより前の章で説明しているのでなんとかなるかな、と期待してます。<br><br>あと、モデルのDBスキーマも入れたいのですが、それを入れるとActiveScaffoldの機能を2個ぐらい省略しないといけなくなるので、割愛してしました。多機能なこのプラグインの色んな機能を1つでも多く紹介したかったので。ただ本全体の流れとして、本の内容通りにやってもらうというより、こういう機能があるよ、というリファレンス的な方向性になってる節はあります(ソースコードのCD付属とかないですし)。<br><br>関連は Company has many users というヒントがあるものの、確かに不親切ですね。プルダウンの項目は関連先のレコードの内容の見出し(to_label)がそのまま自動的に現れます。この辺は次の増刷の機会があれば、もう少し Rails 初学者に優しい内容になるように書き足してみたいと思います。的確なご指摘、ありがとうございます。

_ dola (2007-12-06 23:46)

1.1.0 RC1が出ましたが、1.1の情報は盛り込めそうですか?<br>http://activescaffold.com/2007/12/4/1-1-0-release-candidate-1

_ suna (2007-12-14 00:21)

config.actions.exclude :edit, :delete<br>は :editではなくて :update ではないですか?

_ 舞波 (2007-12-14 06:21)

>>dola<br>1.1で結構変わってる部分がありますね。入稿が終わってしまっているので追加は無理ですが、次の増刷の機会があったらまた最新情報を入れてみようと思います。<br><br>>>suna<br>あぁ、正解!てことで、Web本文を修正しました。本の方も正誤表に追加しておきます。ご指摘感謝です!

_ suna (2007-12-14 09:34)

conf.actions.exclude :delete, :show, :create, :update, :search<br><br>ついでに全部舞波さんのところに書いてあると今からやる人は楽かも^^

_ 舞波 (2007-12-15 08:41)

たしかにー。とりあえず一覧を追加しました。

_ den (2007-12-16 17:05)

class Category < ActiveRecord::Base<br> belongs_to :parent, :class_name => 'Category', :foreign_key => 'parent_id'<br> has_many :children, :class_name => 'Category', :foreign_key => 'parent_id'<br>end<br><br>やったー自己参照できたよー<br>と、思ったら親カテゴリ→子カテゴリと開いて子を追加すると表示が乱れてしまいました<br>具体的には、listに親カテゴリを表示させてたら、そこだけ空白になるらしく、トルツメ状態に。。。<br>Rails2.0 + ActiveScaffold1.1な環境がいけないのかしら?

_ 舞波 (2007-12-17 11:01)

まずは Rails1.2 + ActiveScaffold1.1 で試した方がよいよね。問題の切り分け的に。なんとなく、simply_helpful 的な DOM ID の振り方をしていて、同一のレコードを操作するときに DOM 参照に失敗、だと推測。(完全に脳内のみで)

_ den (2007-12-17 21:06)

助言ありがとうございます〜。<br>とりあえずRails1.2で試してみますた。<br>結果…<br><br>id;parent_id;name<br>5;6;"きれいなカテゴリ"<br>6;5;"きれいなジャイアン"<br><br>これは…循環参照とでも言うのか!?<br>2.0のときは、データそのものは正しく入っていたので退化してますね。<br>単純に指定の問題くさいので、もう少しModelをごにょごにょしてみます。<br><br>どうでもいいですが、2.0を入れた後でどうやって1.X系でrailsコマンドを打つかで小一時間悩みました。。。

_ (2008-01-16 18:47)

Postgresでカラムタイプをビットで扱っている項目が、listでは値の表示ができているが、EditやCreat時にinputフィールドが表示されないです。解決方法がわかる方いませんか?

_ やぐち (2008-02-08 12:08)

自己参照のUpdate画面とかどう制御するのか分からないです。has_manyとかあると一括りにされてしまうし。。

_ さわだ (2008-02-08 20:57)

ずーっと過去の記事から追っかけて勉強しております。<br>ありがとうございます。<br><br>http://d.hatena.ne.jp/d_sawada/20080208/1202471234

_ ようた (2008-05-21 14:37)

参考にしております。現在、ActiveScaffoldを試しているのですが、<br>データベースのカラムにない項目をlistのカラムとして追加する方法はありますか?<br>つまり、データベースには、誕生日を登録するようにしていて、listには<br>誕生日と年齢を表示させるという感じです。<br>もちろん、helperにメソッド定義して年齢を本来誕生日のカラムに表示させるのは<br>大丈夫なのですが、別のカラムとして(データベースには登録がないのに)listに<br>表示させたいという意味です。<br>アドバイスお願いします。<br><br>ようた