Abdel P.
Abdel P.

Reputation: 738

How to associate a form object?

I'm trying to save a Form Object in Rails through and association like this:

document.translations_forms.save(translation_params)

And on my Document model I associated it this way:

class Document < ApplicationRecord
  has_many :translations_forms
  ...
end

But when I run the first command above, I getting this error:

NoMethodError: undefined method `relation_delegate_class' for Document::TranslationsForm:Class

I tried declaring the TranslationFrom Object adding the Document namespace

class Document::TranslationsForm
  include ActiveModel::Model

  belongs_to :document

  def save(params: {})
    return false if invalid?

    self.document.translation.create(params)
  end
end

But didn't work either, my TranslationForm object is in the app/forms/translations_form.rb directory, and I'm using rails 6, what can I do to associate the model with my form object?

Upvotes: 0

Views: 63

Answers (1)

max
max

Reputation: 102026

A form object (which is a vague term) is usually just a variation of the Decorator pattern.

So you could simply setup the form object so that it wraps an instance of the model class:

class Document
  class TranslationForm
    include ActiveModel::Model
    attribute_reader :document

    def initialize(record = nil, attributes = {})
      # lets you use the form object for existing records
      if record 
        @document = record 
        @document.assign_attributes(attributes)
      end
      @document ||= Document.new(attributes)
    end

    def to_model
      document
    end

    def save
      # triggers validations on the form object
      if valid?
        document.save     
      else
        false
      end 
    end
  end
end
def create
  @document = Document::TranslationForm.new(document_params)
  if @document.save
    redirect_to @document
  else
    render :new
  end
end
def update
  @document = Document::TranslationForm.new(
    Document.find(params[:id]),
    document_params
  )
  if @document.save
    redirect_to @document
  else
    render :edit
  end
end

To add a validation to the form object (instead of directly to the model) just use delegatation:

class Document
  class TranslationForm
    # ...
    validates :foo, presence: true
    delegate :errors, to: :document
    delegate :foo, to: :document
  end
end

delegate :errors, to: :document makes it so that your validations will add errors to the underlying model instead of the errors object of your form object.

Upvotes: 1

Related Questions