TodoList: もう一つの select の修正2006年12月30日 12時09分42秒

所属団体 (Organization) への公開情報のもう一つの不具合を直す。ブラウザで表示したときに、初期値が正しく選ばれていない問題だ。usr/show の方の不具合は select へ正しい引数を渡せば直ったが、今回は勝手が違う。

こちらだと、複数の変更を一回で受け取りたいので、特殊な形式なので、標準の様にはいかないのだ。そこで表示結果を見ると、毎回初期値になってしまっているのは、最初の項目だ。そこで、:selected でやっているのと同じことを選択肢を作る段階でやる。


% vi app/controllers/todo_controller.rb
  protected
    def published
      @no_yes =  [ ["NO", -1], ["YES", 1] ]
      @yes_stopped =  [ ["YES", 1], ["STOPPED", 0] ]
      @stopped_yes =  [ ["STOPPED", 0], ["YES", 1] ]
      @published_organizations =
        TodoOrganizationPermission.find(:all,
          :conditions=>["todo_id=?", params[:id]])
        #TodoOrganizationPermission.find_all("todo_id = " + params[:id])
      @organization_ids = @published_organizations.map { |o| o.organization_id }
    end
% cat app/views/todo/_published.rhtml
<%= start_form_tag :action => 'update_published', :id => @todo %>
<table>
  <tr>
  <% for column in Organization.content_columns %>
    <th><%= column.human_name %></th>
  <% end %>
   <th>Published-to</th>
  </tr>
  
<% for org in Organization.find_all() %>
  <tr>
  <% for column in Organization.content_columns %>
    <td><%= org.send(column.name) %></td>
  <% end %>
    <td><%= (@organization_ids.member?(org.id) ?
              (@published_organizations[
                @organization_ids.index(org.id)]['published'] != 0 ?
                    "YES" : "STOPPED" ) : "NO" ) %>
    </td>
    <td>
      <%= select :organization, :id,
       (@organization_ids.member?(org.id) ?
         (@published_organizations[
           @organization_ids.index(org.id)].published != 0 ?
             @yes_stopped : @stopped_yes) : @no_yes),
       {},
       { 
         :selected => (@organization_ids.member?(org.id) ?
           (@published_organizations[
           @organization_ids.index(org.id)].published != 0 ? "1" : "0") : "-1"),
         :name => "organization[" + org.id.to_s() + "][published]" } %>
    </td>
  </tr>
<% end %>

</table>
<%= submit_tag "Save" %>
<%= end_form_tag %>

まず、todo_contoroller.rb の published 関数に、@no_yes、@yes_stopped、@stopped_yes を追加した。その後、_published.rhtml を修正。

Ruby での条件式に三項演算子が使えるのを知ったので、if then elsif end を変更した。遥か昔に使えると見た記憶があったのだが動いてくれなかったのだ。どうも、Rails の rhtml の処理だか、Ruby の構文解析に問題があるらしく、改行の位置を気を付けないと、正しく動作しない時がある。文が終了していると誤認し、異常な動作を起こすことが多々ある。

そこで、少し実験してみた。なお、cat 行以下の最初の ? はヒアドキュメント用のプロンプトだ。


% cat << EOF | ruby
? print ( 1 ? "a" : "b")
? EOF
a%
% cat << EOF | ruby
? print (
? "test")
? test%

この実験では、三項演算子も動いている。また、括弧の中身を次の行に置くことも出来るのがわかる。

% cat << EOF | ruby
? print (
? 2
? ? "A"
? :  "B")
? EOF
-:3: parse error, unexpected '?', expecting ')'
? "A"
 ^
-:4: parse error, unexpected ':', expecting $
:  "B")
 ^
% ruby --version
ruby 1.8.5 (2006-08-25) [i386-freebsd6]

しかし、三項演算子を行を跨いで行なおうとすると、構文解析に失敗するようだ。

前回次回