ラベル Rails の投稿を表示しています。 すべての投稿を表示
ラベル Rails の投稿を表示しています。 すべての投稿を表示

2011年5月12日木曜日

ruby の boolean きもい

TrueClass | FalseClass の親クラスBoolClass(仮)が欲しい! on Rubyにも書かれているが、マジきもい。

チェックボックスの値が、'true' という文字列かどうかを判定して boolean として変数に保存していたのだが、if 文の条件分岐が正しく動作しない

@hoge[:fuga] = (params[:fuga] == 'true');
if not @hoge[:fuga]
  # 常に true で評価されてた。アホけ?
end

マジきもい。

2010年12月17日金曜日

railsぼやっきー

 くっそー、ActiveRecord が初期化される前に Controller のメソッドがコールされやがる。
なんじゃこれ?
 で、レコードの代わりに、ご丁寧にも、なんかわからんオブジェクトが渡されやがる・・・
そして、そいつが
warning: Object#id will be deprecated; use Object#object_id
なんて、わけのわからん警告を出して、レコードのIDの代わりに、オブジェクトのIDを代入して、颯爽と風と共に去りぬ。
もう、わけわからん・・・。

追記:ちくしょー、アクティブレコードのオブジェクトじゃなくて、ただの配列になってるやん・・・まぬけ過ぎ・・・はやく気づけよ・・・。スクリプトは好きになれん

2010年8月26日木曜日

passenger ? mongrel_cluster

まぁ、passenger と mongrel_cluster どちらを使ったらええの?とお悩みの方は多いと思います。
将来性を加味した場合、mongrel_cluster は、もうメンテナンスされてなさそうなんで、先行きは暗いです。しかも、長期に稼働させる事を考えると、定期的にリスタートさせる必要があるでしょう。
今後は、passenger を使うのが主流になるような気がしてます。ただし、現時点では CentOS にて passenger を選択する場合には、SELinux の事はスッパリと諦める覚悟が必要です。ここをクリアできるのは、SELinux マスターの方だけでしょう…。テンポラリ・ファイルを設定して…など…ゴニョゴニョとチャレンジしてみましたが、似非ネットワーク管理者には無理な事でした。
 passenger は、結構簡単に動作させる事ができます。はまりどころは、Rails の public とかに、.ht* 系のファイルが残っていて、mod_rewrite のルールが記述されており、そいつが邪魔をしている。あるいは、environment の指定を httpd の conf ファイルに書き忘れていて、dbに接続できていない。といったあたりになります。

2010/12/03 追記: CentOS Passenger + SELinux 成功例を見つけた。

2010年7月29日木曜日

rails helper の汚染ふたたび

 ヘルパの汚染が深刻なのである…。
active_scaffold を使っていると、helper にて

def options_for_association_conditions(association)
if association.name == :hoge
['hoge.funya = ?', 1]
elsif association.name == :fuga
['fuga.hoe = ?', 2]
else
super
end
end

なんてコードを書いて、リレーションの選択時に、コントローラで特有のフィルタリングを行ないます。
ところが、こいつも汚染されてしまう…。

 どう対処するか?ヘタレな方法だけども


class ApplicationController < ActionController::Base
before_filter :set_controller_name

def set_controller_name
session[:controller_name] = self.class;
end
end


として、


def options_for_association_conditions(association)
if session[:controller_name] == 'MogeController'
if association.name == :hoge
['hoge.funya = ?', 1]
elsif association.name == :fuga
['fuga.hoe = ?', 2]
else
super
end
else
if association.name == :hoge
['hoge.funya = ?', 2]
elsif association.name == :fuga
['fuga.hoe = ?', 3]
else
super
end
end
end


という指針にしますた。まだ何か落とし穴がありそうな… Object って危ないのねん、好きになれないな…。

2010/8/6 追記: appliction_controller.rb に

helper :all

の文字が…、こんなの知らねーよっ orz...

rails duplicate habtm 二重に多対多備忘録

 Hoges と Fugas が多対多の関係で欲しい場合は、habtm を使えばシンプルに済みます。しかし、この多対多の関係が、もうひとつ欲しい・・・となったとき、?????かなり悩んだ

create table hoges (
id serial primary key,
name varchar(16)
);
create table fugas (
id serial primary key,
name varchar(16)
);
create table fugas_and_hoges (
id serial primary key,
fuga_id integer,
hoge_id integer
);
create table another_fugas_and_hoges (
id serial primary key,
fuga_id integer,
hoge_id integer
);

