William
William

Reputation: 638

Rails has_many :through, form with checkboxes not working

I've been going at this for about 5 hours now and have tried just about everything. I'm a front-end dev with limited rails experience so I could just be 100% off base.

Here are my models:

class Apartment < ActiveRecord::Base
  validates :name, :amenities, presence: true

  has_many :apartment_amenities
  has_many :amenities, through: :apartment_amenities

  accepts_nested_attributes_for :amenities
end

class Amenity < ActiveRecord::Base
  validates :name, presence: true

  has_many :apartment_amenities
  has_many :apartments, through: :apartment_amenities
end

class ApartmentAmenity < ActiveRecord::Base

  belongs_to :apartment
  belongs_to :amenity

end

schema:

  create_table "amenities", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "apartment_amenities", force: :cascade do |t|
    t.integer  "apartment_id"
    t.integer  "amenity_id"
    t.datetime "created_at",   null: false
    t.datetime "updated_at",   null: false
  end

  add_index "apartment_amenities", ["amenity_id"], name: "index_apartment_amenities_on_amenity_id", using: :btree
  add_index "apartment_amenities", ["apartment_id"], name: "index_apartment_amenities_on_apartment_id", using: :btree

  create_table "apartments", force: :cascade do |t|
    t.string   "name"
    t.string   "address"
    t.string   "website"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

Apartment controller:

class Admin::ApartmentsController < AdminController
  before_action :set_apartment, only: [:edit, :update, :destroy]

  def new
    @apartment = Apartment.new
  end

  def create
    @apartment = Apartment.new(apartment_params)

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

  private
    def set_apartment
      @apartment = Apartment.find(params[:id])
    end

    def apartment_params
      params.require(:apartment).permit(:name, :address, :website, amenities_attributes: [:id])
    end
end

and last but not least the new apartment form

<%= form_for([:admin, @apartment]) do |f| %>
  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>

  <div class="field">
    <%= f.collection_check_boxes(:amenities, Amenity.all, :id, :name ) %>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Everything looks right when I load the page up and the apartments are saved but the amenities aren't actually getting saved. Thanks for taking a look.

Upvotes: 1

Views: 334

Answers (2)

sebsonic2o
sebsonic2o

Reputation: 356

I think you need to permit the name for amenities_attributes as follows:

def apartment_params
  params.require(:apartment).permit(:name, :address, :website, amenities_attributes: [:id, :name])
end

Upvotes: 0

margo
margo

Reputation: 2927

Its because your form fields don't match your strong params. Look at the source code of your form. I suspect you'll find that the n checkboxes look something like

apartment[amenities]

But your strong params has the amenities_attributes as a nested hash. Look at the params hash in the logs and you'll see how the form data is formatted. You'll need to change the form to use a fields_for or change the strong params

params.require(:apartment).permit(:name, :address, :website, amenities: [])

Upvotes: 2

Related Questions