Rails将元素添加到一对多关联

时间:2016-01-24 10:40:35

标签: ruby-on-rails ruby associations one-to-many models

我在相册和帖子之间有一对多的关系:

class Post < ActiveRecord::Base
    belongs_to :album

class Album < ActiveRecord::Base
    has_many :posts, dependent: :destroy
    accepts_nested_attributes_for :posts

AlbumsController中,我想创建一种向此关系添加帖子的方法(Album.posts):

def add_post
    @album = Album.find(params[:album_id])
    params['album']['post_ids'].each do |post_id|
      @album.posts << Post.find(post_id)
    end
end

为什么不起作用?这样做的正确方法是什么?我也尝试将@album.id分配到帖子的album_id列,但它也没有做任何事情。

表格如下:

    <%= form_for :album, url: album_add_post_path(@album), method: :patch do |f| %>  
        <% @posts.each do |post| %>  
            <%= check_box_tag :post_ids, post.id, @album.posts.include?(post), :name => 'album[post_ids][]' %>  
       <% end %>  
        <%= f.submit class:"btn btn-success"%>  
    <% end %>  

2 个答案:

答案 0 :(得分:1)

如果您使用嵌套属性,就像您一样,您无需循环浏览相关帖子进行创建。 (这就是嵌套属性的用途)

但是,您必须确保在参数中允许这些post_id s。 这是最常见的错误之一(我自己已经做了几次)

所以,在你的控制器中:

def add_post
  @album = Album.find(params[:album_id])
  @album.update(album_params)
end

album_params方法如下:

def album_params
  params.require(:album).permit(..., ..., ..., posts_attributes: [:id, ..., ...])
end

这里需要注意的重要事项:

  1. posts_attributes作为所有相关属性(posts_attributes: []
  2. 的属性数组输入
  3. 应允许id用于关联属性,否则每次编辑/更新时都会创建新关联
  4. 需要允许的父对象(相册)的所有属性都直接列在许可块(params.require(:album).permit(..., ...,
  5. 需要允许的子对象(post)的所有属性都列在嵌套属性块中。 (posts_attributes: [:id, ..., ...]
  6.   

    注意:前端视图表单也必须正确设置。 An example can be found on this rails cast,您可以check the documentation了解有关此问题的更多信息。

    我刚看到你的前端视图更新。您可以利用您已经使用的嵌套属性,并通过扩展相册的帖子进行解释,如下所示:

    <%= f.fields_for :posts do |p| %>
      <%= p.collection_select :post_id, Post.order(:name),:id,:name, include_blank: true %>
    <% end %>
    

答案 1 :(得分:0)

代码的直接修复是......

#config/routes.rb
resources :albums do
   match :posts, via: [:get, :patch], on: :member #-> url.com/albums/:id/posts
end

#app/controllers/albums_controller.rb
class AlbumsController < ApplicationController
   def posts
       @album = Album.find params[:id]
       @posts = Post.all if request.get?
       if request.patch?
         @album.update album_params
         @album.save
       end
   end 

   private

   def album_params
       params.require(:album).permit(post_ids: [])
   end
end

这可以伴随collection_select

#app/views/albums/posts.html.erb
<%= form_for @album do |f| %>
   <%= f.collection_select :post_ids, @posts, :id, :name %>
   <%= f.submit %>
<% end %>

然而,这将工作(我推测),因为你希望。

使用belongs_to / has_many时,您只能匹配&#34;对&#34;关系。这意味着添加到singular_collection_ids方法将覆盖belongs_to记录中的任何现有Post引用。

简而言之,如果您想更改(不添加)您的关联对象,它将会起作用。如果您想现有posts添加到album,您必须使用以下代码。

您最好使用has_and_belongs_to_many

#config/routes.rb
resources :album do
   resources :posts #-> url.com/albums/:album_id/posts/new 
end

#app/models/album.rb
class Album < ActiveRecord::Base
   has_and_belongs_to_many :posts
end 

#app/models/post.rb
class Post < ActiveRecord::Base
   has_and_belongs_to_many :albums
end

#app/controllers/albums_controller.rb
class AlbumsController < ApplicationController
    def edit
       @album = Album.find params[:id]
       @posts = Post.all
    end

    def update
       @album = Album.find params[:id]
       @album.update album_params
    end

    private

    def album_params
       params.require(:album).permit(post_ids: [])
    end
end

#app/views/albums/edit.html.erb
<%= form_for @album do |f| %>
   <%= f.collection_select :post_ids, @posts, :id, :name %>
   <%= f.submit %>
<% end %>