2011-05-28 9 views
1

私のモデルのうちの2つが似ていることに間違いなく気付いた。その名前はGameItemとOwnedItemです。 GameItemはゲームの単なるアイテムですが、OwnedItemはプレーヤーがそのアイテムを持っているかどうか、それが自分の在庫や倉庫などにあるかどうかを表します。モデルを組み合わせてレールの方法をスコープ

class OwnedItem < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :game_item 
    belongs_to :ownable, :polymorphic => true # [warehouse|inventory] 

    scope :equipped, where(:is_equipped => 1).includes(:game_item) 

    scope :item, lambda { |item_type| 
    joins(:game_item). 
    where("game_items.item_type = ?", item_type). 
    limit(1) 
    } 

    scope :inventory, where(:ownable_type => 'Inventory') 
    scope :warehouse, where(:ownable_type => 'Warehouse') 
end 



class GameItem < ActiveRecord::Base 

    scope :can_be_sold, where(:is_sold => 1) 

    scope :item_type, lambda { |item_type| 
    where("game_items.item_type = ?", item_type) 
    } 

    scope :item_types, lambda { |item_types| 
    where("game_items.item_type IN (?)", item_types) 
    } 

    scope :class_type, lambda { |class_type| 
    where("game_items.class_type = ?", class_type) 
    } 

    scope :grade, lambda { |grade| 
    where("game_items.grade = ?", grade) 
    } 
end 

お知らせgame_item.item_typeの問題:私のモデルは、(私が検証し、簡単にするために、いくつかの無関係なコードを削除した)今のようなものです。私はowned_itemモデルでそれを参照するため、カプセル化を破って自分自身を繰り返します。実際に私のOwnedItemモデルで繰り返しコードを追加しますが、GameItemモデルのうち、その情報を得ることなく、ある

user.inventory.owned_items.item_type('Weapon').equipped 

:どのように私は実際のような何かを行うことができることができますか?

答えて

2

私はここであなたの問題を引き起こすような方法で関係を定義したと思います。あなたは、モデルに参加した項目には、このようなものをシンプルなユーザーを使用するほうが良いです見つけることがあります。

class User < ActiveRecord::Base 
    has_many :owned_items 
    has_many :game_items, :through => :owned_items 
end 

class OwnedItem < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :game_item 

    # Has 'location' field: 'warehouse' or 'inventory' 
end 

class GameItem < ActiveRecord::Base 
    has_many :owned_items 
    has_many :users, :through => :owned_items 
end 

これは、ユーザーと、彼らはのインスタンスを所有する事のいくつかの種類を持っている一般的なパターンです。中央の関係テーブルOwnedItemは、とりわけ、GameItemのこの特定のインスタンスの固有の特性と、ユーザーに対する相対的な位置を確立するために使用されます。

一般的に、この種の構造体は、あまりにも気軽に使用すると問題になる多態性の関連付けを避けることができます。可能な限り、多態性の関連付けを避けるようにしてください。真ん中に置くと、ジョインが複雑になり、インデックスを調整するのがずっと難しくなります。元に関する注意点として

、あなたはwhereのハッシュ方式を使用して、簡単なスコープにその多くをロールアップすることができます。これは、配列や文字列引数のいずれかになりますし、使用します

scope :with_item_type, lambda { |types| 
    where('game_items.item_type' => types) 
} 

それに応じてINまたは=。実際にこの方法で行うのは、どちらを使うのか覚えておく必要がないので、とても便利です。

+0

お返事ありがとうございます:)私は実際にあなたが提案したものと同じアソシエーションを持つユーザーモデルを持っています(私はちょうどここには含まれていませんでしたが、ownedItemモデルでbelongs_toの使用を見ることができます)。私はまた、gameItemでhas_many owned_itemsを使ってみましたが、それでもuser.inventory.owned_items.game_items.item_type( 'Weapon')のようなことはできませんでした。アイテムが在庫や倉庫に置かれる可能性があるため、ここでは多態的な関連付けが必要でした。 – Spyros

+0

あなたが提案している範囲は本当に便利です。返信には+1が必要ですが、私はまだownItemモデルのカプセル化と同じ問題があります。タイプを確認するためにgameItemモデルを含む別のスコープを作成する必要があります:/ – Spyros

+0

通常、2つの異なるモデルを持つ理由は、それらが表すエンティティがそれを必要とするほど十分に異なるからです。 「インベントリ」が実際にデータの観点から「倉庫」と異なるわけではない場合、なぜそれらを位置標識属性を持つ単一のモデルに組み合わせることはできませんか?両者に若干の違いがある場合は、STIを使用しないでください。多形的な関連付けは、通常、何かが間違っているというサインです。 – tadman