0

im using the cocoon gem to build some dynamic form in which i can add new text fields. Ive read others people same problem but i dont know what im doing wrong, i know it has to be something with the associations but i dont seem to get it.

So these are my models:

class MonitorCategory < ActiveRecord::Base

  validates :operation, presence: true
  attr_accessor :oid, :oid2, :oids, :snmp_oper, :custom_tab_name, :custom_tab_unit, :redfish, :ipmi
  has_many :oids
  has_and_belongs_to_many :sensors

  accepts_nested_attributes_for :oids

class Oid < ActiveRecord::Base
  belongs_to :monitor_category
 end

And my form:

<%= simple_form_for(:monitor_category, url: create_monitor_category_path, :html => { :remote => true, :method => :post }) do |f| %>
<div id='oids'>
    <%= f.simple_fields_for :oids do |oid| %>
    <%= render 'oids_fields', :f => oid %>
    <% end %>
    <div class='links'>
      <%= link_to_add_association 'add oid', f, :oids %>
    </div>
</div>

with the partial _oids_fields.html.erb:

<div class='nested-fields'>
<%= f.input :oids %>
</div>

What am i doing wrong? Im getting undefined method `reflect_on_association' for NilClass:Class:. Form is okay since i was looking at the page of cocoon and is the same syntax, so i guess it must be something with the associations but i dont really know, im kind of new to the rails world. Maybe since it says nilClass, i need to create a controller for the Oid model in which i make a new method or something? im lost.

Apparently this doesnt work either, i have the same error:

class OidController < ApplicationController

  def new
    @oid = Oid.new
  end

end  

thank you for every answer.

edit: just to be more clear, because im very confused.

Before trying to implement this dynamic form, i already have a form which is working correctly. For example, last two fields are these:

      <div class="col-md-12">
        <%= f.input :oid, label: 'SNMP OID', as: :search, placeholder: 'Output stored in var1.', required: false, novalidate: true, input_html: {data: { autocomplete_source: get_oids_path }} %>
      </div>
      <div class="col-md-12">
        <%= f.input :oid2, label: 'SNMP OID 2', as: :search, placeholder: 'Output stored in var2.', required: false, novalidate: true, input_html: {data: { autocomplete_source: get_oids_path }} %>
      </div>

So basically here im storing the values entered on the attribute :oid and :oid2 from the model .

but instead of having these two fields, i want to have only one, and add more dynamically, so i can enter for example 6 values and saved them all on the :oids attribute. Since i was saving the valued on an attribute, i dont know if i have to create a model for Oid, like a did before, and make it belong_to monitor_category. Or if i can just add an attribute :oids to the controller and store all the values in that variable.

JuanMartinez
  • 19
  • 1
  • 6
  • do not use `attr_accessor` in a model unless you have an extremely specific reason for doing so (which should never include overwriting relationships or attributes). I fear that you have created some form of ambiguity by adding `attr_accessor :oids` where the `has_many` is not overriding this. Thus `model.oids #=> nil` because the method is actually `def oids; @oids; end` – engineersmnky Aug 06 '19 at 15:15
  • yep i changed that before, but i still have the same error. Why if i do this returns nil? Theres got to be something wrong with the oid controller maybe? `Oid.reflect_on_association(:owner)` This should return MonitorCategory since i put the `belongs_to` in the Oid class. – JuanMartinez Aug 06 '19 at 15:22

2 Answers2

1

The problem is this line

simple_form_for(:monitor_category, url: create_monitor_category_path, :html => { :remote => true, :method => :post }) do |f| 

This creates a form for a MonitorCategory but does not set an object. So when you then call f.simple_fields_for there is no object to iterate over the associations.

Normally in the controller you set a @monitor_category instance variable, which is either set to an existing instance (when editing) or a newly created item.

And then you can write:

simple_form_for(@monitor_category, :html => { :remote => true, :method => :post }) do |f| 

Rails is smart enough to deduce the url from the object, it will either create a new one or update an existing one.

Is that clear enough?

nathanvda
  • 49,707
  • 13
  • 117
  • 139
  • Hello thank you for your answer. I thought about that before, but if i delete de url and change it to `@monitor_category`, like im doing on the `edit_monitor_category`, which is working good, i get an "undefined method `model_name` por nil:NilClass. The thing is im working with code done by other people long time ago, so maybe they had their reasons to put :monitor_category. What i still dont get is why i get nil if i do @oid = Oid.new – JuanMartinez Aug 07 '19 at 07:58
  • And furthermore, if that was the problem, wont the other f.inputs would be failing too, since "f" is nill as you said? – JuanMartinez Aug 07 '19 at 08:02
  • It is not `f` that is nil, but `f.object`. Is `@monitor_category` set in the controller? If this is only used in the `new` action (normally the form is shared between new and edit), you could also write `simple_form_for MonitorCategory.new, ..` (but just for test). For reference: https://stackoverflow.com/questions/5181143/simpleform-without-for-non-model-form – nathanvda Aug 08 '19 at 10:04
0

I think it's because your form is for a monitor_category and the url is pointing to the create_monitor_category_path. But you're showing us the OidController. You would need something like:

class MonitorCategoryController < ApplicationController
  def new
    @monitor_category = MonitorCategory.new
    @monitor_category.oids.build
  end
end

This will initialize the parent object and then build the child association. You need to build at least one child for the fields to show up when using fields for.

  • Hello, i updated my post explaining a little bit more what im trying to do, since this is not working and i have the same error. Thank you for your time. – JuanMartinez Aug 06 '19 at 11:10
  • If you want to use the form with cocoon that you posted, the form needs to be in the monitor_category new view. It will then dynamically build the children oids onto the parent monitor_category. Your form is not pointing to your oid controller. – Int'l Man Of Coding Mystery Aug 06 '19 at 11:15
  • yes i know. my dynamic form is part of the new_monitor_category view, thats not the problem. The problem is i cant even load that view because of the error `reflect on association which i dont know how to solve. I will keep searching for info since im getting nowhere here, thanks. – JuanMartinez Aug 06 '19 at 11:21