Rails is polymorphic for many associations.

I am trying to configure a common type of related objects. Say I have 4 models.

  • Book
  • Movie
  • Tag
  • Category

I'd like to do:

book = Book.find(1)
book.relations << Tag.find(2)
book.relations << Category.find(3)
book.relations #=> [Tag#2, Category#3]

movie = Movie.find(4)
movie.relations << book
movie.relations << Tag.find(5)
movie.relations #=> [Book#1, Tag#5]

Basically, I want to be able to accept any 2 objects of any model class (or the model class that I allow), and declare that they are related.

Obviously, I don't want to create a huge mess of join tables. This is similar to the fact that not many associations and not quite polymorphic associations.

Is this what Rails can support through association declarations or do I need to flip my own logic?

+3
source share
4 answers

. , . , has_many.

, . -, , . , .

book = Book.find(1)
book.add_related(Tag.find(2))
book.add_related(Category.find(3))
book.related        #=> [Tag#2, Category#3]
book.related(:tags) #=> [Tag#2]

, has_relations.

http://gist.github.com/123966

, - , .

+3

. Rails 2.3, - .

class Relation
  belongs_to :owner, :polymorphic => true
  belongs_to :child_item, :polymorphic => true
end

class Book
  has_many :pwned_relations, :as => :owner, :class_name => 'Relation'
  has_many :pwning_relations, :as => :child_item, :class_name => 'Relation'

  # and so on for each type of relation
  has_many :pwned_movies, :through => :pwned_relations, 
           :source => :child_item, :source_type => 'Movie'
  has_many :pwning_movies, :through => :pwning_relations, 
           :source => :owner, :source_type => 'Movie'
end

, , . , :

( pwned_movies + pwning_movies ).uniq

"" . , Insoshi, , after_create (Relation, ), . after_destroy , , .

class Relation
  after_create do 
    unless Relation.first :conditions => 
      [ 'owner_id = ? and owner_type = ? and child_item_id = ? and child_item_type = ?',       child_item_id, child_item_type, owner_id, owner_type ]
      Relation.create :owner => child_item, :child_item => owner
    end
  end
end
+7

I think the only way to do this exactly as you described is by connecting tables. This is not so bad, although there are only 6, and you can ask and forget a lot of them.

0
source

depending on how closely your db movie / book tables are closely related

what if you announced

class Items < ActiveRecord::Base
  has_many :tags
  has_many :categories
  has_and_belongs_to_many :related_items,
       :class => "Items",
       :join_table => :related_items,
       :foreign_key => "item_id",
       :associated_foreign_key => "related_item_id"
end

class Books < Items
class Movies < Items

make sure you put the type in the element table

0
source

Source: https://habr.com/ru/post/1709819/


All Articles