このようなテーブルに対して

class FugasAndHoge < ActiveRecord::Base
belongs_to :fuga
belongs_to :hoge
end

class AnotherFugasAndHoge < ActiveRecord::Base
belongs_to :fuga
belongs_to :hoge
end

class Fuga < ActiveRecord::Base
has_many :fugas_and_hoges, :dependent => :destroy
has_many :hoges, :through => :fugas_and_hoges, :dependent => :destroy
has_many :another_fugas_and_hoges, :dependent => :destroy
has_many :another_hoges, :source => :hoge, :through => :another_fugas_and_hoges, :dependent => :destroy
end


class Hoge < ActiveRecord::Base
has_many :fugas_and_hoges, :dependent => :destroy
has_many :fugas, :through => :fugas_and_hoges, :dependent => :destroy
has_many :another_fugas_and_hoges, :dependent => :destroy
has_many :another_fugas, :source => :fuga, :through => :another_fugas_and_hoges, :dependent => :destroy
end



 うーむ・・・

2010年7月8日木曜日

activescaffold controller is nested call?

コントローラが、nested つまり、親コントローラの入れ子コントローラとして動作しているかどうかを判定したい…。こんな簡単そうな事が、意外と難しい。なんでもかんでも隠蔽しすぎているからだ。それだけ、activescaffold の完成度が高いとも言えるのだが…。

answer


<% if params[:parent_model] != nil -%>
...
<% end -%>


もちろん、コントローラ内でも使えます。

2010年6月25日金曜日

ぼやきまくる

 Rails の polymorphic association を調べていて、rails では クラスを継承できるから…うんぬんの記述を見つけた。冗談でしょ? foo_controller を継承して、bar_controller を作成した事がありますが、production 環境で、既に生成されたクラスを検索する時に bar_controller が foo_controller として表示されてしまうという酷い目にあいました。なんじゃこれ…?全然ダメじゃん…?と、ぼやきながら、継承を避けて DRY の原則を曲げて、泣く泣くコピペ・コーディングしました。
 Activescaffold の subform における更新も変です。昨日は、この問題を追っていましたが、簡単には解決できず、template オーバーライドで
_hoge_form_column.html.erb

<div>
<%= render :active_scaffold => "hoges", :constraints => { :fuga_id => @record.id }
-%>
</div>

解決しました。
そうでもしないと、has_many の関連レコードが、全部削除して、全部挿入されてしまいます。モデルで

:has_many => hoges, :dependent => :destroy

と指定しない場合には、全部削除の代わりに全部リンクが外され(fuga_id に nil がセットされる)、どんどんとレコードが増え続けます。仮に hoge モデルに対して belongs_to を指定しているモデルがあった場合には、どうするつもりなんでしょうか? ticket 353 の事ですが、habtm が前提となって書かれている気がします。enumlator と yield の嵐で、自己完結的に記述されていて、修正は難しいように感じました。ここは、バグの巣窟です。コントローラにて config.columns[:hoges].show_blank_record = false を指定すると、ここでは最後の1レコードが永遠に削除できません。逆に blank_record を表示するようにした場合、hoge の初期値に何かを設定すると、record.unsaved = true が働いてしまい。fuga 更新時には勝手に hoge のレコードが挿入されてしまいます。

2010年6月18日金曜日

activescaffold の subgroup をタブ化してみる(期待しないで)

あんましオススメできないかもしれないけど、一応、力入れて改造したのを、お披露目です。
activescaffold にて、全てのカラムが add_subgroup されている場合には、タブページのレイアウトにするというものです。jquery を使っているので、要注意です。 subgroup 名が 'main' の場合に限り、タブから脱出させて常に表示するよう配慮しました。

application.html.erb にて

<%= stylesheet_link_tag 'jquery-ui-1.8.1.custom', :media => 'all' %>
<%= javascript_include_tag "jquery-1.4.2.min.js" %>
<script type="text/javascript">
jQuery.noConflict();
var j$ = jQuery;
</script>
<%= javascript_include_tag "jquery-ui-1.8.1.custom.min.js" %>



lib/active_scaffold/helpers/id_helper.rb
追加

def tab_form_id(options = {})
options[:action] ||= params[:action]
options[:id] ||= params[:id]
options[:id] ||= params[:parent_id]
clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-tabform"
end

