straffaren
straffaren

Reputation: 337

Active Admin has_many with set number of nested relations

I'm using Active Admin and I have a one-to-many relationship between two models:

class WeeklyMenu < ActiveRecord::Base
  has_many :menu_items
  attr_accessible :menu_items
  accepts_nested_attributes_for :menu_items
end

In the admin page for WeeklyMenu I'd like to display five menu_items. This is what my admin page looks like at the moment:

ActiveAdmin.register WeeklyMenu do
  form do |f|
    f.inputs "Details" do
      f.input :title
      f.input :week
    end

    f.has_many :menu_items do |menu_item|
      menu_item.input :title
    end

    f.buttons
  end
end

That gives me a very nice interface for adding more menu_items, but I want the user to have five of them - no more, no less. How would I go about doing that?

Upvotes: 5

Views: 4366

Answers (4)

Ken Hill
Ken Hill

Reputation: 156

Activeadmin defines callbacks that can be used for this sort of thing: https://github.com/activeadmin/activeadmin/blob/master/lib/active_admin/resource_dsl.rb#L157-L161

The after_build hook seems like an appropriate place to initialize a has_many relationship

ActiveAdmin.register WeeklyMenu do
  after_build do |weekly_menu|
    (5 - weekly_menu.menu_items.size).times do
      weekly_menu.menu_items.build
    end
  end

  form do |f|
    f.inputs "Details" do
      f.input :title
      f.input :week
    end

    f.has_many :menu_items do |menu_item|
      menu_item.input :title
    end

    f.buttons
  end
end

Upvotes: 0

DiuDiugirl
DiuDiugirl

Reputation: 71

If you want to edit the form again, the answer of @user946611 lacks of a condition to tell whether the menu_item exists, because when submit and edit the form there will generate another five menu_items.

so it should be:

f.inputs 'Menu Items' do
    if !f.object.menu_items.present?
      5.times do
      f.object.menu_items.build
      end
    end
    f.fields_for :menu_items do |m|
      m.inputs do
        m.input :title
      end
    end
  end

Upvotes: 2

deadwards
deadwards

Reputation: 1561

The fields_for answer that @user946611 suggested didn't work for me, but the following code did:

f.inputs 'Menu Items' do
  (5 - f.object.menu_items.count).times do
    f.object.menu_items.build
  end

  f.has_many :menu_items, new_record: false do |m|
    m.input :title
    m.input(:_destroy, as: :boolean, required: false, label: 'Remove') if m.object.persisted?
  end
end

That will always show 5 forms for items, whether they have that many created or not. The new_record: false disables the "Add New Menu Item" button.

Upvotes: 3

user946611
user946611

Reputation:

Replace

f.has_many :menu_items do |menu_item|
  menu_item.input :title
end

with

f.inputs "Menu items" do
  5.times do
    f.object.menu_items.build
  end
  f.fields_for :menu_items do |m|
    m.inputs do
      m.input :title
    end
  end
end

May not be the best solution, but this should work...

Upvotes: 7

Related Questions