2009-09-02 60 views
1

我有一个Map模型,它定义了MUD中给定区域的ASCII-art地图的细节。我希望能够使用它的名称而不是其ID来访问每个地图的页面,所以如果我有西部地区的地图,我希望能够从/maps/western_ithmia(还有/maps/withmia)访问它。需要同时创建两个相关的Rails模型

我有第二个模型,MapAlias,其中包含可用于路径到达地图的所有现有短名称。外键与每个别名一起存储,指的是其关联的Map的ID。

我想要做的是与每个新创建的Map同时创建一个新的MapAlias。不幸的是,它似乎没有得到我的新的Map的ID直到它被保存,但我不想保存它,直到我已验证/保存其新的MapAlias。更糟糕的是,我希望每个Map都知道哪个MapAlias是其主要别名,即生成链接将引用哪个。这似乎是一个循环依赖于我...

我还是很新的Rails,所以我不知道我应该做什么,但我已经探讨了模型回调钩子(像before_save)只有限的成功 - 我仍然有处理循环依赖。有任何想法吗? =/

回答

0

好了,时间公平一点后,我想我有一个工作解决方案。当我写这个问题时,Map has_many MapAlias'es,每个MapAlias都属于一个Map。我最近意识到我想要的是另一个关联:一个地图属于它的主要名称,该网站在该地图的链接中使用该名称。我添加了三个钩子 - 两个用于设置/创建别名的before_validation_on_ *,一个用于为原始关联设置别名的map_id外键的after_create - 并且它就像一个魅力一样。

对于控制器它只是一个地图。保存通话,但在内部,别名首先保存:

belongs_to :shortname, :class_name => "MapAlias" # primary name 

before_validation_on_create :add_map_alias 
def add_map_alias 
    self.create_shortname(:title => self.title) 

    @alias_failed = !(self.shortname.errors.empty?) 

    nil 
end 

before_validation_on_update :set_map_alias 
def set_map_alias 
    self.shortname.title = self.title 
    self.shortname.save(false) 

    @alias_failed = !(self.shortname.errors.empty?) 

    nil 
end 

after_create :set_alias_map_id 
def set_alias_map_id 
    self.shortname.update_attribute :map_id, self.id 

    nil 
end 

它可能不是最理想的解决方案,但它工作得很好,我的目的。感谢大家的建议,无论如何!

1

总结这一切在一个数据库事务:

Map.transaction do 
    # ... save all your stuff ... 
end 

不要试图重新实现与回调的交易......让数据库做它擅长。它会全部得到保存,否则它们都不会被保存。

0

我通常做的是手动同时创建两个模型。也就是说,如果我有两个模型,原因和效果,那么我创建了我可以创建一个原因(通常来自控制器)的所有方法,并且包含一条线,如果原因已创建,则会创建一个效果,传入这样,即使没有保存,我也可以访问它的ID(因为对象仍然存在于方法中,即使它没有保存)。

它可能不像before_save方法那样自动,但我喜欢能够看到会发生什么,以及何时,在方法之前/之后没有生根。

0

如果您试图通过html表单进行操作,可以在控制器上的新Map实例上调用build


# maps_controller.rb 
def new 
    @map = Map.new 
    @map_alias = @map.map_aliases.build 
end 

还有更多了一点(创建虚拟属性),但你可以看看这个截屏的一些想法: http://railscasts.com/episodes/75-complex-forms-part-3