def tab_form_panel_id(column,options = {})
options[:action] ||= params[:action]
options[:id] ||= params[:id]
options[:id] ||= params[:parent_id]
clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-#{column.label}-tabform"
end



lib/active_scaffold/helpers/form_column_helper.rb

def override_tab_form_partial?(column)
path, partial_name = partial_pieces(override_tab_form_partial(column))
template_exists?(File.join(path, "_#{partial_name}"), true)
end

# the naming convention for overriding tab form with partials
def override_tab_form_partial(column)
"#{column.label}_tab_form"
end

def tab_form_partial_for_column(column)
if override_tab_form_partial?(column)
override_tab_form_partial(column)
else
"tab_form"
end
end



従来の_form.html.erb が _tab_form.html.erb になります。
frontends/default/views/_form.html.erb

<%
# 全ての column が、add_subgroup されているかどうかで、処理を切り替える
is_tabbed = true
columns.each :for => @record do |column|
if not is_subsection? column
is_tabbed = false;
break;
end
end
-%>
<% if is_tabbed -%>
<% columns.each :for => @record do |column| -%>
<% if column.label == 'main' %>
<div class="tab-form" id="<%= tab_form_panel_id(column) %>">
<% if !override_tab_form_partial?(column) -%>
<%= render :partial => 'tab_form', :locals => { :columns => column } %>
<% end -%>
</div>
<br clear="all" />
<% end -%>
<% end -%>
<script type="text/javascript">
j$(function(){
j$("#<%= tab_form_id %>").tabs();
});
</script>
<div id="<%= tab_form_id %>" class="form" <%= 'style="display: none;"' if columns.collapsed -%>>
<ul>
<% columns.each :for => @record do |column| -%>
<% if column.label != 'main' -%>
<li class="tab-form"><a href="#<%= tab_form_panel_id(column) %>"><%= t column.label %></a></li>
<% end -%>
<% end -%>
</ul>
<% columns.each :for => @record do |column| -%>
<% if column.label != 'main' -%>
<div class="tab-form" id="<%= tab_form_panel_id(column) %>">
<%= render :partial => tab_form_partial_for_column(column), :locals => { :columns => column } %>
</div>
<% end -%>
<% end -%>
</div>
<% else -%>
<%= render :partial => 'tab_form', :locals => { :columns => columns } %>
<% end -%>



frontends/default/views/_tab_form.html.erb

<ol class="form" <%= 'style="display: none;"' if columns.collapsed -%>>
<% columns.each :for => @record do |column| -%>
<% if is_subsection? column -%>
<li class="sub-section">
<h5><%= column.label %> (<%= link_to_visibility_toggle(:default_visible => !column.collapsed) -%>)</h5>
<%= render :partial => 'form', :locals => { :columns => column } %>
</li>
<% elsif is_subform? column and !override_form_field?(column) -%>
<li class="sub-form <%= active_scaffold_config_for(column.association.klass).subform.layout %>-sub-form <%= column.css_class unless column.css_class.nil? %>" id="<%= sub_form_id(:association => column.name) %>">
<%= render :partial => form_partial_for_column(column), :locals => { :column => column } -%>
</li>
<% else -%>
<li class="form-element <%= 'required' if column.required? %> <%= column.css_class unless column.css_class.nil? %>">
<%= render :partial => form_partial_for_column(column), :locals => { :column => column } -%>
</li>
<% end -%>
<% end -%>
</ol>


 ちょい実装してから、時間が経過しているので、ここにポストした改造箇所が足りてるかどうか不安…。あんまし期待しないで…。
 他にも、Java の absolute layout よろしく <table> レイアウトで、各 column のプロパティから、レイアウトを決定するような改造もしてみたのだけれども…。これもどうなのかな…?

FormHelper の汚染に対応(2)

 FormHelperの汚染に対応の続きです。
 前回のやり方だと、デフォルトの動作と切り替えるのが困難なので、activescaffold に新たにオーバーライドするかどうかをチェックするためのヘルパを加えてみました。

lib/active_scaffold/helpers/form_column_helpers.rb です。
まず下準備としてメソッドを追加します。

def override_form_field_will_do?(column)
respond_to?(override_form_field_will_do(column))
end

def override_form_field_will_do(column)
"#{column.name}_form_column_will_do"
end

次に、active_scaffold_input_for を改造します

