Administrate: Specify scope with model in admin page?

Created on 22 Apr 2016  路  5Comments  路  Source: thoughtbot/administrate

I have a user model with a role enum: [:student, :teacher, :admin]

In my administrate classroom dashboard, a classroom belongs to a teacher and has many students:

require "administrate/base_dashboard"

class ClassroomDashboard < Administrate::BaseDashboard

ATTRIBUTE_TYPES = {
    teacher: Field::BelongsTo.with_options(class_name: "User"),
    classroom_students: Field::HasMany,
    students: Field::HasMany.with_options(class_name: "User"),
    id: Field::Number,
    subject: Field::String,
    teacher_id: Field::Number,
    created_at: Field::DateTime,
    updated_at: Field::DateTime,
  }

....

FORM_ATTRIBUTES = [
    :subject,
    :teacher,
    :students,

  ]

  def display_resource(classroom)
    "#{classroom.subject} - #{classroom.teacher.first_name} #{classroom.teacher.last_name}"
  end

Everything works fine, but I'm wondering if I can make it to where my BelongsTo dropdown on the form can be limited using a scope I have in my User model User.teachers:

  # scopes
  scope :students, -> { where(role: User.roles[:student]) }
  scope :teachers, -> { where(role: User.roles[:teacher]) }
  scope :admins, -> { where(role: User.roles[:admin]) }

As it stands, the admin could make a student a teacher of a class (undesired). Whether or not it uses scopes, could I specify "This drop down contains model Users, where :type => :teacher"?

feature models

Most helpful comment

I'm late to the game but I got a decent solution, for the ones still using this gem in 2019.

I needed to apply a scope on the HasMany field and the cleaner solution I found was to create a custom field, extend from the default HasMany field and allow a dynamic scope using fields options. All the code is commented below.

app/fields/has_many_scoped_field.rb (you have nothing to change in this file, just create it)

class HasManyScopedField < Administrate::Field::HasMany
  # apply a dynamic scope
  def candidate_resources
    associated_class.send options.fetch(:model_scope)
  end

  # tell this field to use the views of the `Field::HasMany` parent class
  def to_partial_path
    "/fields/has_many/#{page}"
  end

  # apply the same class as the parent otherwise `selectize` (from JavaScript) doesn't apply
  def html_class
    "has-many"
  end
end

Then in your dashboard file (the only thing you need to change here is the scope_name)

class FooDashboard < Administrate::BaseDashboard
  ATTRIBUTE_TYPES = {
    foo: HasManyScopedField.with_options(model_scope: "scope_name"),
  }
end

All 5 comments

I have a similar issue. Leaving this comment to +1 and to subscribe to new comments.

I have the same issue.

@jdell64 Could you solve this with a custom field? Here's an example which builds a custom field off of the existing BelongsTo in order to add an order to the collection. Could you use the same approach to add a scope?

I'm late to the game but I got a decent solution, for the ones still using this gem in 2019.

I needed to apply a scope on the HasMany field and the cleaner solution I found was to create a custom field, extend from the default HasMany field and allow a dynamic scope using fields options. All the code is commented below.

app/fields/has_many_scoped_field.rb (you have nothing to change in this file, just create it)

class HasManyScopedField < Administrate::Field::HasMany
  # apply a dynamic scope
  def candidate_resources
    associated_class.send options.fetch(:model_scope)
  end

  # tell this field to use the views of the `Field::HasMany` parent class
  def to_partial_path
    "/fields/has_many/#{page}"
  end

  # apply the same class as the parent otherwise `selectize` (from JavaScript) doesn't apply
  def html_class
    "has-many"
  end
end

Then in your dashboard file (the only thing you need to change here is the scope_name)

class FooDashboard < Administrate::BaseDashboard
  ATTRIBUTE_TYPES = {
    foo: HasManyScopedField.with_options(model_scope: "scope_name"),
  }
end

I'm going to close this as it hasn't been addressed in a long time. Similar to #553, there's alternative solutions to this problem too. But of course, please open a new issue if this is still a problem!

Was this page helpful?
0 / 5 - 0 ratings