2013-06-12 61 views
4

我对我应该如何去关于有效使用我的关联的“轨道方式”完全感到困惑。如何创建一个自动设置连接表属性的关联?

下面是从一个轨道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

如果你有一个正常的has_and_belongs_to_many关系,即在电影和参与者之间,那么你可以创建一个电影连同你的例子。

由于您的加盟模式更复杂,你必须单独建立roleships:

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]) 

的是,所有的属性用于构建roleships和电影必须是质量分配,所以在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的内容),这是一个坏主意的数据,使你的代码。

+0

这岂不是有不利影响的道路?例如,如果有嵌套表单(即从视图中构建电影),那么这将全部被推入一个胖子控制器中?另外,正如我所提到的,这是一个rails4应用程序(使用强参数) – Hodor

+0

您可以将角色的创建推送到模型,然后您必须将所有必要的参数传递给该创建函数。这样你就可以用某种“自定义嵌套属性”来构建表单 –

+0

我想我在概念上理解,但我无法准确设想代码的样子。 – Hodor

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])

+0

非常感谢您将此置入一个真正的应用程序和回购。实际上,我没有投入参与者和角色模型,因为构建它们与我的问题无关。基本上我想知道我应该如何设置我的关联来支持编写类似于“我愿意的代码”下的代码 – Hodor

+0

好的。我懂了。你可以在seed.rb中看到一个例子。确实,在我的解决方案中,角色可以是动态的,而不仅仅是作家。 – Zoltan

+0

使用虚拟属性更新的答案。 – Zoltan

相关问题