Объединим модель Области применения Rails Way - PullRequest
1 голос
/ 28 мая 2011

Я случайно заметил, что две мои модели имеют некоторое сходство.Их зовут 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.Я ссылаюсь на это в модели own_item, тем самым нарушая инкапсуляцию и повторяя себя.Как я могу на самом деле быть в состоянии сделать что-то вроде:

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

, то есть, фактически не добавляя повторный код в мою модель OwnedItem, но получая эту информацию из модели GameItem?

1 Ответ

2 голосов
/ 28 мая 2011

Я думаю, что вы определили здесь отношения таким образом, что это вызовет у вас проблемы. Возможно, вы обнаружите, что лучше использовать простую модель соединения пользователя с элементом, что-то вроде этого:

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 или = соответственно. Это действительно очень удобно, потому что вам не нужно помнить, какой из них использовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...