• 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

色々奥が深いと思った(not http://0xcc.net/misc/bad-knowhow.html 笑)

■前提:記事←関連テーブル→ユーザというモデル関係がある。

   1  # has_many :throughのパターン
   2  class Article< ActiveRecord::Base
   3    has_many :articles_users
   4    has_many :users, :through => :articles_users
   5  end
   6  
   7  class User < ActiveRecord::Base
   8    has_many :articles_users, :dependent => :destroy
   9    has_many :articles, :through => :articles_users
  10  end
  11  
  12  # 関連テーブルを実テーブルで持つ
  13  class ArticlesUsers < ActiveRecord::Base
  14    belongs_to :article
  15    belongs_to :user
  16  end

■関連テーブルの操作

あるユーザの関連をごそっと別の関連に切り替えたいような場合!

User.articles_users.destroy_allして作り直すという方法もあるが User.articles_users.replace()という便利なメソッドがある。

AWD第二版(AgileWebDevelopment)で言うとP308。 「○orders.replace(order1,...) この顧客に関連付けられた注文のセットを、新しいセットに置き換える。現在の子のセットと新しいセットの違いを検出し、それに応じてデータベースの変更を最適化する。」という奴。

   1   /ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.0/lib/active_record/associations/association_collection.rb
   2  
   3        # Replace this collection with +other_array+
   4        # This will perform a diff and delete/add only records that have changed.
   5        def replace(other_array)
   6          other_array.each { |val| raise_on_type_mismatch(val) }
   7  
   8          load_target
   9          other   = other_array.size < 100 ? other_array : other_array.to_set
  10          current = @target.size < 100 ? @target : @target.to_set
  11  
  12          @owner.transaction do
  13            delete(@target.select { |v| !other.include?(v) })
  14            concat(other_array.select { |v| !current.include?(v) })
  15          end
  16        end
これは便利。

1.配列を放り込むだけ

「Replace this collection with +other_array+」ということで検索結果、あるいはセッションなどで生成した新しい関連の配列を放り込むだけで使える。

2.以前の関連との差分をチェックして差分だけ反映してくれる。

「This will perform a diff and delete/add only records that have changed.」ということで必要な差分だけチェックして必要なdelete/addをしてくれる。

ちなみにdeleteだと「Railsレシピブック」のP157「Entryオブジェクトobjectとの関連を削除する。Entryオブジェクトobjectの外部キー(blog_id)をNULLにし、関連を削除する。複数の参照元オブジェクトを同時に指定できる。」にある通り、関連テーブルの実レコードは削除されない(外部キーがNULLになるだけ)。関連テーブルにごみが残って気持ち悪い場合は上記モデルのように「:dependent => :destroy」を付けると物理的に削除される。

posted by Face ysakaki on Fri 22 Aug 2008 at 15:54

Comments:

or Preview
Social Bookmarks
  • Delicious
  • B_entry805
  • Clip_16_12_w
Services from s21g
twpro(ツイプロ)
Twitterプロフィールを快適検索
地価2009
土地の値段を調べてみよう
MyRestaurant
自分だけのレストラン手帳
Formula
ブログに数式を埋め込める数式コミュニティ