【问题标题】:Rails Nested Form with Ajax使用 Ajax 的 Rails 嵌套表单
【发布时间】:2010-12-23 18:05:18
【问题描述】:

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

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

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

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

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

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

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

    我之前遇到过类似的问题。作为记录,我从未发现远程标签有用,也从未最终将它们用于如此复杂的事情。你是对的 - 带有 accept_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. “playlist[songs_attributes]...”之后的 num_songs 索引非常重要。相反,对于每首歌曲来说,它都是独一无二的,这一点非常重要。把它想象成一个数组索引。因此,根据不断增加的歌曲列表的大小来确定它是完美的。 (这是动态创建嵌套表单字段中最棘手和最不明显的部分,IMO。)

    我的代码可能并不完美,而且我确定我没有正确地获取您的字段名称。但这应该是一个好的开始。此外,查看应用程序开发日志中提交的表单数据对于调试这些内容非常有帮助。

    【讨论】:

    • 谢谢!这看起来符合我的需要。我会尝试一下。 :)
    • 我意识到以这种方式使用隐藏字段将允许用户编辑我不想要的数据。我尝试做的解决方法是将查询保存在隐藏字段中。但是,这迫使我不得不在播放列表“创建”方法中重新获取外部数据,这很慢。如果我首先创建并保存播放列表,然后在用户输入时创建并保存每首歌曲,这一切都会更简单。但是,我不想最终得到不包含给定数量歌曲的播放列表。我希望有某种临时数据库存储。
    【解决方案2】:

    这里有几点需要考虑:

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

    【讨论】:

    • 好点,虽然我已经考虑过这些。由于其他原因,整个应用程序需要 JavaScript,所以我不太关心支持没有启用它的用户。我希望将这些过程联系起来的原因是对象必然是相互联系的。也就是说,我不想要一个不包含所有“x”歌曲的播放列表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多