jgrant
jgrant

Reputation: 592

collection_select with multiple models rails 4

I have Products and Books. I'm trying to connect Books to a Product with collection_select

Here's part of my product form:

    <%= f.label :book_id %><br>
    <%= f.collection_select(:book_id, Book.all, :id, :title, {}, multiple: :true) %>

Book Model:

class Book < ActiveRecord::Base
 belongs_to :product
end

Product Model:

class Product < ActiveRecord::Base
 has_many :books
end

Migrations:

class AddBookToProducts < ActiveRecord::Migration
 def change
  add_column :products, :book_id, :integer
  add_index :products, :book_id
 end
end

class AddProductToBooks < ActiveRecord::Migration
 def change
  add_column :books, :product_id, :string
  add_index :books, :product_id
 end
end

BooksController:

def new
 @book = Book.new
 authorize @book
end

def create
 @book = Book.new(book_params)
 @book.user = current_user
...

ProductsController:

        class ProductsController < ApplicationController
          require "stripe"
          before_action :set_product, only: [:show, :edit, :update, :destroy]

          # GET /products
          # GET /products.json
          def index
            @products = Product.all.page params[:page]
            authorize @products

          end

          # GET /products/1
          # GET /products/1.json
          def show

           @stripe_btn_data = {
             key: "#{ Rails.configuration.stripe[:publishable_key] }",
             description: @product.title,
             amount: (@product.price * 100),
           }    


           authorize @product
          end

          # GET /products/new
          def new
            @product = Product.new
            @books = Book.all
            authorize @product
          end

          # GET /products/1/edit
          def edit
            authorize @product
          end

          # POST /products
          # POST /products.json
          def create
            @product = Product.new(product_params)
            authorize @product

            respond_to do |format|
              if @product.save
                format.html { redirect_to @product, notice: 'Product was successfully created.' }
                format.json { render :show, status: :created, location: @product }
              else
                format.html { render :new }
                format.json { render json: @product.errors, status: :unprocessable_entity }
              end
            end
          end

          # PATCH/PUT /products/1
          # PATCH/PUT /products/1.json
          def update
            authorize @product
            respond_to do |format|
              if @product.update(product_params)
                format.html { redirect_to @product, notice: 'Product was successfully updated.' }
                format.json { render :show, status: :ok, location: @product }
              else
                format.html { render :edit }
                format.json { render json: @product.errors, status: :unprocessable_entity }
              end
            end
          end

          # DELETE /products/1
          # DELETE /products/1.json
          def destroy

            @product.destroy
            authorize @product
            respond_to do |format|
              format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
              format.json { head :no_content }
            end
          end

          private
            # Use callbacks to share common setup or constraints between actions.
            def set_product
              @product = Product.find(params[:id])
            end

            # Never trust parameters from the scary internet, only allow the white list through.
            def product_params
              params.require(:product).permit(:title, :body, :price, :active, :state, :hardcopy_book, :online_only, :online_hardcopy, :expiration, :monthly, :annual, :user_id, :book, :book_id, :id)
            end
        end

Parameters show the :book_id but it does not insert the book_id into products.

Here's how I am showing the selected books on the product/show

  <strong>Book:</strong>
  <ul>
   <% @product.books.each do |book| %>
    <li><%= link_to book.tile, (book) %><li>
   <% end %>
  </ul>

What am I missing?

Upvotes: 0

Views: 68

Answers (1)

Long Nguyen
Long Nguyen

Reputation: 11275

Firstly, your migration is wrong, we only need one migration and here it is:

class AddBookToProducts < ActiveRecord::Migration
 def change
  add_column :books, :product_id, :string
  add_index :books, :product_id
 end
end

Because Book belongs to Product and Product has many Book so add one column product_id to Books table is enough.

Secondly, edit your Product form to: (please note the change from book_id to book_ids)

<%= f.label :book_id %><br>
<%= f.collection_select(:book_ids, Book.all, :id, :title, {}, multiple: :true) %>

Then add book_ids to Strong parameter in ProductsController

def product_params
  params.require(:product).permit(:title, :body, :price, :active, :state, :hardcopy_book, :online_only, :online_hardcopy, :expiration, :monthly, :annual, :user_id, :book, :id, :book_ids => [])
end

Upvotes: 1

Related Questions