Search code examples
ruby-on-railsrubymany-to-many

How to save a many-to-many in Ruby on Rails


I have a many-to-many relationship that is not being saved by rails when created nor edited. I used checkbox control in order to get the many-to-many relation.

Basically when the user is creating the "Shop" it will have the checkboxes of the categories that shop belongs to (restaurant, burguer place, pizza makers). So the user will hit the checkboxes to select these categories.

I don't receive any errors and the operation is completed. The Shop is created but the relation is not saved on the database.

If I try to edit this shop, the relations are not there.

this is my models:

class Shop < ActiveRecord::Base
  belongs_to :locale
  has_many :shop_categorizations
  has_many :shops_categories, through: :shop_categorizations
  has_many :shop_hours
  has_attached_file :image, :default_url => "/assets/default_image.png", :storage => :s3,
      :s3_credentials => Rails.root.join("config/s3_credentials.yml"),
      :path => ":style/shop/:id",
      :url => ":s3_domain_url"
  validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
end


class ShopsCategory < ActiveRecord::Base
  has_many :shop_categorizations
  has_many :shops, through: :shop_categorizations
end


class ShopCategorization < ActiveRecord::Base
  belongs_to :shop
  belongs_to :shops_category
end

This is my controller that handles my code:

   class ShopsController < ApplicationController
  before_action :set_shop, only: [:show, :edit, :update, :destroy]

  def new
    @shop = Shop.new
  end

def create
    @shop = Shop.new(shop_params)

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

  def shop_params
      params.require(:shop).permit(:company_name, :fantasy_name, :cnpj, :locale_id, :street_name, :number, :neighborwood, :complement, :login, :password, :phone1, :phone2, :flag_open, :flag_card, :flag_delivery, :price_delivery, :image)
    end

My simple_form is prepared for it like this:

<%= simple_form_for(@shop) do |f| %>
  <%= f.error_notification %>

  <div class="form-inputs">
    <%= f.input :company_name %>
    <%= f.input :fantasy_name %>
    <%= f.input :cnpj %>
    <%= f.association :locale, :label_method => :city %>
    <br>
    <%= f.association :shops_categories, as: :check_boxes, :label_method => :name, :input_html => { :class => 'check'} %>
    <br>
    <%= f.input :street_name %>
    <%= f.input :number %>
    <%= f.input :neighborwood %>
    <%= f.input :complement %>
    <%= f.input :login %>
    <%= f.input :password %>
    <%= f.input :phone1 %>
    <%= f.input :phone2 %>
    <%= f.input :flag_open %>
    <%= f.input :flag_card %>
    <%= f.input :flag_delivery %>
    <%= f.input :price_delivery %>

    <%= f.input :image, as: :file %>
  </div>

  <div class="form-actions">
    <%= f.button :submit %>
  </div>
<% end %>

Solution

  • Yeah, so like Alex mentioned in his comment, your shop_params should be as follow:

    def shop_params
      params.require(:shop).permit(:company_name, :fantasy_name, :cnpj, :locale_id, :street_name, :number, :neighborwood, :complement, :login, :password, :phone1, :phone2, :flag_open, :flag_card, :flag_delivery, :price_delivery, :image, shops_category_ids: [])
    end
    

    Notice that the new addition, shops_category_ids is an array, to allow the array of ids coming from your

    <%= f.association :shops_categories, as: :check_boxes, :label_method => :name, :input_html => { :class => 'check'} %>
    

    in the form.