module FormColumnHelpers
# This method decides which input to use for the given column.
# It does not do any rendering. It only decides which method is responsible for rendering.
def active_scaffold_input_for(column, scope = nil, options = {})
begin
will_do = true
options = active_scaffold_input_options(column, scope, options)
options = javascript_for_update_column(column, scope, options)
# prepare, check if form_field will be override?
if override_form_field_will_do?(column)
will_do = send(override_form_field_will_do(column), @record, options)
end
# first, check if the dev has created an override for this specific field
if will_do and override_form_field?(column)
send(override_form_field(column), @record, options)
# second, check if the dev has specified a valid form_ui for this column
elsif column.form_ui and override_input?(column.form_ui)
send(override_input(column.form_ui), column, options)
# fallback: we get to make the decision
else
....


同様に list_column_helper.rb も改造します

module ListColumnHelpers
def get_column_value(record, column)
begin
will_do = true
if column_override_will_do? column
will_do = send(column_override_will_do(column), record)
end
# check for an override helper
value = if will_do and column_override? column
......


def column_override_will_do(column)
"#{column.name.to_s.gsub('?', '')}_column_will_do"
# parse out any question marks (see issue 227)
end

def column_override_will_do?(column)
respond_to?(column_override_will_do(column))
end




 これで、FormHelper にて



def name_column_will_do
record.is_a? Customer
end

def name_column(record)
"<a href='mailto:" + record[:email_address].to_s + "'>" + record[:name].to_s + "</a>";
end



と、汚染に対する耐性が簡単に実装できました。

2010年6月10日木曜日

record_select の google chrome 対応

 規格がどうだ・・・とか、厳密な話をしていても、微妙な違いは起こるものです。自分の開発環境がノートパソコンだからかどうかは、わかりませんが、少なくとも Firefox と Google chrome では、javascript 内における onkeypress イベントで、ハンドリングされないキーが存在します。
 あと、意図せずに、ESC キーを押してしまった場合、フォーカスを当てなおさないと選択リストが表示されません。これらを考慮に入れた上で、record_select.js を修正してみました。


...

/**
* all the behavior to respond to a text field as a search box
*/
_respond_to_text_field: function(text_field) {
// attach the events to start this party
text_field.observe('focus', this.open.bind(this));

// the autosearch event - needs to happen slightly late (keyup is later than keypress)
text_field.observe('keyup', function() {
if (!this.is_open()) return;
this.container.down('.text-input').value = text_field.value;
}.bind(this));

// keyboard navigation, if available
if (this.onkeypress) {
text_field.observe('keypress', this.onkeypress.bind(this));
}
if (this.onkeydown) {
text_field.observe('keydown', this.onkeydown.bind(this));
}
},

_use_iframe_mask: function() {
return this.container.insertAdjacentHTML ? true : false;
}
});

