Search code examples
ruby-on-railsrubyserializationruby-on-rails-3.2to-json

Syntax error in as_json when using multi level :include


I've got two models that are connected through a third one:

Playlist has_many :song_in_playlists, :dependent => :destroy
         has_many :songs, :through => :song_in_playlists

Song has_many :song_in_playlists, :dependent => :destroy
     has_many :playlists, :through => :song_in_playlists

The song_in_playlist table simply lists the playlist_id, song_id, as well as a track_number.

When calling /playlists/1.json, I'd like to get a json hash that holds the playlist's attributes and has another hash inside, which contains the songs (as in /songs.json plus the track_number from the song_in_playlists table entry).

According to the Rails API, I should be able to achieve this doing the following:

  def show
    @playlist = Playlist.find(params[:id])
    [...]
      respond_to do |format|
        format.html # show.html.erb
        format.json { render json: @playlist.as_json(
                           :include => { :song_in_playlists => { 
                              :only => :track_number, :include => :songs { 
                                 :except => [:dropbox_link, :local_path] } } } 
                            ) }
      end
    end
  end

However, what I do get is the following:

/home/sloth/audiomixer/app/controllers/playlists_controller.rb:30: syntax error, unexpected '{', expecting '}'
            :only => :track_number, :include => :songs { 
                                                        ^
/home/sloth/audiomixer/app/controllers/playlists_controller.rb:31: syntax error, unexpected '}', expecting keyword_end
              :except => [:dropbox_link, :local_path] } } } 
                                                         ^
/home/sloth/audiomixer/app/controllers/playlists_controller.rb:103: syntax error, unexpected $end, expecting keyword_end

So I tried a little less complexity, calling

format.json { render json: @playlist.as_json( 
                                :include => song_in_playlists { 
                                   :only => :track_number } ) }

but I'm getting a similar error. As soon as I'm putting any braces in between the parentheses, Rails complains, although the API documentation states the opposite.

I really don't know what to try anymore :(

PS: Ruby 1.9.3, Rails 3.2.13

--- EDIT --- Okay, I don't really know why but I got this to produce the expected output:

format.json { render json: @playlist.as_json( 
                    :include => { :song_in_playlists => { 
                       :include => :song, :only => :track_number } } ) }

However, when trying to add { :except => [:dropbox_link, :local_path] } in between :song and , :only, I'm getting the same errors again..


Solution

  • This is only partly about rails

    :include => song_in_playlists {:only => :track_number}
    

    just isn't valid ruby syntax

    this should be

    :include => {:song_in_playlists => {:only => :track_number}}
    

    Each time, the key is the association name (song_in_playlists) and the value is hash containing one or more of the keys :only, :except or :include

    If you want to change what attributes from the songs table are in the json then you need to take

    format.json { render json: @playlist.as_json( 
                    :include => { :song_in_playlists => { 
                       :include => :song, :only => :track_number } } ) }
    

    and replace :song with a hash that describes what you want to do with song, for example

    format.json { render json: @playlist.as_json( 
                    :include => { 
                      :song_in_playlists => { 
                        :include => {
                          :song => {
                            :except => [:dropbox_link, :local_path]
                          }
                        }, 
                        :only => :track_number 
                      } 
                     })}