如何通过 AJAX POST 请求关联 HABTM 关系中的两个 objects

How to associate two objects in a HABTM relationship via an AJAX POST request

我无法在 HABTM 关系中将一个 object 与另一个 object 关联,只有在通过 JSON POST 创建新的 object 时(使用 Rails 控制台时,这种关系按预期工作)。

重现:我用视频(有标题和 URL)和播放列表(有名称)创建了一个示例项目:

rails new videotest
cd videotest
rails g scaffold video title:string url:string
rails g scaffold playlist name:string
rails g migration create_playlists_videos playlist_id:integer video_id:integer
rake db:migrate

我设置模型之间的has_and_belongs_to_many关系:

class Playlist < ActiveRecord::Base
  has_and_belongs_to_many :videos
end

class Video < ActiveRecord::Base
  has_and_belongs_to_many :playlists
end

在视频控制器中我white-listplaylist_ids参数:

def video_params
  params.require(:video).permit(:title, :url, playlist_ids: [])
end

然后在 rails 控制台中创建一些示例 objects:

Video.create!(title:"video1", url:"http://youtube.com/123")
Video.create!(title:"video2", url:"http://youtube.com/456")

@playlist = Playlist.create(name:"playlist1")
@playlist.videos.append([Video.first, Video.second])

Playlist.first.videos.count returns 2 符合预期,表明正确配置了 HABTM 关系。

我可以使用 AJAX POST 请求成功创建新视频 object,我还硬编码了第一个播放列表的 ID:

data =   JSON.stringify({
  "title": "test video",
  "url": "http://www.youtube.com/987",
  "playlist_ids": [1]
});

$.ajax({
  url: "http://" + window.location.host + "/videos.json",
  type:"POST",
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  data: data,
  success: function(msg) {
    console.log("added " + msg.title)
  }
});

问题:未使用 playlist_id,生成的视频 object 未与播放列表 1 相关联。

create方法包括:

def create
    @video = Video.new(video_params)

我注意到 video_params 不包括 playlist_id,但 params 包括:

(byebug) video_params
{"title"=>"test video", "url"=>"http://www.youtube.com/987"}
(byebug) params[:playlist_ids]
[1]

为什么playlist_ids 没有通过白名单?

当您使用 habtm 时,您会得到几个应该使用的方法:

具体来说,如果您想在创建时设置 videoplaylist_id,您最好填充 playlist_ids 属性:

$.ajax({
  url: "http://" + window.location.host + "/videos.json",
  type:"POST",
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  data: JSON.stringify({"title": title, "url": "http://www.youtube.com", "playlist_ids": [1]}),
  success: function(msg) {
    console.log("added " + msg.title)
  }
});

#app/controllers/videos_controllers.rb
class VideosController < ApplicationController
   def create
      @video = Video.new video_params
      @video.save
   end

   private

   def video_params
      params.require(:video).permit(:title, :url, playlist_ids: [])
   end
end

这将覆盖您的 video 关联的当前 playlists;这意味着如果您想 添加 / 删除 视频到播放列表,您最好使用 <<.delete 方法。

如果需要,我可以解释如何执行此操作。

如果这些关联设置正确,您的播放列表模型应该有一个 video_ids 属性,而您的视频模型应该有一个 playlist_ids 属性。

您可以通过表单传递这些,rails 应该会在您的 playlists_videos link table.

中创建相应的记录

所以在您的 VideosController 中像这样设置您的白名单:

def video_params
  params.require(:video).permit(:title, :url, playlist_ids: [])
end

现在调整您的 ajax 调用以传递 playlist_ids 数组,如下所示:

JSON.stringify({ "video": {"title": title, "url": "http://www.youtube.com", "playlist_ids": [1,2]}})

记得将参数嵌套在 "video" 节点内。

所以在这种情况下,您要将视频与 playlist_id 1 和 playlist_id 2 相关联,例如。