Rails nested form with Ajax

I have an interesting problem with the step of creating an object in my Rails 3 music application.

I have two models (not for real models, but for simplicity): Playlist Song

Playlist has_many Songs; The song belongs to the playlist.

Each playlist object must have an exact number of songs. Each song must belong to a playlist.

With this in mind, I want to create a playlist creation process that also includes creating all the necessary songs at once.

Another thing is that to obtain Song data, the user enters a query (which I will not save in the Song model), which then collects data from the API. This is the data that should be used to create the Song object. So I can’t (don't think?) Use the traditional form_for.

Instead, I use remote form_tag. This form requests a request, and then uses an Ajax request to retrieve the data, which is placed in a temporary Song object and then displayed on a line on the playlist creation page using the Song view. This form is reused for all required Song objects for the playlist.

So, the idea is that when the user has entered the required number of requests (that is, added the required number of songs to the playlist), they will be presented with a new button that allows them to send information about the playlist and continue the process. Then a playlist will be created with all the song objects that were created using Ajax as children.

In fact, I cannot find a way for this to work in an elegant way. Although I create Song objects via Ajax, they are not saved anywhere, and they don’t know which playlist they should be added (since the playlist object does not exist in the database yet.) Therefore, when I go to the next step, I am left without all Song data. I studied using nested forms with accepts_nested_attributes_for, but I can't figure out how to use it with my setup (non-model form using Ajax.)

So I'm stuck. If anyone can help, he will be very grateful.

+4
source share
2 answers

I am having problems like this before. For the record, I never found deleted tags useful and never used them for something so complicated. You are right - the nested forms with accepts_nested_attributes_for were made for this kind of thing, and there certainly is a way to make it work.

What you need to do, after your Ajax request, generate your Song sub-fields on the fly using JavaScript. For example, let's say you have:

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

You want your Ajax callback to do something like (I assume 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 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 several things that happen there:

  • The field name "playlist [songs_attributes] ..." is what tells Rails that this field belongs to a nested attribute
  • The num_songs index after "playlist [songs_attributes] ..." is extremely important. Rather, it is extremely important that it be unique to each song. Think of it as an array index. Therefore, based on the size of an ever-growing list of songs, ideal. (This is the most complex and least obvious part of dynamically creating nested form fields, IMO.)

My code is probably not perfect, and I am sure that I did not get the field names anyway. But that should be a good start. In addition, viewing the data of the submitted forms in the application development log is very useful for debugging this material.

+1
source

Here are a few things to consider:

  • What about your users who don't have JavaScript? (I was told that these people exist.)
  • Why do you want to connect the process of creating playlists with the process of creating a song? What happened to creating a playlist as your own process? This way you can save the playlist. Then you can create songs (since this requires collecting data from a separate API), so the songs can be saved. You can then link the songs to the playlist. Consider saving user input at every step so that if he / she should stop in the middle, he / she will not lose all existing data.
  • If you first implement a non-Ajax interface, then it might be easier for you to put together the pieces to create your latest Ajax interface. Thus, you have all your necessary resources. Ajax just becomes a beautiful glue, so not many pages are updated.
0
source

Source: https://habr.com/ru/post/1333222/


All Articles