как получить доступ к атрибутам модели рельсов при использовании has_many: через - PullRequest
5 голосов
/ 12 марта 2009

У меня есть модель данных примерно так:

# columns include collection_item_id, collection_id, item_id, position, etc
class CollectionItem < ActiveRecord::Base
  self.primary_key = 'collection_item_id'
  belongs_to :collection
  belongs_to :item
end

class Item < ActiveRecord::Base
  has_many :collection_items
  has_many :collections, :through => :collection_items, :source => :collection
end

class Collection < ActiveRecord::Base
  has_many :collection_items, :order => :position
  has_many :items, :through => :collection_items, :source => :item, :order => :position
end

Предмет может появляться в нескольких коллекциях, а также более одного раза в одной коллекции в разных позициях.

Я пытаюсь создать вспомогательный метод, который создает меню, содержащее каждый элемент в каждой коллекции. Я хочу использовать collection_item_id для отслеживания текущего выбранного элемента между запросами, но я не могу получить доступ к каким-либо атрибутам модели соединения через класс Item.

def helper_method( collection_id )
  colls = Collection.find :all
  colls.each do |coll|
    coll.items.each do |item|
# !!! FAILS HERE ( undefined method `collection_item_id' )
      do_something_with( item.collection_item_id )
    end
  end
end

Я тоже это пробовал, но и с ошибкой (неопределенный метод `collection_item ')

do_something_with( item.collection_item.collection_item_id )

Редактировать: спасибо serioys sam за указание на то, что вышеприведенное явно неверно

Я также пытался получить доступ к другим атрибутам в модели соединения, например:

do_something_with( item.position )

и

do_something_with( item.collection_item.position )

Редактировать: спасибо serioys sam за указание на то, что вышеприведенное явно неверно

но они тоже терпят неудачу.

Может кто-нибудь посоветовать мне, как поступить с этим?

Редактировать: -------------------->

Из онлайн-документации я обнаружил, что использование has_and_belongs_to_many будет прикреплять атрибуты объединяемой таблицы к полученным элементам, но, видимо, это не рекомендуется. Я еще не пробовал.

В настоящее время я работаю над внесением поправок в мою коллекционную модель следующим образом:

class Collection < ActiveRecord::Base
  has_many :collection_items, :order => :position, :include => :item
  ...
end

и изменение помощника для использования coll.collection_items вместо coll.items

Редактировать: -------------------->

Я поменял своего помощника на работу, как указано выше, и она отлично работает - (спасибо Сэм)

Это испортило мой код - из-за других факторов, не детализированных здесь - но ничего, что час или два перефакторинга не уладят.

Ответы [ 3 ]

3 голосов
/ 12 марта 2009
do_something_with( item.collection_item_id )

Сбой, потому что элемент не имеет члена collection_item_id.

do_something_with( item.collection_item.collection_item_id )

Это не удалось, поскольку элемент не имеет члена collection_item.

Помните, что отношение между item и collection_items является has_many. Таким образом, элемент имеет collection_items, а не просто один элемент. Также у каждой коллекции есть список предметов коллекции. Что вы хотите сделать, это, вероятно, это:

colls = Collection.find :all
colls.each do |coll|
  coll.collection_items.each do |collection_item|
    do_something_with( collection_item.id )
  end
end

Несколько других советов:

  • Читали ли вы документацию для has_many: через в Руководствах по Rails? Это очень хорошо.
  • Вам не нужно указывать параметры: source в объявлениях has_many, поскольку вы разумным образом назвали свои модели и ассоциации.

Из онлайн-документации я обнаружил, что использование has_and_belongs_to_many будет прикреплять атрибуты объединяемой таблицы к полученным элементам, но, очевидно, это не рекомендуется. Я еще не пробовал.

Я рекомендую вам придерживаться has_many: through, поскольку has_and_belongs_to_many более запутанна и не дает никаких реальных преимуществ.

3 голосов
/ 12 марта 2009

В вашем примере вы определили в модели модели Item как has_many для collection_items и коллекций, сгенерированный метод ассоциации - collection_items и collection, соответственно, оба они возвращают массив, поэтому способ, которым вы пытаетесь получить доступ, здесь неправильный. это в первую очередь случайное отношение ко многим отношениям. просто проверьте эту документацию ассоциации для дальнейшего использования.

0 голосов
/ 27 октября 2010

Я смог заставить это работать для одной из моих моделей:

class Group < ActiveRecord::Base
  has_many :users, :through => :memberships, :source => :user do
    def with_join
      proxy_target.map do |user|
        proxy_owner = proxy_owner()
        user.metaclass.send(:define_method, :membership) do
          memberships.detect {|_| _.group == proxy_owner}
        end
        user
      end
    end
  end
end

В вашем случае что-то подобное должно работать (не проверялось):

class Collection < ActiveRecord::Base
  has_many :collection_items, :order => :position
  has_many :items, :through => :collection_items, :source => :item, :order => :position do
    def with_join
      proxy_target.map do |items|
        proxy_owner = proxy_owner()
        item.metaclass.send(:define_method, :join) do
          collection_items.detect {|_| _.collection == proxy_owner}
        end
        item
      end
    end
  end
end

Теперь у вас должен быть доступ к CollectionItem из Предмета, если вы обращаетесь к своим предметам следующим образом (items.with_join):

def helper_method( collection_id )
  colls = Collection.find :all
  colls.each do |coll|
    coll.items.with_join.each do |item|
      do_something_with( item.join.collection_item_id )
    end
  end
end

Вот более общее решение, которое вы можете использовать, чтобы добавить это поведение к любой has_many :through ассоциации: http://github.com/TylerRick/has_many_through_with_join_model

class Collection < ActiveRecord::Base
  has_many :collection_items, :order => :position
  has_many :items, :through => :collection_items, :source => :item, :order => :position, :extend => WithJoinModel
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...