TodoList: 複数の公開情報更新をデータベースに反映2006年12月24日 09時37分11秒

プルダウンメニューの表示に成功したので、次はユーザの入力を元にデータベースを更新する。

app/controllers/todo_controllers.rb に新しい関数を作る。update_published と呼ぶことにした。

実は更新を処理する過程で、無効な入力が入ってくる可能性に気が付いた。とりうる値は三つで、古い値と新しい値があるので合計九通りの処理が出来ることになる。しかし、一度公開したのを中止することは出来ても、無かったことには出来ない。NO は YES に移行するのみで、YES になったとは YES と STOPPED を入れ換える事が出来るだけだ。

それ以外の入力が来ても、無視するかユーザにエラーを返すしかない。そうなるとユーザの入力値制限して、ユーザに不当な値を指定できないようにした方が早い。そこで、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><%=
      if @organization_ids.member?(org.id)
      then
        if @published_organizations[
          @organization_ids.index(org.id)]['published'] != 0
        then
          "YES"
        else
          "STOPPED"
        end
      else
        "NO"
      end %></td>
    <td>
      <%= select :organization, :id,
       if @organization_ids.member?(org.id) then @yes_stopped else @yes_no end,
       { },
       { 
         :selected =>
          if @organization_ids.member?(org.id)
          then
            if @published_organizations[
              @organization_ids.index(org.id)]['published'] != 0
            then
              1
            else
              0
            end
          else
            -1
          end,
         :name => "organization[" + org.id.to_s() + "][published]" } %>
    </td>
  </tr>
<% end %>

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

organization_id が organization_ids 配列の中にあるか無いかによって初期値を決めるのである。

そして、データベースの更新を app/controllers/todo_controller.rb の update_published 関数の中で行う。


  def update_published
    @params[:organization].each { | org_id, attr |
      top = TodoOrganizationPermission.find(:first,
      :conditions=>["todo_id = ? AND organization_id = ?",
        @params[:id], org_id]
      )
      if top == nil
        if attr[:published].to_i() == 1 # "NO" to "YES"
          top = TodoOrganizationPermission.new
          top.update_attribute(:todo_id, @params[:id])
          top.update_attribute(:organization_id, org_id)
          top.update_attribute(:published, attr[:published])
          top.save
        end
      elsif attr[:published].to_i() != top.published.to_i()
        # "YES/STOPPED" is changed to "STOPPED/YES"
          top.update_attribute(:published, attr[:published])
      end
    }
    redirect_to :action => 'show', :id => @params[:id]
  end

  protected
    def published
      @yes_no =  [ ["YES", 1], ["NO", -1] ]
      @yes_stopped =  [ ["YES", 1], ["STOPPED", 0] ]
      @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

@params[:organization] にて画面で指定されている全ての公開情報が手に入る、これは Hash なので、each で各々を処理するのだ。まず、todo_organization_permissions テーブルに対応する対のレコードがあるかを調べる。それをユーザの入力と照らし合わせて更新する。ユーザの入力とデータベースの値なら更新する必要はない。違った場合は上の条件に従って処理すればいい。

これで、ユーザが Todo の公開情報を更新出来るようになった。

前回次回