heartcombo/simple_form · error · ArgumentError

:has_one associations are not supported by f.association

Error message

:has_one associations are not supported by f.association

What it means

When f.association resolves the reflection, build_association_attribute maps belongs_to to the foreign-key attribute and has_many/has_and_belongs_to_many to multi-select collections; a :has_one target has no foreign key on the parent and no sensible single select, so it raises ArgumentError instead of rendering something wrong (lib/simple_form/form_builder.rb:523). A singular associated record is meant to be edited with nested fields, not an association input.

Source

Thrown at lib/simple_form/form_builder.rb:523

        else
          order = reflection.options[:order]
          conditions = reflection.options[:conditions]
          conditions = object.instance_exec(&conditions) if conditions.respond_to?(:call)

          relation = relation.where(conditions) if relation.respond_to?(:where) && conditions.present?
          relation = relation.order(order) if relation.respond_to?(:order)
        end

        relation
      end
    end

    def build_association_attribute(reflection, association, options)
      case reflection.macro
      when :belongs_to
        (reflection.respond_to?(:options) && reflection.options[:foreign_key]) || :"#{reflection.name}_id"
      when :has_one
        raise ArgumentError, ":has_one associations are not supported by f.association"
      else
        if options[:as] == :select || options[:as] == :grouped_select
          html_options = options[:input_html] ||= {}
          html_options[:multiple] = true unless html_options.key?(:multiple)
        end

        # Force the association to be preloaded for performance.
        if options[:preload] != false && object.respond_to?(association)
          target = object.send(association)
          target.to_a if target.respond_to?(:to_a)
        end

        :"#{reflection.name.to_s.singularize}_ids"
      end
    end

    # Find an input based on the attribute name.
    def find_input(attribute_name, options = {}, &block)

View on GitHub (pinned to 18f38aad0b)

Solutions

  1. Replace it with nested fields: f.simple_fields_for :profile do |pf| ... end, with accepts_nested_attributes_for :profile on the model
  2. If you really need one selectable record, model the relation as belongs_to on this model (a *_id column) and use f.association on that
  3. Otherwise render manual inputs for the associated object's attributes via simple_fields_for

Example fix

# before
<%= f.association :profile %>  <!-- ArgumentError: :has_one not supported -->

# after (model: has_one :profile + accepts_nested_attributes_for :profile)
<%= f.simple_fields_for :profile do |pf| %>
  <%= pf.input :bio %>
<% end %>
Defensive patterns

Strategy: validation

Validate before calling

reflection = f.object.class.reflect_on_association(:profile)
if reflection&.macro == :has_one
  f.simple_fields_for :profile do |pf|
    render 'profiles/fields', f: pf
  end
else
  f.association :profile
end

Prevention

When it happens

Trigger: f.association :profile on a model that declares has_one :profile; f.association :account where the reflection macro is :has_one (including polymorphic has_one); code that enumerates all reflections and feeds each to f.association.

Common situations: Assuming f.association works for every association macro; trying to shortcut a nested profile/account form with one call; scaffolding or admin generators that list reflections automatically.

Related errors


AI-assisted analysis of heartcombo/simple_form@18f38aad0b (2026-08-21). Data as JSON: /api/errors/f29102824ee7fa21. Report an issue: GitHub.