使用 Ajax 的 Rails 嵌套表单

发布于 2024-10-09 03:18:49 字数 821 浏览 0 评论 0原文

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

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

播放列表有_许多歌曲;歌曲属于播放列表。

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

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

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

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

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

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

所以,我陷入了困境。如果有人可以提供帮助,我们将不胜感激。

I have an interesting problem involving an object creation step in my Rails 3 music application.

I have two models (not the actual models; but for simplicity):
Playlist
Song

Playlist has_many Songs; Song belongs_to Playlist.

Each Playlist object must have an exact number of Songs. Each Song must belong to a Playlist.

Given this, I want to create a process for creating a Playlist that also involves creating all of the necessary Songs at the same time.

Another thing is that to get Song data, the user enters a query (which I will not be saving in the Song model), which I then gather data from an API with. This is the data that should be used to make the Song object. Therefore, I can't (don't think?) use a traditional form_for.

Instead, I'm using a remote form_tag. This form asks for a query and then uses an Ajax request to fetch the data, which is put into a temporary Song object and then displayed inline on the Playlist creation page using a Song view. This form is reused for all the necessary Song objects for the Playlist.

So, the idea is that when the user has entered the required number of queries (i.e. added the required number of songs to the playlist), they are presented with a new button that enables them to submit the playlist info and continue in the process. The Playlist will then be created with all the Song objects that were created via Ajax as children.

In reality, I can't figure out a way for this to work in an elegant way. Although I create the Song objects via Ajax, they aren't saved anywhere and they aren't aware of which Playlist they're supposed to be added into (because the Playlist object doesn't exist in the database yet either.) Therefore, when I go to the next step, I'm left without all the Song data. I looked into using nested forms with accepts_nested_attributes_for, but I can't figure out a way to use it with my setup (a non-model-based form using Ajax.)

So, I'm stuck. If anyone can help, it would be very much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

放血 2024-10-16 03:18:49

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

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

I've run into problems similar to this before. For the record, I have never found the remote tags useful and never end up using them for something this complicated. You're right - nested forms with accepts_nested_attributes_for were made for this kind of thing, and there's certainly a way to get it work.

What you need to do is, after your Ajax query, generate your nested Song fields on the fly with JavaScript. For example, let's say you have:

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

You will want your Ajax callback to do something like (I'm assuming jQuery here):

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

There are few things going on there:

  1. The field name "playlist[songs_attributes]..." is what tells Rails that that field belongs to a nested attribute
  2. The num_songs index after "playlist[songs_attributes]..." is extremely important. Rather, it's extremely important that it be unique for every song. Think of it like an array index. So basing it off of the size of the every-increasing list of songs is perfect. (This is the trickiest and least-obvious part of dynamically creating nested form fields, IMO.)

My code probably isn't perfect, and I'm sure I didn't get your field names right anyway. But it should be a good start. Also, looking at the submitted form data in your app's development log is quite helpful for debugging this stuff.

等往事风中吹 2024-10-16 03:18:49

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

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

Here are a few things to consider:

  • What about your users who don't have JavaScript available? (I've been told those people exist.)
  • Why do you want to couple the playlist creation process to the song creation process? What's wrong with creating a playlist as its own process? This way a playlist can be saved. Then you can create songs (since it requires gathering data from a separate API), so the songs can be saved. Then you can associate songs to a playlist. Consider saving the user's input at each step, so that if s/he has to stop in the middle, s/he won't lose all the existing data.
  • If you implement a not-Ajax interface first, then it may be easier for you to pull together the pieces to create your final Ajax interface. This way you have your all your necessary resources in place. The Ajax just becomes a nice glue so that there aren't so many page refreshes.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文