我对如何有效地使用我的关联的“轨道方式”感到困惑。
以下是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])
我不确定我是否会考虑这完全错误,但似乎不可能。完成此任务的正确方法是什么?嵌套资源?自定义setter +范围?别的什么?虚拟属性?谢谢!
答案 0 :(得分: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])
答案 1 :(得分: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
的内容),这是一个坏主意。