關於delete_all的BUG後續

前文請看這邊關於delete_all的bug
先感謝Bruce 的玩具間對於我的疑問抱持著同樣的好奇心(他用的awesome_rails_console也超好用的啊),並且深入的研究了一番,也讓我對delete_all這個method有了更加的了解,然後也學習到了找rails source code的方法,雖然說xdite說現在看source code只會搞死自己拉~
下面我就再紀錄一下看完Bruce 的玩具間的文章之後,再紀錄一下自己try的結果

先從結論開始講好了,用delete_all把foreign keys update成nil並不是一個BUG(我誤會他了)
這邊要先講一件重要的事情就是我們一般操作rails物件用的delete_all跟直接操作db table所用的delete_all是兩個不同檔案的不同method!(這件事讓我有點訝異),看下面就可以清楚的知道

DEVELOPMENT [4] rails101(#<GroupsController>)> @group.group_users.method(:delete_all).source_location
[
    [0] "/Users/kuro/.rvm/gems/ruby-2.2.2@global/gems/activerecord-4.2.5/lib/active_record/associations/collection_proxy.rb",
    [1] 442
]
DEVELOPMENT [7] rails101(#<GroupsController>)> GroupUser.method(:delete_all).source_location
[
    [0] "/Users/kuro/.rvm/gems/ruby-2.2.2@global/gems/activerecord-4.2.5/lib/active_record/querying.rb",
    [1] 8
]

再去看了rails/activerecord/lib/active_record/associations/collection_proxy.rb可以看到在這個method前的註解寫到

  # Deletes all the records from the collection according to the strategy
  # specified by the +:dependent+ option. If no +:dependent+ option is given,
  # then it will follow the default strategy.
  #
  # For +has_many :through+ associations, the default deletion strategy is
  # +:delete_all+.
  #
  # For +has_many+ associations, the default deletion strategy is +:nullify+.
  # This sets the foreign keys to +NULL+.

重要的一行我把它放大

For +has_many+ associations, the default deletion strategy is +:nullify+.This sets the foreign keys to +NULL+.

也就是說如果has_manythrough的話用delete_all的確就會執行delete,但如果has_many沒有through也沒有dependent的話就會執行default strategy,在has_many的情況的話default strategy就是nullify
另外在Do not invoke callbacks when delete_all is called有講到@post.comments.delete_all(:nullify)這樣子的用法

DEVELOPMENT [15] rails101(main)> @group.group_users.delete_all(:delete_all)
  SQL (0.1ms)  DELETE FROM "group_users" WHERE "group_users"."group_id" = ?  [["group_id", 1]]
nil

然後我也去試了在has_many有through option時用delete_all去刪除,的確會執行delete

group.rb
has_many :members , through: :group_users , source: :user
DEVELOPMENT [2] rails101(#<GroupsController>)> @group.members.delete_all
  SQL (4.9ms)  DELETE FROM "group_users" WHERE "group_users"."group_id" = ? AND "group_users"."user_id" = 5  [["group_id", 66]]
nil

至於執行@group.group_users.all.delete_all會刪除是因為這邊用的delete_all跟GroupUser所用的delete_all都同屬個method都屬於rails/activerecord/lib/active_record/relation.rb所以還是會執行delete

看到這邊終於可以了解到為什麼執行delete_all會變成update成nil的問題,但我還是不太能理解為什麼沒有dependent
就要把重要的foreign keys清除掉,這樣資料庫裡面不就很容易有孤兒資料了嗎?

comments powered by Disqus