需要同时创建两个相关的Rails模型

时间:2009-09-02 08:19:20

标签: ruby-on-rails activerecord

我有一个Map模型,它定义了MUD中给定区域的ASCII艺术地图的详细信息。我希望能够使用其名称而不是ID来访问每个地图的页面,因此,如果我有西方Ithmia地图,我希望能够从/maps/western_ithmia访问它(还有{{1} })。

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

我想要做的是与每个新创建的Map同时创建一个新的MapAlias。不幸的是,我似乎无法获取新的Map ID,直到它被保存为止,但在我验证/保存新的Map之前我不想保存它。 。更糟糕的是,我希望每个MapAlias知道哪个Map是其主要别名,即生成链接所引用的别名。这似乎是对我的循环依赖...

我还是Rails的新手,所以我不确定我应该做什么,但是我已经探索了模型回调钩子(比如before_save),只取得了有限的成功 - 我仍然有循环依赖来处理。有任何想法吗? = /

4 个答案:

答案 0 :(得分:1)

在数据库事务中包装所有内容:

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

不要尝试使用回调重新实现事务...让数据库做它擅长的事情。它会全部被保存,或者没有一个被保存。

答案 1 :(得分:0)

我通常做的是同时手动创建两个模型。也就是说,如果我有两个模型,原因和结果,那么我创建我查看可以创建原因的所有方法(通常来自控制器),并包括一个创建一个效果的行,如果创建原因,传入原因中的相应参数..这样,即使它没有保存,我也可以访问它的ID(因为该对象仍然存在于方法中,即使它没有保存)。

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

答案 2 :(得分:0)

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


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

还有更多内容(创建虚拟属性),但您可以查看此截屏视频以获取一些想法: http://railscasts.com/episodes/75-complex-forms-part-3

答案 3 :(得分:0)

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

对于控制器来说,它只是一个Map.save调用,但在内部,别名首先被保存:

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

它可能不是最理想的解决方案,但它适用于我的目的。无论如何,谢谢大家的建议!