【问题标题】:Show Administrate Attribute in One Area But Not In Another在一个区域显示管理属性,但在另一个区域不显示
【发布时间】:2021-04-16 17:40:46
【问题描述】:

我正在创建一个学习管理系统。我已经让用户注册了课程。我想在用户显示页面上显示用户完成课程的时间。像这样:

如果我在app/dashboards/course_dashboard.rb 中的COLLECTION_ATTRIBUTES 下添加complete 属性,它也会显示在课程索引页面中,这是我不想要的:

如何将complete 属性添加到用户显示页面上的用户课程信息(如第一张图片)但不将其添加到课程索引页面(如第二张图片)?

【问题讨论】:

    标签: ruby-on-rails administrate


    【解决方案1】:

    很遗憾,Administrate 不支持此功能。然而,使用一点 Ruby 技巧是可能的。这是非官方的,确切的实现可能会随着新版本的管理而改变。它应该适用于 Administrate 0.15,可能还有其他版本。

    关键是Administrate代码中的这个模板:https://github.com/thoughtbot/administrate/blob/c16b8d1ee3a5ef1d622f9470738e89d73dbb8f1b/app/views/administrate/application/_collection.html.erb

    这里有两行很重要。第一个列出了表头<th>,就是这个:

    <% collection_presenter.attribute_types.each do |attr_name, attr_type| %>
    

    第二个列出每条记录的数据列&lt;td&gt;,看起来像这样:

    <% collection_presenter.attributes_for(resource).each do |attribute| %>
    

    该链接指向 Administrate 用于呈现集合的模板。这可以是索引页,也可以是 HasMany 字段中的记录列表。在上面的每一行中,它遍历为仪表板定义的集合属性,由collection_presenter.attribute_types 和collection_presenter.attributes_for(...) 返回,具体取决于具体情况。

    为了达到您想要的效果,您需要在渲染索引页面或渲染 HasMany 列表时使这些列表不同。目前,HasMany 字段没有选项来规定此列表在他们的情况下必须有所不同。

    幸运的是,我们可以在这里一起破解一些东西。

    首先,从CourseDashboard::COLLECTION_ATTRIBUTES 中删除:complete。您不希望它在索引页中列出,因此它不应该出现在那里。 不要将其从 CourseDashboard::ATTRIBUTE_TYPES 中删除,因为我们仍然需要定义它以便我们可以在其他地方使用它。

    其次,新建一个字段。我打算称它为CustomHasMany,但它可以是任何东西:

    $ ./bin/rails g administrate:field custom_has_many
          create  app/fields/custom_has_many_field.rb
          create  app/views/fields/custom_has_many_field/_show.html.erb
          create  app/views/fields/custom_has_many_field/_index.html.erb
          create  app/views/fields/custom_has_many_field/_form.html.erb
    

    我们将在UserDashboard 中将此字段用于您的courses 属性:

    require "administrate/base_dashboard"
    
    class UserDashboard < Administrate::BaseDashboard
      ATTRIBUTE_TYPES = {
        # ...
        courses: CustomHasManyField
        # ...
      }
    
    

    这最初是行不通的,因为该字段是新的。它需要的第一件事是复制现有HasMany 字段的行为。我们可以通过类继承来做到这一点:

    class CustomHasManyField < Administrate::Field::HasMany
    end
    

    这不会完全模仿HasMany 字段,因为它使用的是生成器提供的基本模板。让我们告诉它改用has_many 模板:

    class CustomHasManyField < Administrate::Field::HasMany
      def to_partial_path
        "/fields/has_many/#{page}"
      end
    end
    

    好的,现在它应该与HasMany 字段相同。到目前为止,这一直是使用公共接口和“官方”管理的东西。我不得不承认to_partial_path 没有很好的文档记录,但我认为它足够稳定。

    所以现在我们必须告诉它将complete 添加到字段列表中......这就是黑客发挥作用的地方。

    如果你阅读了Administrate的源码,你会发现上面的collection_presenter是由上层模板提供的。反过来,这被定义为field.associated_collection(order),其中field 是字段对象,在我们的例子中是CustomHasManyField 的一个实例。

    所以如果我们可以破解CustomHasManyField#associated_collection 以返回一个集合,其中attribute_types 和attributes_for 包含:complete... 我们应该没问题?

    查看集合的代码,我们可以看到两个列表依次基于另一个方法的结果attribute_names,这就是应该呈现哪些属性的真相来源:https://github.com/thoughtbot/administrate/blob/c16b8d1ee3a5ef1d622f9470738e89d73dbb8f1b/lib/administrate/page/collection.rb 如果我们修改这个attribute_names 方法,其余的都应该效仿。

    猴子补丁来救援:

    class CustomHasManyField < Administrate::Field::HasMany
      def associated_collection(*)
        collection = super
    
        def collection.attribute_names
          [:complete] + super
        end
    
        collection
      end
    
      def to_partial_path
        "/fields/has_many/#{page}"
      end
    end
    

    看起来它可以在我的电脑上运行。对你有用吗?

    至于以更正式的方式来做这件事……你想为这个项目创建一个 PR 吗?

    【讨论】:

    • 我在courses: Field::LimitedHasManyField 上收到“未初始化的常量 Administrate::Field::LimitedHasManyField”。也许我在错误的地方添加了LimitedHasManyField 类?我在 app/fields/limited_has_many_field.rb 中添加了它。
    • 啊,我找到了。几年前有人有the same problem。应该是courses: LimitedHasManyField。问题是,这并不能解决问题。我在课程索引页面上还有一个完整的条目。
    • 抱歉,我只修补了足够的修复表头&lt;th&gt;,但没有修复表记录&lt;td&gt;。我已将代码修改为足够通用以适用于两者。
    • 通过这些更改,我在collection.attribute_names 方法中得到“无法修改冻结数组:[:complete, :title, :lessons, :users]”。
    • fields.dup.delete(:complete) 更改修复了错误,但我仍然在课程索引页面上看到 complete 条目。
    【解决方案2】:

    查看https://administrate-demo.herokuapp.com/customizing_dashboards中的文档

    您需要在 SHOW_PAGE_ATTRIBUTES 中添加属性。不在 COLLECTION_ATTRIBUTES 中。

    【讨论】:

    • 也许我解释得不好我的问题,但这不是我想要完成的。如果我将complete 添加到SHOW_PAGE_ATTRIBUTES,它将显示在课程显示页面上。我不希望它在那里。我希望complete 在用户展示页面的课程信息上显示only。我已经更新了我的问题。
    • 据我了解,您需要在course_dashboard.rb 的`ATTRIBUTE_TYPES` 中声明complete,而不是在COLLECTION_ATTRIBUTES 中。然后在你的user_dashboard.rb中声明`ATTRIBUTE_TYPES`中的用户关联并在SHOW_PAGE_ATTRIBUTES中调用COLLECTION_ATTRIBUTES是出现在索引模板中的属性。
    • 我在ATTRIBUTE_TYPES 数组中做了complete 声明。我不明白“在 user_dashbaord.rb 中声明用户关联”是什么意思。你能详细说明一下吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-25
    • 1970-01-01
    • 2018-09-23
    • 2019-11-02
    • 1970-01-01
    • 2021-11-14
    相关资源
    最近更新 更多