TodoList: 作成者を記録2006年12月31日 11時45分56秒

以前から作りたいと思っていた Todo の作成者 (Creator) を追加したい。これは、todos テーブルと、users テーブルの一対多の関係となる。そして、Todo なので、担当者 (Assignee) も付けられる様にする。こちらも同様の一対多だ。

つまり、Rails の一対多の関係を単純には使えない。has_many と belongs_to にて外部キーを指定する必要がある。app/models/todo.rb と app/models/user.rb に以下の変更を加えた。


% cvs diff app/models
--- app/models/todo.rb  26 Dec 2006 04:11:12 -0000      1.2
+++ app/models/todo.rb  26 Dec 2006 08:54:11 -0000
@@ -1,4 +1,7 @@
 class Todo < ActiveRecord::Base
-  has_many :todo_organiation_permissions
+  has_many :todo_organization_permissions
   has_many :organizations, :through=>:todo_organization_permissions
+
+  belongs_to :creator, :foreign_key => "creator_id", :class_name => "User
"
+  belongs_to :assignee, :foreign_key => "assignee_id", :class_name => "Us
er"
 end
--- app/models/user.rb  6 Dec 2006 07:14:51 -0000       1.2
+++ app/models/user.rb  26 Dec 2006 08:14:03 -0000
@@ -27,6 +27,10 @@
 # module, and is further extended by UserEngine::AuthorizedUser.
 class User < ActiveRecord::Base
   belongs_to :organization
+
+  has_many :created_todos, :foreign_key => "creator_id", :class_name => "
Todo"
+  has_many :assigned_todos, :foreign_key => "assignee_id", :class_name =>
 "Todo"
+
   include LoginEngine::AuthenticatedUser
   include UserEngine::AuthorizedUser

todos テーブルに新しい項目を追加する。


% cat owners.mysql
USE todos;
ALTER TABLE todos ADD creator_id INT;
ALTER TABLE todos ADD assignee_id INT;
% cat owners.mysql | mysql

次に todo/new を作成者 (Creator) を割り当てるように変更する。http://localhost:3000/todo/new の入力は create 関数に渡される。作成者は変える必要がないので、新規に作られるときのみ割り当てる。作成者の id は user_engine のおかげで @session から取り出せる。


% cvs diff app/controllers/todo_controller.rb
--- app/controllers/todo_controller.rb  26 Dec 2006 05:34:30 -0000      1.11
+++ app/controllers/todo_controller.rb  26 Dec 2006 08:51:08 -0000
@@ -37,6 +38,7 @@
 
   def create
     @todo = Todo.new(params[:todo])
+    @todo.creator_id = @session[:user][:id]
     if @todo.save
       flash[:notice] = 'Todo was successfully created.'
       redirect_to :action => 'list

http://localhost:3000/todo/new にアクセスして、「Test TodoList」を入力した。しかし、http://localhost:3000/todo/list にアクセスしても今入れたばかりの Todo レコードがない。todo/list も変更する必要がある。昔の条件に加えて、自信の id が creator_id であれば表示する。

まずは、SQL を自分で試す。


mysql> SELECT * FROM todos LEFT JOIN todo_organization_permissions
 ON todo_organization_permissions.todo_id = todos.id
 WHERE (published = 1 AND organization_id = 1) OR creator_id = 1;
+----+------------------+------+------------+-------------+------+---------+-----------------+-----------+
| id | description      | done | creator_id | assignee_id | id   | todo_id | organization_id | published |
+----+------------------+------+------------+-------------+------+---------+-----------------+-----------+
|  1 | Create todo list |    0 |       NULL |        NULL |    1 |       1 |               1 |         1 | 
|  2 | Enter todos      |    0 |       NULL |        NULL |    4 |       2 |               1 |         1 | 
|  4 | Test TodoList    |    0 |          1 |        NULL | NULL |    NULL |            NULL |      NULL | 
+----+------------------+------+------------+-------------+------+---------+-----------------+-----------+
3 rows in set (0.01 sec)

うまくいったようだ。

今度はこれと等価な SQL を todo_controller.rb から作ればよい。


% cvs diff app/controllers/todo_controller.rb
--- app/controllers/todo_controller.rb  26 Dec 2006 05:34:30 -0000      1.11
+++ app/controllers/todo_controller.rb  26 Dec 2006 08:51:08 -0000
@@ -21,8 +21,9 @@
       #  "published = 1 AND organization_id = " +
       #  session[:user][:organization_id].to_s(),
       :include => :todo_organization_permissions,
-        :joins => ["WHERE published = 1 AND organization_id = " +
-         session[:user][:organization_id].to_s()],
+        :joins => ["WHERE (published = 1 AND " +
+         "organization_id = " + session[:user][:organization_id].to_s() + ")" +
+         " OR creator_id = " + session[:user][:id].to_s()],
       :per_page => 10)
   end

これで、所属団体 (Organization) に関係なく自分の作った Todo は見られる様になった。

前回次回