使用Ajax导航嵌套表单

时间:2010-12-23 18:05:19

标签: ruby-on-rails ajax ruby-on-rails-3 nested-forms

我有一个有趣的问题,涉及我的Rails 3音乐应用程序中的对象创建步骤。

我有两个型号(不是实际型号;但为了简单起见): 播放列表 曲

播放列表has_many歌曲;歌曲属于播放列表。

每个播放列表对象必须具有确切数量的歌曲。每首歌必须属于播放列表。

鉴于此,我想创建一个创建播放列表的过程,该过程还涉及同时创建所有必需的歌曲。

另一件事是,要获取Song数据,用户输入一个查询(我不会在Song模型中保存),然后我从API收集数据。这是应该用于制作Song对象的数据。因此,我不能(不要认为?)使用传统的form_for。

相反,我正在使用远程form_tag。此表单要求查询,然后使用Ajax请求获取数据,该数据被放入临时Song对象,然后使用Song视图在播放列表创建页面上内联显示。此表单将重复用于播放列表的所有必需的Song对象。

因此,我们的想法是,当用户输入所需数量的查询(即将所需数量的歌曲添加到播放列表中)时,会向他们显示一个新按钮,使他们能够提交播放列表信息并继续这个过程。然后将创建播放列表,其中包含通过Ajax作为子项创建的所有Song对象。

实际上,我无法找到一种优雅的工作方式。虽然我通过Ajax创建了Song对象,但它们并没有保存在任何地方,并且他们不知道应该添加哪个播放列表(因为播放列表对象在数据库中也不存在。)因此,当我进入下一步时,我没有收到所有的宋数据。我研究了使用带有accepts_nested_attributes_for的嵌套表单,但我无法找到一种方法将它用于我的设置(使用Ajax的非基于模型的表单。)

所以,我被困住了。如果有人可以提供帮助,我们将非常感激。

2 个答案:

答案 0 :(得分:1)

我之前遇到过类似的问题。为了记录,我从来没有发现远程标签有用,并且永远不会最终使用它们来处理这个复杂的事情。你是对的 - 带有accepts_nested_attributes_for的嵌套表单就是为这种东西而制作的,而且肯定有办法让它工作。

在Ajax查询之后,您需要做的是使用JavaScript动态生成嵌套的Song字段。例如,假设你有:

<form...>
  <input type="text" name="playlist[name]" />
  <div class="songs">
  </div>
</form>

你会希望你的Ajax回调做类似的事情(我在这里假设jQuery):

<script type="text/javascript">
  $(function() {
    var songs = $('form .songs') // Store a reference to the DOM song container
    // Insert Ajaxy goodness for song lookup here.
    // When it's finished, it should call add_song and pass in any data it needs
  })

  function add_song(song_name, artist_name, artist_id) {
    var num_songs = $(songs).size()
    $(songs).append('<p>'+song_name+' by '+artist_name+
      '<input type="hidden" name="playlist[songs_attributes]['+num_songs+'][name]" value="'+song_name+'" />' +
      '<input type="hidden" name="playlist[songs_attributes]['+num_songs+'][artist_id]" value="'+artist_id+'" /></p>')
  }
</script>

那里发生的事情很少:

  1. 字段名称“playlist [songs_attributes] ...”告诉Rails该字段属于嵌套属性
  2. “播放列表[songs_attributes] ...”之后的num_songs索引非常重要。相反,它对每首歌都是独一无二的非常重要。把它想象成一个数组索引。所以基于每个增加的歌曲列表的大小是完美的。 (这是动态创建嵌套表单字段的最棘手和最不明显的部分,IMO。)
  3. 我的代码可能并不完美,我确信无论如何我都没有正确的字段名称。但这应该是一个好的开始。此外,在应用程序的开发日志中查看提交的表单数据对于调试这些内容非常有用。

答案 1 :(得分:0)

以下是需要考虑的一些事项:

  • 没有JavaScript的用户怎么样? (我被告知那些人存在。)
  • 为什么要将播放列表创建过程与歌曲创建过程相结合?将播放列表创建为自己的流程有什么问题?这样可以保存播放列表。然后您可以创建歌曲(因为它需要从单独的API收集数据),因此可以保存歌曲。然后,您可以将歌曲与播放列表相关联。考虑在每一步保存用户的输入,这样如果他/她必须在中间停止,他/她将不会丢失所有现有数据。
  • 如果您首先实现非Ajax接口,那么您可能更容易将各个部分组合在一起以创建最终的Ajax接口。这样您就拥有了所有必要的资源。 Ajax刚刚成为一个很好的粘合剂,因此没有那么多的页面刷新。