Home > database >  Ruby on Rails Create A-B relationship instance when A has_and_belongs_to_many B and vice versa
Ruby on Rails Create A-B relationship instance when A has_and_belongs_to_many B and vice versa

Time:09-26

I have two example classes:

# book.rb
class Book < ApplicationRecord
    has_and_belongs_to_many :tag
end

# tag.rb
class Tag < ApplicationRecord
  has_and_belongs_to_many :formula
end

If I understand correctly, this means that I could eventually have tags with many books and books with many tags. Right now, I want to assign tags to books when I create books.

I have a multiselect dropdown on the books/new page to send these tags to the controller, but I don't know what to do once they reach the controller.

  <div>
    <%= form.label :tags, style: "display: block" %>
    <%=  select_tag :tags, options_from_collection_for_select(@tags, :id, :name), multiple: true, prompt: "Select Tags" %>
  </div>

Controller looks like this:

def create
    @Book = Book.new(book_params)

    respond_to do |format|
      if @book.save
        format.html { redirect_to book_url(@book), notice: "Book was successfully created." }
        format.json { render :show, status: :created, location: @book }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @book.errors, status: :unprocessable_entity }
      end
    end
  end

When I make a book with the form, it doesn't have any tags when I inspect the latest book in the rails console.

I tried putting @book.tag.build(tag_ids: book_params["tags"]) into thee create method but that didn't work and I feel like I'm barking up the wrong tree.

CodePudding user response:

You may add accepts_nested_attributes_for :tags in the Book model. This way, when the form is submitted, @book.save will create the associations for tags from params[:books][:tags]

# book.rb
class Book < ApplicationRecord
  has_and_belongs_to_many :tag
    
  accepts_nested_attributes_for :tags
end


Reference: https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

CodePudding user response:

If you want to assign existed tags to new book, you can use select method in your form

<%= form.select :tag_ids, Tag.all.map { |p| [p.name, p.id] }, multiple: true, prompt: "Select Tags" %>

Of course you can pass @tags from controller instead of Tag.all

If you use strong params, you need to add this param there, something like

params.require(:book).permit(
  # existed params,
  tag_ids: []
)
  • Related