has_many通过Rails AngularJS Restangular'POST'

时间:2016-10-12 01:27:15

标签: ruby-on-rails angularjs post has-many-through restangular

我希望创建一个音乐应用,用户可以在其中添加歌曲到播放列表。我创建了一个has_many通过关联,以便将“playlist_songs”添加到播放列表而不是“歌曲”

以下是一些相关代码,可以让您更好地了解。

playlist_song.rb

class PlaylistSong < ActiveRecord::Base
  belongs_to :playlist
  belongs_to :song
end

song.rb

class Song < ActiveRecord::Base
  belongs_to :album
  has_many :playlist_songs
  has_many :playlists, through: :playlist_songs
end

playlist.rb

class Playlist < ActiveRecord::Base
  belongs_to :user
  has_many :playlist_songs
  has_many :songs, through: :playlist_songs
end

Song.attribute_names

["id", "url", "name", "created_at", "updated_at", "album_id", "song_title"]

PlaylistSong.attribute_names

["id", "playlist_id", "song_id", "created_at", "updated_at"]

我要做的是将playlist_song添加到特定的播放列表。我认为最好的方法是简单地创建一个playlist_song,它只有song_id和playlist_id属性。这将引用我需要的歌曲网址,以及该歌曲所属的播放列表_id。

我想将playlist_song保存到显示以下内容的网址http://localhost:3000/api/user_profiles/1/playlists/8/song_references

[
  {
    "id": 14,
    "playlist_id": 8,
    "song_id": 2,
    "created_at": "2016-09-25T15:43:36.459Z",
    "updated_at": "2016-09-25T15:43:36.459Z"
  },
  {
    "id": 15,
    "playlist_id": 8,
    "song_id": 3,
    "created_at": "2016-09-25T15:43:36.460Z",
    "updated_at": "2016-09-25T15:43:36.460Z"
  }
]

与网址http://localhost:3000/api/user_profiles/1/playlists/8/playlist_songs明显不同,后者显示与特定播放列表相关的实际歌曲属性:

[
  {
    "id": 3,
    "url": "https://www.song3url.mp3",
    "name": "05 Smoke Signal (Original Mix).mp3",
    "created_at": "2016-09-24T02:33:46.648Z",
    "updated_at": "2016-09-29T03:44:35.464Z",
    "album_id": 1,
    "song_title": null
  },
  {
    "id": 2,
    "url": "https://www.song2url.mp3",
    "name": "07 The Son Of Flynn (Remixed by Moby).mp3",
    "created_at": "2016-09-24T02:25:52.373Z",
    "updated_at": "2016-09-24T02:25:52.373Z",
    "album_id": 1,
    "song_title": null
  }
]

您可以在下面看到我的routes.rb文件的特定API部分:

  namespace :api, defaults: { format: :json } do
    # resources :newsfeed_item
    resources :chat_rooms do
      resources :chat_messages
    end
    resources :playlists do
      resources :playlist_songs
    end
    resources :songs
    resources :venue_requests
    resources :user_profiles do
      resources :libraries
      resources :playlists do
        resources :playlist_songs
        resources :song_references
      end
    end
    resources :artist_profiles do
      resources :albums do
        resources :album_songs
      end
    end
  end

以下是显示playlist_songs的song_references_controller.rb文件:

class Api::SongReferencesController < ApplicationController
  def index
    @playlist = Playlist.find(params[:playlist_id])
    @playlist_songs = PlaylistSong.where(playlist_id: params[:playlist_id])
    render json: @playlist_songs, status: :ok
  end

  def new
    @playlist_song = PlaylistSong.new
  end

  def create
    @playlist_song = PlaylistSong.new(playlist_song_params)

    if @playlist_song.save
      render json: @playlist_song, status: :created
    else
      render json: @playlist_song.errors, status: :unprocessable_entity
    end
  end

  def playlist_song_params
    params.fetch(:song, {}).permit(:song_id, :playlist_id)
  end
end

以下是PlaylistCtrl.js文件,它显示了各个播放列表和歌曲,以及我用来将playlist_songs保存到播放列表的$ scope.saveSong函数:

(function (){
  function PlaylistCtrl($scope, $resource, $interval, Restangular, angularSoundManager) {
    $scope.addToPlaylistVisible = false;
    $scope.selectedPlaylist = Restangular.one('api/user_profiles/1/playlists', 8).all('song_references');
    $scope.allPlaylists = Restangular.all('api/playlists');

    $interval(function(){
      $scope.allPlaylists.getList().then(function(playlists) {
        $scope.playlists = playlists;
      });

        console.log("PLAYLISTS GRABBED");
    }, 1000);

    $scope.basePlaylist = Restangular.one('api/playlists', 8).all('playlist_songs');
    $scope.playlistId = '8';

    $interval(function(){
      $scope.basePlaylist.getList().then(function(songs) {
        $scope.songs = songs;
      });

      console.log("Playlist Songs GRABBED");
    }, 1000);

    $scope.setPlaylistAttributes = function(playlistId) {
      $scope.basePlaylist = Restangular.one('api/playlists', playlistId).all('playlist_songs');
      $scope.playlistId = playlistId;
      console.log("CURRENT PLAYLIST ID " + $scope.playlistId)
    }

    $scope.setSong = function(songId) {
      $scope.songId = songId;
      $scope.addToPlaylistVisible = true;
      console.log("CURRENT SONG ID " + $scope.songId)
    }

    $interval(function(){
      $scope.selectedPlaylist.getList().then(function(playlistSongs) {
        $scope.playlistSongs = playlistSongs;
      });
      console.log("Working");
    }, 1000);


    // CREATE PLAYLIST SONG (song_reference instance) - PLAYLIST ID, SONG ID (NOT SONG, BUT PLAYLIST SONG)
    $scope.saveSong = function(selectedPlaylistId) {
      $scope.selectedPlaylist = Restangular.one('api/user_profiles/1/playlists', selectedPlaylistId).all('song_references');
      $scope.selectedPlaylistId = selectedPlaylistId;
      var newSong = {
          "playlist_id": $scope.selectedPlaylistId,
          "song_id": $scope.songId,
      };
      $scope.selectedPlaylist.post(newSong).then(function(newSong){
        $scope.playlistSongs.push(newSong);
        console.log(newSong);
      })
    };

    $scope.hidePlaylists = function() {
      $scope.addToPlaylistVisible = false;
    }

  }
  angular
      .module('PlaylistCtrl', ['angularSoundManager'])
      .controller('PlaylistCtrl', ['$scope', '$resource', '$interval', 'Restangular', PlaylistCtrl]);
})();

