4

我完全不知道我应该如何去有效地使用我的联想的“轨道方式”。

这是来自 Rails 4 应用程序的示例模型配置:

class Film < ActiveRecord::Base
  # A movie, documentary, animated short, etc
  has_many :roleships
  has_many :participants, :through => :roleships
  has_many :roles, :through => :roleships
  # has_many :writers........ ?
end

class Participant < ActiveRecord::Base
  # A human involved in making a movie
  has_many :roleships
end

class Role < ActiveRecord::Base
  # A person's role in a film. i.e. "Writer", "Actor", "Extra" etc
  has_many :roleships
end

class Roleship < ActiveRecord::Base
  # The join for connecting different people
  # to the different roles they have had in
  # different films
  belongs_to :participant
  belongs_to :film
  belongs_to :role
end

鉴于上述模型配置,我希望我拥有的代码将允许我直接将作者添加到电影中,并最终正确设置连接。

例如,我希望能够做这样的事情:

## The Code I WISH I Had
Film.create!(name: "Some film", writers: [Participant.first])

我不确定我是否要考虑完全错误的想法,但这似乎是不可能的。实现这一目标的正确方法是什么?嵌套资源?自定义设置器+范围?还有什么?虚拟属性?谢谢你!

4

2 回答 2

3

我根据您的问题创建了一个示例应用程序。 https://github.com/szines/hodor_filmdb

我认为在参与者和角色模型中设置通过关联也很有用,但没有这个也可以。这取决于您以后想如何使用这个数据库。没有通过此查询将无法正常工作:Participant.find(1).films

class Participant < ActiveRecord::Base
  has_many :roleships
  has_many :films, through: :roleships
end

class Role < ActiveRecord::Base
  has_many :roleships
  has_many :films, through: :roleships
end

不要忘记为您的films_controller.rb 中的额外字段(strong_parameters)提供许可

def film_params
  params.require(:film).permit(:title, :participant_ids, :role_ids)
end

奇怪的是,如果您创建一个包含参与者和角色的新电影,则会在连接表中创建两条记录。

更新:

您可以在模型中创建一种虚拟属性。例如:

def writers=(participant)
  @writer_role = Role.find(1)
  self.roles << @writer_role
  self.participants << participant
end

你可以使用:Film.create(title: 'The Movie', writers: [Participant.first])

于 2013-06-13T07:35:27.267 回答
0

如果您有正常的has_and_belongs_to_many关系,即电影和参与者之间的关系,那么您可以将您的示例与电影一起制作。

由于您的加入模型更加复杂,您必须单独构建角色:

writer= Roleship.create(
          participant: Participant.find_by_name('Spielberg'),
          role: Role.find_by_name('Director')
        )
main_actor= Roleship.create(
          participant: Participant.find_by_name('Willis'),
          role: Role.find_by_name('Actor')
        )

Film.create!(name: "Some film", roleships: [writer, main_actor])

为此,您用于构建角色和电影的所有属性都必须是可批量分配的,因此在 Rails 3.2 中您必须编写:

class Roleship < ActiveRecord::Base
   attr_accessible :participant, :role
   ...
end

class Film < ActiveRecord::Base
   attr_accessible :name, :roleships
   ...
end

如果你想使用 roleship_ids,你必须写

class Film < ActiveRecord::Base
   attr_accessible :name, :roleship_ids
   ...
end

附录:

当然你可以写一个setter方法

class Film ...

  def writers=(part_ids)
     writer_role=Role.find_by_name('Writer')
     # skiped code to delete existing writers
     part_ids.each do |part_id|
        self.roleships << Roleship.new(role: writer_role, participant_id: part_id)
     end
  end
end

但这会使您的代码取决于数据库中的数据(表的内容roles),这是一个坏主意。

于 2013-06-12T23:25:35.803 回答