/**
* Adds keyboard navigation to RecordSelect objects
*/
Object.extend(RecordSelect.Abstract.prototype, {
current: null,

/**
* keyboard navigation - where to intercept the keys is up to the concrete class
* some browser does not handle KEY_XXXX. so separate to keydown event
*/
onkeypress: function(ev) {
var elem;
switch (ev.keyCode) {
case Event.KEY_SPACE:
case Event.KEY_RETURN:
if (this.current) this.current.down('a').onclick();
break;
case Event.KEY_RIGHT:
if( !this.is_open() ) this.open();
elem = this.container.down('li.pagination.next');
if (elem) elem.down('a').onclick();
break;
case Event.KEY_LEFT:
if( !this.is_open() ) this.open();
elem = this.container.down('li.pagination.previous');
if (elem) elem.down('a').onclick();
break;
case Event.KEY_ESC:
break;
case Event.KEY_TAB:
return;
default:
if( !this.is_open() ) this.open();
return;
}
Event.stop(ev); // so "enter" doesn't submit the form, among other things(?)
},
/**
* keyboard navigation - where to intercept the keys is up to the concrete class
*/
onkeydown: function(ev) {
var elem;
switch (ev.keyCode) {
var elem;
switch (ev.keyCode) {
case Event.KEY_UP:
if( !this.is_open() ) this.open();
if (this.current && this.current.up('.record-select')) elem = this.current.previous();
if (!elem) elem = this.container.getElementsBySelector('ol li.record').last();
this.highlight(elem);
break;
case Event.KEY_DOWN:
if( !this.is_open() ) this.open();
if (this.current && this.current.up('.record-select')) elem = this.current.next();
if (!elem) elem = this.container.getElementsBySelector('ol li.record').first();
this.highlight(elem);
break;
case Event.KEY_RIGHT:
if( !this.is_open() ) this.open();
elem = this.container.down('li.pagination.next');
if (elem) elem.down('a').onclick();
break;
case Event.KEY_LEFT:
if( !this.is_open() ) this.open();
elem = this.container.down('li.pagination.previous');
if (elem) elem.down('a').onclick();
break;
case Event.KEY_TAB:
case Event.KEY_ESC:
this.close();
break;
default:
return;
}
},

/**
* moves the highlight to a new object
*/
highlight: function(obj) {
if (this.current) this.current.removeClassName('current');
this.current = $(obj);
obj.addClassName('current');
}
});


追記:修正部分が足りてませんでした。追加しました。
2010/06/11 追記:keypress イベントにもリスト再表示のコードを挿入しました。
2010/07/29 追記:tab イベント時の処理がまずかったので、修正。元のコードの方がすっきりしているので、この改造は本末転倒だったかも…

ControllerHelper の汚染に対応

 何が起こっているのか、よくわかんないのだが、helper は、モジュールで作成されており、コントローラからコントローラを利用すると、モジュールによる汚染があるのでは無いか?と推察しています。
 どういう現象が起こるかと言うと、Employee と Customer に name というフィールドが存在している場合に、CustomersHelper 内で activescaffold の Field override を使った場合に、意図せず Employee の name まで挙動が波及してしまう事があります。


def name_column(record)
"<a href='mailto:" + record[:email_address].to_s + "'>" + record[:name].to_s + "</a>";
end


 Oh!No! Employee の name まで波及してるやんけーーーーー!!!

こんな時は、慌てず

def name_column(record)
if record.is_a? Customer
"<a href='mailto:" + record[:email_address].to_s + "'>" + record[:name].to_s + "</a>";
else
if record[:name] != nil
record[:name].to_s
else
''
end
end
end


です。うーん・・・どうなんでしょ・・・これ・・・

2010年6月8日火曜日

rails 2.3.8 で The error occurred while evaluating nil.[]

 またまた、いろいろ変更されたおかげで、mongrel に修正が必要なようだ…。

mongrel-1.1.5/lib/mongrel/cgi.rb

def send_cookies(to)
...
else
#to['Set-Cookie'] = options['cookie'].to_s
to['Set-Cookie'] = @head['cookie'].to_s
end
...
end


2010/06/09 追記:このやり方でも、まだダメみたいだ…。
2010/06/09 追記2: @ ぬけてるやん orz...

2010年6月3日木曜日

html の select 要素でまたはまる

 html のフォーム系要素は、まだまだ糞だ。IE6 の select が、zindex に関係なく一番上にくるというアホな話は、まあいいとして・・・。今回は、select 要素を readonly にできなくてハマった。正確に言えば、readonly="readonly" と指定しても、ぜんぜん readonly じゃないのだ・・・。バンバン選択できるぜセニョリータ・・・アホけ?

いやいや、disabled がありますよ?

 そうは問屋がおろさないのである。フォームをサブミットした時に、disabled された要素は、もちろん無視される。そうすると、どうなるか? rails とかで、更新時に値がリセットされてしまうのである。こいつを避けるために hidden 要素を追加すればいいのである・・・。である。わかるよ。うん。わかる。hidden 要素を追加すればいいんだよね?アホだろ?

 そもそも、input 要素とかにフィールドと連携した id 属性が自動で割り振られるようになっているところへ、hidden 要素を追加しろだー?なんで、こんなまわりくどい事をせにゃならんねん・・・。

 他にも、style で、ime-mode: active, inactive, ... の中に、カナ・モードとかも欲しいところなのだが、ありま千円。これ最初に考えたの MS でしょ?中途半端だ・・・。せっかく firefox も追随してくれてるのに・・・。

追記: 結局のところ、activescaffold を改造するハメに・・・ form_column_helpers.rb

def active_scaffold_input_singular_association(column, html_options)
associated = @record.send(column.association.name)

select_options = options_for_association(column.association)
select_options.unshift([ associated.to_label, associated.id ]) unless associated.nil? or select_options.find {|label, id| id == associated.id}

selected = associated.nil? ? nil : associated.id
method = column.name
#html_options[:name] += '[id]'
options = {:selected => selected, :include_blank => as_(:_select_)}

html_options.update(column.options[:html_options] || {})
html = ""
# to be disabled ... and add hidden tag
if html_options[:readonly]
html_options[:disabled] = true;
end
options.update(column.options)
html << select(:record, method, select_options.uniq, options, html_options)
if html_options[:readonly]
# この段階でないと、options[:name] が確定していない?
html << "<input type='hidden' name='#{html_options[:name]}' value='#{selected}' />"
end
html
end

くどい・・・

2010/06/18 追記: W3Cでは、readonly なんて属性は invalid のようだ…。ちゃんと練られていないって事でいいのかな?

2010年5月29日土曜日

rails と postgresql schema

 うちの社員から、スキーマは分けないんですか?と、問われて、そんな事は無理だろう・・・と即座に思った。でも、まぁ、ちょっと実験してみるか・・・と、やってみたら、簡単に切り替える事ができた…。ショックでした…。


create schema test;
create table foos (
id serial primary key,
bar_id integer,
name varchar(16)
);
create table bars(
id serial primary key,
name varchar(8)
);
create table test.bars (
id serial primary key,
name varchar(8)
);


こんな感じのリレーションを作成しておいて


class FoosController < ApplicationController
before_filter :change_schema

def change_schema
Bar.set_table_name 'test.bars'
end
end


とか、やっちゃったら、簡単にスキーマが切り替えられたんです。怖いです。よくよく考えてみると、テーブル名は規約から外れるわけじゃないので、そうなのかもしれません。

 postgresql の slony-i のマスター・スレーブ方式ですが、DB単位じゃないですか?schema単位でマスター・スレーブ方式が選択できると、途端に幅が広がったりしませんか?相互にスキーマを転送できると、凄い事になりそうです。

2010年5月20日木曜日

activescaffold の :select の sort

ActiveScaffold の form_ui = :select を指定した時に、意図した並び順でリストボックスを表示したい。
ActiveRecord にデフォルトの並び順が指定できるようになった。

class Hoge < ActiveRecord::Base
default_scope :order => 'id';
end

だから、activescaffold における form_ui = :select を指定した場合にアルファベット順でソートする挙動は、もう要らない。
helpers/association_helpers.rb を修正する。

# returns options for the given association as a collection of [id, label] pairs intended for the +options_for_select+ helper.
def options_for_association(association, include_all = false)
available_records = association_options_find(association, include_all ? nil : options_for_association_conditions(association))
available_records ||= []
# available_records.sort{|a,b| a.to_label <=> b.to_label}.collect { |model| [ model.to_label, model.id ] }
# already sorted by sql. so disable sorting.
available_records.collect { |model| [ model.to_label, model.id ] }
end

2010年2月3日水曜日

mongrel_cluster prefix AbstractRequest (NameError) 備忘録

 また、検索しそうなので備忘録として記録する。

mongrel_cluster + mod_proxy_balancer の組み合わせで、prefix を指定すると、エラーが出るようになった。原因は、Rails の内部仕様が変更された事による。

/usr/lib64/ruby/gems/1.8/gems/mongrel-1.1.5/lib/mongrel/rails.rb
に修正を施す。

ActionController::AbstractRequest.relative_url_root = ops[:prefix] if ops[:prefix]

という部分を

if ops[:prefix]
if ActionController::Base.respond_to?('relative_url_root=')
ActionController::Base.relative_url_root = ops[:prefix]
# new way to set the relative URL in Rails 2.1.1
else
ActionController::AbstractRequest.relative_url_root = ops[:prefix]
end
end

 とする。

参考URL
LANKHMAR
mongrel rubyforge

2009年2月5日木曜日

active_scaffold action ボタンの追加

 ネタに走ります…(^^;。
アクションボタンの追加は


config.action_links.add ....


で追加できますが、これにより追加されたボタンのHTML要素には、class 'action' 属性がプレゼントされます。
この 'action' クラス属性は、active_scaffold.js により次の副作用を持ちます。

  • 入れ子のパネルへレンダリングされる


という事なので、部分的にAJAXでパーツを置き換えようと思っても、うまく行きません。そこで、テンプレートを書き換えるしかありません。以下は、_list_header.rhtml を書き換えて、フィルタを切り替える例です。


<% if active_scaffold_config.action_links.any? { |link| link.type == :table } -%>
<div class="actions">
<!-- ここに目的のチェックボックスを作成 -->
<a position="top" class="link">
<input type="checkbox" id="view_past" value="全表示" onclick="view_all_foo()"
<%= 'checked' if(session[:pcomp] == 1) -%> />全表示</a>
<!-- ここまで -->
<% new_params = params_for(:action => :table) %>
<% active_scaffold_config.action_links.each :table do |link| -%>
<% next if controller.respond_to? link.security_method and !controller.send(link.security_method) -%>
<%= render_action_link(link, new_params) -%>
<% end -%>

<%= loading_indicator_tag(:action => :table) %>
</div>
<% end %>
<h2><%= active_scaffold_config.list.user.label %></h2>
<!-- ここからは、フィルタを実行するリクエストを送信 -->
<script type='text/javascript'>
function view_all_foo() {
var elem = document.getElementById( 'view_past' );
if( elem.checked ) {
new Ajax.Updater( 'foos-content', '/foos/set_view_all?scaffold_id=foo&page=1', { asynchronous:true, evalScripts:true } );
} else {
new Ajax.Updater( 'foos-content', '/foos/set_view_new?scaffold_id=foo&page=1', { asynchronous:true, evalScripts:true } );
}
}
</script>
<!-- ここまで -->


これに対して foos_controller.rb では


class FoosController < ApplicationController
layout 'application'
before_filter :authorize
record_select :per_page => 7, :search_on => [:name], :full_text_search => true
active_scaffold :foo do |config|
...
end

def set_view_all
session[:pcomp] = 1
rewrite_list
end

def set_view_new
session[:pcomp] = 0
rewrite_list
end

def conditions_for_collection
if session[:pcomp] == 0
'complete_flag = 0'
end
end

protected
...

def rewrite_list
do_list
render :active_scaffold => 'foos', :partial => 'list'
end

end


としています。尚、フィルタの値は、クッキーによる session[:pcomp] に持たせています。

修正:
一部コードがおかしかったので修正しました。

2008年10月23日木曜日

Rails ActiveRecord 備忘録

モデル User と Hoge があり、Hoge から、多対1の関係で User にリレーションを2箇所設定したい場合、はて?どうしたものか?となった。


class User < ActiveRecord::Base
has_many :Hoges
...
end

class Hoge < ActiveRecord::Base
belongs_to :user, :foreign_key => 'user_id'
belongs_to :manager, :class_name => 'User', :foreign_key => 'manager_id'
...
end

class HogesController < ApplicationController
active_scaffold :hoge do |config|
config.columns = [..., :user, :manager, ...]
config.columns[:user].form_ui = :select
config.columns[:manager].form_ui = :select
...
end
...
end
keyword: rails active_record table relation same column

2008年10月21日火曜日

Railsについて思うこと

 実はRuby On Rails に(ゾッコン)はまりました。やってみて思った事を書きます。

  1. 生産性は高く素晴らしい!しかし、レールが敷かれている限りにおいては・・・
  2. 安定稼動しないのでアプリケーションとして提供するには、不満
  3. 革新的な技術がどんどん導入されて楽しいが、バージョンアップに伴うアプリケーションメンテナンスが大変
 active_scaffold と JasperReports の組み合わせで、型どおりのアプリケーションを作成するのは速く、生産性が高いわけですが、ちょっと細かい事をしようと思うと、とたんに難しくなります。みんなで新しいレールを敷設してまわれば楽しいわけですが、レールを外れた場合に生産性が高いか?と問われれば、極めて疑問を感じます。

 社内の日報管理システムをRoRで組みました。実際に長期稼動をしてみると、安定しているのですが、別の環境の別システムでは、システムが止まるので、1日1回に cron でリスタートをかけるという選択をしました。サービスとして選択するのは、まだ厳しいのではないかと感じます。

 Rubyの環境がアップデートされた場合に、rails が急に動作しなくなるといった事があります。また、railsのバージョンが上がると、後方互換性は捨てられていくわけですが、古いバージョンには脆弱性というものが付き物です。古いバージョンはサポートされなくなるので、ブラウザの挙動が変更された場合などにも対応されなくなります。そこで、railsのバージョンも追随したい訳ですが、レールを外れるほどに追随するための作業が大量に発生します。正直、つらいです(Zope & Plone に似た状況)。

 私の感覚では、RoRは斬新で素晴らしいけれども、仕事に向いているとは、必ずしも言えない。です。