播放列表/ index.html.erb:

<h1>All Playlists</h1>

<div ng-controller="PlaylistCtrl">
  <div>
    <ul ng-repeat="playlist in playlists">
      <li>
        <a style="cursor:pointer;" ng-click="setPlaylistAttributes(playlist.id);">{{ playlist.name }}</a>
      </li>
    </ul>
  </div>
  <%= link_to "New playlist",  new_user_profile_playlist_path, data: { push: true } %>
  <br/>
  <br/>
  <h3>Selected Playlist</h3>
  <div>
    <ul>
      <li ng-repeat="song in songs">
        <a style="cursor:pointer;" music-player="play" add-song="song">{{ song.name }}</a>
        <button ng-click="setSong(song.id);">ADD TO PLAYLIST</button>
      </li>
    </ul>
    <button play-all="songs" data-play="false">Add all</button>
    <div ng-if="addToPlaylistVisible">
      <a style="cursor:pointer;" ng-click="hidePlaylists();"><img src="/assets/HUD_icons/x.png"/></a>
      <ul ng-repeat="playlist in playlists">
        <li>
          <a style="cursor:pointer;" ng-click="saveSong(playlist.id);">{{ playlist.name }}</a>
        </li>
      </ul>
    </div>
  </div>
</div>

但是,在选择要添加的正确歌曲,选择要添加的歌曲的播放列表并保存playlist_song后,它不会保存任何属性以及播放列表歌曲。

在rails控制台中查看时,我得到一个如下所示的对象:

=> #<PlaylistSong:0x007f9397d3c700
 id: 48,
 playlist_id: nil,
 song_id: nil,
 created_at: Wed, 12 Oct 2016 00:50:47 UTC +00:00,
 updated_at: Wed, 12 Oct 2016 00:50:47 UTC +00:00>

但我在服务器日志中看到了这一点:

Started POST "/api/user_profiles/1/playlists/8/song_references" for ::1 at 2016-10-11 20:50:47 -0400
Processing by Api::SongReferencesController#create as JSON
  Parameters: {"playlist_id"=>"8", "song_id"=>4, "user_profile_id"=>"1", "song_reference"=>{"playlist_id"=>"8", "song_id"=>4}}
   (0.1ms)  begin transaction
  SQL (1.1ms)  INSERT INTO "playlist_songs" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2016-10-12 00:50:47.752976"], ["updated_at", "2016-10-12 00:50:47.752976"]]
   (8.2ms)  commit transaction
Completed 201 Created in 19ms (Views: 0.5ms | ActiveRecord: 9.5ms)

如果我更改了song_references_controller.rb文件中的playlist_song_params,那么他们会读取:

  def playlist_song_params
    params.require(:playlist_song).permit(:song_id, :playlist_id)
  end

我收到400 BAD REQUEST ERROR,我在服务器日志中看到了这一点:

Started POST "/api/user_profiles/1/playlists/8/song_references" for ::1 at 2016-10-11 20:50:47 -0400
Processing by Api::SongReferencesController#create as JSON
  Parameters: {"playlist_id"=>"8", "song_id"=>4, "user_profile_id"=>"1", "song_reference"=>{"playlist_id"=>"8", "song_id"=>4}}
   (0.1ms)  begin transaction
  SQL (1.1ms)  INSERT INTO "playlist_songs" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2016-10-12 00:50:47.752976"], ["updated_at", "2016-10-12 00:50:47.752976"]]
   (8.2ms)  commit transaction
Completed 201 Created in 19ms (Views: 0.5ms | ActiveRecord: 9.5ms)

我是否完全偏离了如何保存我的“playlist_songs”?

如果是这样,有人会介意如何配置我的strong_params,以及如何在“$ scope.saveSong”函数中设置“newSong”变量吗?

如果您在我的项目中需要任何其他代码,请告诉我,我很乐意提供。

1 个答案:

答案 0 :(得分:0)

我找到了答案。我可以通过将playlist_song_params更改为以下内容来获取要保存的playlist_song属性:

def playlist_song_params
   params.permit(:playlist_id, :song_id)
end

我不知道为什么会这样,所以如果有人想对此有所了解,我们将不胜感激。