Несколько ВНУТРЕННИХ СОЕДИНЕНИЙ в отношении Rails has_many? - PullRequest
0 голосов
/ 30 октября 2011

У меня есть следующие модели:

class Image < ActiveRecord::Base
  belongs_to :gallery
  has_many :bookmarks
  has_many :gallery_tags, :foreign_key => :gallery_id
end

class Bookmark < ActiveRecord::Base
  belongs_to :user
  belongs_to :image
  has_many :gallery_tags, :through => :image, :source => :gallery_tags
end


class GalleryTag < ActiveRecord::Base
  belongs_to :gallery
  belongs_to :tag
end

class Gallery < ActiveRecord::Base
  belongs_to :provider
  has_many :images
  belongs_to :user
  has_many :gallery_tags
  has_many :tags, :through => :gallery_tags
end

class Tag < ActiveRecord::Base
end

class User < ActiveRecord::Base
  has_many :bookmarks
  has_many :galleries
end

Я бы хотел иметь возможность

User.find(1).bookmarked_tags

и извлекает все теги, связанные со всеми изображениями пользователя, добавленными в закладки, через галереи, связанные с изображениями Теги связаны с галереями.

Запрос будет выглядеть так:

SELECT
  tags.*
FROM
  tags
  INNER JOIN gallery_tags ON gallery_tags.tag_id = tags.id
  INNER JOIN images ON gallery_tags.gallery_id = images.gallery_id
  INNER JOIN bookmarks ON images.id = bookmarks.image_id
WHERE
  bookmarks.user_id = 1
GROUP BY
  tags.id;

Я пытался добавить

has_many :tags, :through => :gallery_tags, :foreign_key => :gallery_id

to Image, что приводит к тому, что Image.find (34) .tags приводит к

SELECT `tags`.* FROM `tags` INNER JOIN `gallery_tags` ON `tags`.id = `gallery_tags`.tag_id WHERE ((`gallery_tags`.gallery_id = 34))

(в запросе не используется gallery_id изображения), а затем я попытался добавить

has_many :bookmarked_tags, :through => :bookmarked_images, :source => :tags

для пользователя, что приводит к тому, что User.find (1) .bookmarked_tags приводит к

ActiveRecord :: HasManyThroughSourceAssociationMacroError: Неверно макрос отражения источника: has_many: through для has_many : bookmarked_tags,: through =>: bookmarked_images. Использование: источник для укажите источник отражения.

Итак: как я могу заставить Rails выполнить запрос, который я отправил с помощью User.find (1) .bookmarked_tags?

1 Ответ

3 голосов
/ 31 октября 2011

есть два решения

Первое решение :

Создайте представление в вашей базе данных, которое действует как таблица соединения:

CREATE VIEW user_bookmarks_tags (
  SELECT
    bookmarks.user_id AS user_id  
    gallery_tags.tag_id AS tag_id
  FROM
    gallery_tags
    INNER JOIN images ON gallery_tags.gallery_id = images.gallery_id
    INNER JOIN bookmarks ON images.id = bookmarks.image_id
  GROUP BY
    user_id, tag_id
)

(вы можете сделать это внутри миграции) Это представление действует как «таблица» со столбцами user_id | tag_id

Теперь мы можем адаптировать наши модели, используя has_and_belongs_to_many:

user.rb

class User < ActiveRecord::Base
  has_many :bookmarks
  has_many :galleries

  # we use our magic (view) join table here!
  has_and_belongs_to_many :tags, :join_table => :user_bookmarks_tags
end

tag.rb

class Tag < ActiveRecord::Base
  # we use our magic (view) join table here
  has_and_belongs_to_many :users, :join_table => :user_bookmarks_tags
end

Теперь вы можете сделать: User.find(1).tags или Tag.find(1).users:)


Второй раствор

Выполнить объединение вручную без просмотра:

определить отсутствующие отношения (необходимые для автоматического поиска иностранных_ключей):

tag.rb

class Tag < ActiveRecord::Base
  has_many  :gallery_tags
end

gallery_tag.rb

class GalleryTag < ActiveRecord::Base
  belongs_to :gallery
  belongs_to :tag
  # new:
  has_many :images, :through => :gallery
end

Теперь мы можем добавить bookmarked_tags метод к нашему user.rb

class User < ActiveRecordBase
  has_many :bookmarks
  has_many :galleries

  def bookmarked_tags
    Tag.joins(:gallery_tags => {:images => :bookmarks}).where('bookmarks.user_id = ?', self.id).group('tags.id')
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...