Question

Thanks to help on stackoverflow I got my create nested models form working the other day but I can't for the life of me get the corresponding update form to work. I have read a lot and tried out as many solutions as I can find.

The form looks fine but the nested attributes of Manufacturer and Scale, which are select via drop down, don't have their current values. All non nested elements of the form work fine.

Whatever changes you make to the two nested drop downs, pressing save changes creates NEW lines in the corresponding tables and doesn't alter the existing.

Ultimately what I want is for the attributes to be editable and then i'll have an "add manufacturer" and "add scale" button or link for miniatures that need multiple listings.

Here are my form fields where I've tried and failed to pass a hidden field.

Form

<%= render 'shared/error_messages', object: f.object %>
      <%= f.label :name %>
      <%= f.text_field :name %>
      <%= f.label :material %>
      <%= f.select 'material', options_from_collection_for_select(Miniature.select("DISTINCT material"), :material, 'material', @miniature.material) %>
      <%= f.fields_for :sizes do |size_fields| %>
      <%= size_fields.label :scale_id, "Scale".pluralize %>
      <%= hidden_field "Miniature Scale", @miniature.sizes %>
      <%= size_fields.select :scale_id, options_from_collection_for_select(Scale.all, :id, :name) %>
      <% end %>
       <%= f.fields_for :productions do |production_fields| %>
      <%= production_fields.label :manufacturer_id, "Manufacturer".pluralize %>
      <%= hidden_field "Miniature Manufacturer", @miniature.productions %>
      <%= production_fields.select :manufacturer_id, options_from_collection_for_select(Manufacturer.all, :id, :name, @miniature.manufacturers) %>
      <% end %>
      <%= f.label :release_date %>
      <%= f.date_select :release_date, :start_year => Date.current.year, :end_year => 1970, :include_blank => true %>

Here is the miniatures controller where I'm pretty sure I've filled the 'def update' with too much/the wrong stuff.

Miniatures Controller

class MiniaturesController < ApplicationController
   before_action :signed_in_user, only: [:new, :create, :edit, :update]
   before_action :admin_user,     only: :destroy


  def show
    @miniature = Miniature.find(params[:id])
  end

  def new
    @miniature = Miniature.new 
    @miniature.productions.build
    @miniature.sizes.build
  end

  def create
    @miniature = Miniature.new(miniature_params)
    @production = @miniature.productions.build
    @size = @miniature.sizes.build
    if @miniature.save
      redirect_to @miniature
    else
      render 'new'
    end
  end

  def edit
    @miniature = Miniature.find(params[:id])

  end

  def update
    @miniature = Miniature.find(params[:id])
    @production = @miniature.productions.find(params[:id])
    @size = @miniature.sizes.find(params[:id])
    if @miniature.update_attributes(miniature_params)
       @production = @miniature.productions.update_attributes(:manufacturer_id)
       @size = @miniature.sizes.update_attributes(:scale_id)
      flash[:success] = "Miniature updated"
      redirect_to @miniature
    else
      render 'edit'
    end
  end
  def index
    @miniatures = Miniature.paginate(page: params[:page])
  end

  def destroy
    Miniature.find(params[:id]).destroy
    flash[:success] = "Miniature destroyed."
    redirect_to miniatures_url
  end

private
    def miniature_params
      params.require(:miniature).permit(:name, :release_date, :material, productions_attributes: [:manufacturer_id], sizes_attributes: [:scale_id])
    end

    def admin_user
      redirect_to(root_url) unless current_user.admin?
    end

    def signed_in_user
      unless signed_in?
        store_location
        redirect_to signin_url, notice: "Please sign in."
      end
    end
end

I won't attach the models as I'm pretty sure the relationships are all correct since they work fine for creating new nested models. Miniatures have_many scales and manufactures through sizes and productions.

Any help or pointers very much appreciated.

Was it helpful?

Solution

Thanks to an answer on this Q I've solved it. What I had already was fine for CREATING but didn't work for UPDATES because I hadn't whitelisted the JOIN model ids in the 'miniature_params, so they couldn't retrieve the existing info.

Now I have productions_attributes: [:id, :manufacturer_id] instead of just productions_attributes: [:manufacturer_id]

as below

def miniature_params
  params.require(:miniature).permit(:name, :release_date, :material, productions_attributes: [:id, :manufacturer_id], sizes_attributes: [:id, :scale_id])
end

I can also strip ALL of the references to the nested models out of my miniatures controller update method as it 'just works'.

 def update
    @miniature = Miniature.find(params[:id])
    if @miniature.update_attributes(miniature_params)
      flash[:success] = "Miniature updated"
      redirect_to @miniature
    else
      render 'edit'
    end
  end

Hope this is useful to someone in future.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top