1

I have looked at various answers to similar questions and haven't quite cracked it. A wine model is defined with has_one :register, :dependent => :destroy and rightly or wrongly I have added accepts_nested_attributes_for :register. A register is defined with belongs_to :wine.

The code within wines_controller.rb for create is:

def new
  @wine = Wine.new
  @register = Register.new

def create
  @wine = Wine.new(wine_params)
  @register = @wine.registers.build(register_params)
  respond_to do |format|
    if @wine.save 
    #success
    else
      format.json { render json: @wine.errors, status: :unprocessable_entity }
      format.json { render json: @register.errors, status: :unprocessable_entity }
    end
  end 
end

My form for creating a new wine has the following code:

<%= simple_form_for @wine do |f| %>  
# various working elements
<div class="field">
  <% f.fields_for :register do |r| %>
    <%= r.label :short_name %>
    <%= r.text_field :short_name %>
    <%= r.label :barcode %>
    <%= r.text_field :barcode %>
  <% end %>
</div>

When this form is called up no fields are created from the f.fields_for command but this block is executed because I can add test buttons within it to prove it is accessed.

If I try to create a wine I get the following error message:

undefined method `registers' for #<Wine:0x007f1204375330> Did you mean? register register= register_id

I believe that using .build is there to ensure data integrity: I don't want to create a wine that does not have a corresponding register. I have tried thinking about it nested attributes but that seems to be considered a bad plan by many. This current approach feels correct but I think I am missing some understanding of syntax at the very least.

At a later date it will be necessary to have other models linked to register that will not be associated to wines. I was considering a similar approach but I am happy to be told to rethink!

2 Answers 2

2

If I understand you correctly you have 2 issues:

Firstly fields for register aren't being displayed - this is partly because @wine.register is nil.

You should change your new action to:

def new
  @wine = Wine.new
  @wine.register = Register.new

In addition because you are using simple_form_for you will need to use simple_fields_for instead of fields_for

Your second issue that results in the exception tells you everything... you are trying to access @wine.registers, and not @wine.register

Change in your create method to:

  @register = @wine.register.build(register_params)

This will fix that issue ... however ... all you really need to do is build the @wine object from your params - your params should be configured to permit the right nested attributes - if it is set up correctly the register object will also be built when building the @wine object.

Your model is already set to accept_nested_attributes and thus will also validate and save the register object when calling @wine.save - no need to explicitly save the register object.

You should have something like:

def wine_params
    params.require(:wine).permit(
          :attribute1, :attribute2,
          register_attributes: [:id, :short_name, :barcode])
end
Sign up to request clarification or add additional context in comments.

9 Comments

OK, thanks for the input. The first adjustment you suggest gives rise to ` ActiveModel::MissingAttributeError in WinesController#new ` and can't write unknown attribute 'wine_id'
That error arises if I try to create a new wine entry
could you clarify ... are we talking about the @wine.register = Register.new line? If so then check your Register table ... it should have a wine_id reference
The table wines does indeed have have a column wine_id, automatically created by Rails. The error message is pointing to the line @wine.register = Register.new
I tried adding wine_id into the attributes of register` but happily that didn't fix it. I would only have been confused if it had!
|
0

Try this

Wine and Register models

class Wine < ApplicationRecord
    has_one :register, inverse_of: :wine,  :dependent => :destroy
    accepts_nested_attributes_for :register
end

class Register < ApplicationRecord
    belongs_to :wine, inverse_of: :register
    validates_presence_of :wine
end

Wines Controller

class WinesController < ApplicationController
  def new
    @wine = Wine.new
    @wine.build_register
  end


  def create
    @wine = Wine.new(wine_params)

    if @wine.save
        redirect_to @wine
    else
        render :new
    end
  end

  private
    def wine_params
        params.require(:wine).permit(:name, register_attributes: [:simple_name])
    end
end

My wine_params are specific for

rails g model wine name:string
rails g model register name:string wine_id:integer

Lastly wine form should look like this

<%= form_for @wine do |f|%>
    <p>
        <%= f.label :name%>
        <%= f.text_field :name%>
    </p>

    <%= f.fields_for :register do |r|%>
    <p>
        <%= r.label :simple_name%>
        <%= r.text_field :simple_name%>
    </p>    
    <% end %>

    <%= f.submit %>
<% end %>

So you can modify wine_params and form partial for your application specifics

2 Comments

register will be saved automatically when you create wine
Also you can use simple_form_for and simple_fields_for instead of form_for and fields_for

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.