I have one-to-many relation between albums and posts:
class Post < ActiveRecord::Base
belongs_to :album
class Album < ActiveRecord::Base
has_many :posts, dependent: :destroy
accepts_nested_attributes_for :posts
In AlbumsController
, I would like to create a method for adding post to this relation (to 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
Why doesn't it work? What is the correct way of doing this? I've also tried assigning @album.id
to the album_id
column of the post, but it doesn't do anything either.
Form looks like this:
<%= 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 %>
If you are using nested attributes, like you are, You don't necesarily have to loop through the associated posts to create. ( that is what the nested attributes is for )
However, you have to ensure that you are permitting these post_id
s in the parameters. This is one of the most common mistakes ( I have made this a few times myself )
So, in your controller:
def add_post
@album = Album.find(params[:album_id])
@album.update(album_params)
end
Where the album_params
method is as follow:
def album_params
params.require(:album).permit(..., ..., ..., posts_attributes: [:id, ..., ...])
end
The important things to note here:
posts_attributes: []
) id
should be permitted for associated attributes, or else new associations will always be created each time there is an edit/update params.require(:album).permit(..., ...,
) posts_attributes: [:id, ..., ...]
) NOTE: The front-end view form has to be set right as well. An example can be found on this rails cast , And you can check the documentation for more information on this.
I just saw your update with the front-end view. You can leverage the nested attributes you are already using and that I've explained by extending the album's post as follow:
<%= f.fields_for :posts do |p| %>
<%= p.collection_select :post_id, Post.order(:name),:id,:name, include_blank: true %>
<% end %>
The direct fix for your code is...
#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
This can be accompanied with a collection_select
:
#app/views/albums/posts.html.erb
<%= form_for @album do |f| %>
<%= f.collection_select :post_ids, @posts, :id, :name %>
<%= f.submit %>
<% end %>
However , this will not work (I presume) as you'd hope.
When using belongs_to
/ has_many
, you can only have matching "pairs" of relations. This means that adding to the singular_collection_ids
method will override any existing belongs_to
reference in the Post
records.
In short, if you want to change (not add) your associated objects, it will work. If you want to add existing posts
to an album
, you'll have to use the code below.
You'd be best using 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 %>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.