has_many: через has_and_belongs_to_many ассоциацию

Я пытаюсь сделать следующее в проекте Ruby on Rails:

class FoodItem < ActiveRecord::Base
  has_and_belongs_to_many :food_categories
  has_many :places, :through => :food_categories
end

class FoodCategory < ActiveRecord::Base
  has_and_belongs_to_many :food_items
  belongs_to :place
end

class Place < ActiveRecord::Base  
  has_many :food_categories
  has_many :food_items, :through => :food_category
end

Но вызов метода экземпляра some_food_item.places дает мне следующую ошибку:

ActiveRecord::StatementInvalid: PGError: ERROR:  column 
food_categories.food_item_id does not exist
LINE 1: ...laces".id = "food_categories".place_id    WHERE (("food_cate...

: SELECT "places".* FROM "places"  INNER JOIN "food_categories" ON "places".id = "food_categories".place_id    WHERE (("food_categories".food_item_id = 1))

Который имеет смысл - из-за HABTMs на FoodItem и FoodCategory, мне назвали таблицу отображения food_categories_food_items.

Что я должен сделать для получения some_food_item.places искать места правильно через таблицу отображения вместо того, чтобы искать a food_item_id в food_categories таблица?

6
задан CDspace 2 November 2017 в 21:43
поделиться

3 ответа

Моя первая версия ответа была неверной, но это работает отлично. Я сделал пару опечаток в первый раз (опасность не создает приложение для тестирования), но на этот раз я проверил. И нужен плагин, но это легко. Во-первых, установите плагин:

script/plugin install git://github.com/ianwhite/nested_has_many_through.git

Это устанавливает обходной путь IAN White, и он работает без проблем. Теперь модели, скопированные непосредственно из тестируемого приложения, я настроив, чтобы получить эту работу:

class FoodItem < ActiveRecord::Base
  has_many :food_category_items
  has_many :food_categories, :through => :food_category_items
  has_many :places, :through => :food_categories
end

class FoodCategory < ActiveRecord::Base
  has_many :food_category_items
  has_many :food_items, :through => :food_category_items
  belongs_to :place
end

class FoodCategoryItem < ActiveRecord::Base
  belongs_to :food_item
  belongs_to :food_category
end

class Place < ActiveRecord::Base
  has_many :food_categories
  has_many :food_category_items, :through => :food_categories
  has_many :food_items, :through => :food_category_items
end

сейчас работают «далеко» ассоциации. Place_Instance.food_items и food_item.places Оба работают без безусловно, а также более простые ассоциации. Просто для справки, вот моя схема, чтобы показать, где все иностранные ключи идут:

create_table "food_categories", :force => true do |t|
  t.string   "name"
  t.integer  "place_id"
  t.datetime "created_at"
  t.datetime "updated_at"
end

create_table "food_category_items", :force => true do |t|
  t.string   "name"
  t.integer  "food_item_id"
  t.integer  "food_category_id"
  t.datetime "created_at"
  t.datetime "updated_at"
end

create_table "food_items", :force => true do |t|
  t.string   "name"
  t.datetime "created_at"
  t.datetime "updated_at"
end

create_table "places", :force => true do |t|
  t.string   "name"
  t.datetime "created_at"
  t.datetime "updated_at"
end

Надеюсь, это поможет!

Обновление: Этот вопрос недавно пришел в несколько раз. Я написал статью, вложил свой HAS_MANY: через отношения , подробно объяснить. Он даже имеет приложение пример на Github, чтобы загрузить и играть с.

7
ответ дан 10 December 2019 в 02:47
поделиться

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

class FoodItem < ActiveRecord::Base
  has_and_belongs_to_many :food_categories
  named_scope :in_place, lambda{ |place|
    {
      :joins      => :food_categories,
      :conditions => {:food_categories => {:id => place.food_category_ids}},
      :select     => "DISTINCT `food_items`.*" # kill duplicates
    }
  }
end

class FoodCategory < ActiveRecord::Base
  has_and_belongs_to_many :food_items
  belongs_to :place
end

class Place
  has_many :food_categories
  def food_items
    FoodItem.in_place(self)
  end
end

Это даст вам uDe_food_item.places .

2
ответ дан 10 December 2019 в 02:47
поделиться

Это правильно, потому что вы не можете PEFORM «имеет много через таблицу присоединения. По сути, вы пытаетесь продлить отношения в одну степень дальше, чем вы действительно можете. Habtm (has_and_belongs_to_many) - не очень надежное решение для большинства проблем.

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

class FoodItem < ActiveRecord::Base
  has_many :food_categories, :through => :food_category_items
  has_many :places, :through => :food_categories
end

class FoodCategory < ActiveRecord::Base
  has_many :food_items, :through => :food_category_items
  belongs_to :place
end

class FoodCategoryItems < ActiveRecord::Base
  belongs_to :food_item
  belongs_to :food_category
end

class Place < ActiveRecord::Base  
  has_many :food_categories
  has_many :food_items, :through => :food_categories
end

Примечание, я также зафиксировал опечаток в «месте -> has_many: food_items». Это должно позаботиться о том, что вам нужно, и предоставить вам дополнительный бонус, чтобы быть в состоянии добавить функциональность в модель ваших продуктов питания в будущем.

-1
ответ дан 10 December 2019 в 02:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: