Skip to content

Has Many Relationship Tab

Oskars Ezerins edited this page Aug 5, 2021 · 8 revisions

Question

How do you add a has_many tab to manage relationships of a model?

Answer

There is a plan to eventually implement a "subresource" feature, allowing easy management of has_many associations, either inline or from a separate form. However here is how you would accomplish it in the mean time.

I'll use an example below of a Project that has_many Tasks. First we'll add the tab and table on the parent resource:

Trestle.resource(:projects) do
  form do |project|
    tab :project do
      text_field :name
      text_area :description
    end

    tab :tasks, badge: project.tasks.size do
      table project.tasks, admin: :tasks do
        column :description, link: true
        column :done, align: :center
        column :created_at, align: :center
        actions
      end

      concat admin_link_to("New Task", admin: :tasks, action: :new, params: { project_id: project }, class: "btn btn-success")
    end
  end
end

The "New Task" link is probably the most complicated bit, but we want to ensure that we pass the project id as a parameter when building the task. To actually use this, we need to override the build_instance block in the child (Task) resource:

Trestle.resource(:tasks) do
  build_instance do |attrs, params|
    scope = params[:project_id] ? Project.find(params[:project_id]).tasks : Task
    scope.new(attrs)
  end
end

This uses the Project association to build the new task if the project id is provided, otherwise it will ignore it and simply to Task.new. You'll need to make sure that your task form includes a project_idfield somewhere, either via a select tag or hidden_field.

A couple of potential improvements are to load the task form within a dialog (which may or may not make sense for your use case), as well as to show the project select field depending on whether it has been previously set:

form dialog: true do |task|
  if task.project
    hidden_field :project_id
  else
    select :project_id, Project.all
  end

  text_field :description
  check_box :done
end

I hope that all helps. You're definitely right about the documentation lacking right now, and it's taking way too long for me to get it out. However I've recently restructured my current WIP and it's making things progress much smoother.

If You want to use scoped resources prefix the the class name with module name and "/":

Trestle.resource(:projects) do
  form do |project|
    tab :project do
      text_field :name
      text_area :description
    end

    tab :tasks, badge: project.tasks.size do
      table project.tasks, admin: 'custom_scope/tasks' do
        column :description, link: true
        column :done, align: :center
        column :created_at, align: :center
        actions
      end
    end
  end
end