has_many通过第三个模型的角色和范围

时间:2015-04-22 00:21:43

标签: ruby-on-rails ruby activerecord

假设我有电影,人物和电影人物

class Person < ActiveRecord::Base
  has_many :movies_people
  has_many :movies, through: :movies_people

class Movies < ActiveRecord::Base
  has_many :movies_people
  has_many :people, through: :movies_people


class MoviesPerson < ActiveRecord::Base
  belongs_to :movie
  belongs_to :person
end

movies_people有一个角色属性,我想在电影中存储这个人的工作。现在我可以在控制台中做这样的事情:

u = User.first
m = Movie.first
m.people << u

然后找到合适的movies_people条目并设置&#39;角色&#39;

检索看起来像这样:

m.people.where(movies_people: {role: :actor})

最好的方法是:

  1. 将人加入电影时保存角色( 到第三个表格 )?
  2. 归还电影中的所有演员与所有导演和所有作家?

2 个答案:

答案 0 :(得分:2)

一种解决方案是创建Roles,其中包含现有角色列表和MovieRole 加入电影,人物和角色的课程。

class Movie < ActiveRecord::Base
  has_many :movie_roles, class_name: "MovieRole"
  has_many :roles, through: :movie_roles
  has_many :people, through: :movie_roles
end

class People < ActiveRecord::Base
  has_many :movie_roles, class_name: "MovieRole"
  has_many :movies, through: :movie_roles
  has_many :roles, through: :movie_roles
end

class Role < ActiveRecord::Base
  has_many :movie_roles, class_name: "MovieRole"
  has_many :people, through: :movie_roles
  has_many :movies, through: :movie_roles
end

class MovieRole < ActiveRecord::Base
  belongs_to :movie
  belongs_to :people
  belongs_to :role
end

所有关系都是movie_roles中的商店,这是一个三向连接表:

class CreateMovieRoles < ActiveRecord::Migration
  def change
    create_table :movie_roles do |t|
      t.references :movie, index: true
      t.references :people, index: true
      t.references :role, index: true
      t.timestamps
    end
  end
end

您可以如何查询此关联的一些示例:

@roles = Movie.find_by(title: 'Godzilla').roles
@directors = People.joins(:roles).where(roles: {name: 'Director'})
@directed_by_eastwood = Movie.joins(:people, :roles)
                               .merge(Role.where(name: 'Director'))
                               .merge(People.where(name: 'Clint Eastwood'))

加了:

要将某人与电影相关联,您需要:

MovieRole.create(people: person, movie: movie, role: role)

但是你需要设置方便的方法,如:

class People < ActiveRecord::Base
  def add_role(role, movie)
    role = Role.find_by(name: role) unless role.is_a?(Role)
    MovieRole.create(people: self, movie: movie, role: role)
  end 
end

class Movie < ActiveRecord::Base
  def add_cast(role, person)
    role = Role.find_by(name: role) unless role.is_a?(Role)
    MovieRole.create(people: person, movie: self, role: role)
  end 
end

答案 1 :(得分:1)

要保存角色,只需:

person = Person.find(person_id)
movie = Movie.find(movie_id)

movie.movies_people.create(person: person, role: :actor)

按角色检索

movie = Movie.includes(:people).where(id: movie_id).where(movies_people: {role: :actor})

编辑:除非您需要,否则我不建议添加角色表。我遵循agile principles,在这种情况下:“简单 - 最大化未完成工作量的艺术 - 是必不可少的。”