Search code examples
ruby-on-railsrubystimulusjs

nested form fields using fields_for is giving error "hash is defined by Active Record... same name"


I'm fairly new to rails, so excuse my ignorance. But I currently have a controller which stores "Scan Results" for a theoretical virus scanner.

The Scan Model, has_many Detections, which is a record which holds a Sha256 hash and a type.

the code looks as follows

model/scan.rb

class Scan < ApplicationRecord
    has_many :detections, class_name: "detection", foreign_key: "d_id", :dependent => :destroy
    accepts_nested_attributes_for :detections
    validates :hostname, presence: true, uniqueness: { case_sensitive: true }, length: {maximum: 50, minimum: 1}, if: :hostname_not_empty
    
    

    def hostname_not_empty 
        if ( self.hostname != '' || self.hostname.nil? )
            return true
        end
        return errors.add(:scansErr, "Hostname is empty")
    end
end

model/detections

class Detection < ApplicationRecord
  belongs_to :scan
  validates :hash, presence: true, length: {maximum: 64, minimum:64}, format: { with: /\b[A-Fa-f0-9]{64}\b/ }
  
  def new () 

  end 
  def new_record
  end
end

when I try creating a template for adding new scans to the db, I'm getting this error hash is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name.

I'm using the following template to try and render it all.

views/dashboard/form.html.haml

...
= form_for :scans, url: dashboard_scan_create_path(params.to_unsafe_h.slice(:hostname)), :html => {:class => 'flex w-full flex-col scan-form' } do |s|
        %div.flex.w-full.relative
          #{s.text_field :hostname, :class => 'input border border-gray-400 appearance-none rounded w-full px-3 py-3 pt-8 pb-2 my-2 focus focus:border-indigo-600 focus:outline-none active:outline-none active:border-indigo-600' }
          #{s.label :hostname, :class => 'label absolute mb-0 -mt-2 pt-4 pl-3 leading-tighter text-gray-400 text-base mt-2 cursor-text'}
        %div.detections.flex.w-full.my-2{ 'data-controller' => 'detection-form' }
          %div.text-xl.font-bold Detections
          %template{"data-target" => "detection-form.template"}
            = s.fields_for :detections, Detection.new, child_index: "NEW_RECORD" do |d_form|
              = render "detection_fields", form: d_form
...

views/dashboard/detections-fields.html.haml

= content_tag :div, class: "detection-fields" do
  .input.detection-field-input.d-flex.justtify-content-between.mb-2
    .col-11.pl-0
      = form.fields_for(:detection) do |detection_form|
        = detection_form.text_field :type
        = detection_form.text_field :hash
    .col-1
      = link_to "delete", "#", data: { action: "nested-form#remove_association" }
  = form.hidden_field :_destroy, as: :hidden


can anyone help me figure out what I am doing wrong.


Solution

  • The error is clear in that ActiveRecord::Core has defined a method hash and your model, Detection, has a conflicting attribute called hash.

    The action here is to rename the hash attribute of your model to something that isn't already implemented/reserved.

    As an example, if you change the model attribute (and the associated code that uses it) to be sha256 or sha it will avoid the conflict.