motor-admin / motor-admin-rails

Low-code Admin panel and Business intelligence Rails engine. No DSL - configurable from the UI. Rails Admin, Active Admin, Blazer modern alternative.
https://app.getmotoradmin.com/demo/
MIT License
761 stars 76 forks source link

Resource missing in the UI #120

Closed Frexuz closed 1 year ago

Frexuz commented 1 year ago

Just using default motor-admin without any customizations: My model that is missing:

class Matter < ApplicationRecord
  include UniqueTokenOnCreate
  unique_token_options(name: :reference, length: 5)

  belongs_to :patient
  belongs_to :doctor, optional: true
  has_many :orders, dependent: :destroy
  has_many :matter_comments, dependent: :destroy

  has_one_attached :overview_image
  has_one_attached :dermatoscope_image

  def overview_image_url
    S3UrlHelper.url_for(overview_image)
  end

  def dermatoscope_image_url
    S3UrlHelper.url_for(dermatoscope_image)
  end

  enum :status, {
    pending_payment: 0,
    paid: 1,
    delivery_sent: 2,
    delivered: 3,
    pending_info: 4,
    pending_assessor: 5,
    assessment_started: 6,
    completed: 7,
  }, suffix: true

  enum :symptom, {
    itching: 0,
    bleeding: 1,
    irritation: 2,
    visible_change: 3,
    more_noticable: 4
  }, suffix: true

  enum :planned_action, {
    no: 0,
    biopsy: 1,
    control: 2,
  }, suffix: true

  enum :diagnosis, {
    nevus: 0,
    seborrheic_keratosis: 1,
    basal_cell_carcinoma: 2,
    benign_tumor: 3,
    lentigo_solaris: 4,
    melanoma: 5,
    nevus_deviant: 6,
    deramtofibroma: 7,
    vascular_lesion: 8,
    benign_lichenoid_keratosis: 9,
    actinic_keratosis: 10,
    malign_tumor: 11,
    pigmentation_deviant: 12,
    mb_bowen_disease: 13,
    inflammatory_papule: 14,
  }, suffix: true

  enum :tag, {
    svg_melanoma_recommendation: 0,
    follow_up_dermatoscopy_in_progress: 1,
    follow_up_dermatoscopy_done: 2,
    teaching_case: 3,
  }, suffix: true

  def self.ransackable_associations(auth_object = nil)
    ['doctor', 'patient']
  end

  def self.ransackable_attributes(auth_object = nil)
    ['created_at', 'diagnosis', 'doctor_id', 'id', 'patient_id', 'planned_action', 'status', 'symptom', 'updated_at']
  end

  def display_reference
    "##{reference.upcase}"
  end
end

image

Therefore, also the associations in the UI is missing

class Patient < ApplicationRecord
  belongs_to :user
  has_many :matters, dependent: :destroy
end

SCR-20230520-ld0

Did I miss anything?

motor-admin 0.4.11 rails 7.0.4.3

omohokcoj commented 1 year ago

@Frexuz there should be an error message regarding this model in your rails server stdout after you try to load the motor admin UI for the first time after boot. At first glance the model looks good - idk what unique_token_options does - maybe it breaks the model

Frexuz commented 1 year ago

Thanks for the help :)

This? 🤔 That's the :status enum on the Matter model

translation data {:assessment_started=>"Assessment started", :completed=>"Completed", :delivered=>"Package delivered", :delivery_sent=>"Package sent", :paid=>"Paid", :pending_assessor=>"Waiting for assessor", :pending_info=>"Waiting for case information", :pending_payment=>"Waiting for payment"} can not be used with :count => 1. key 'one' is missing.

Full output

19:55:40 web.1  | Started GET "/motor_admin/cable" for ::1 at 2023-05-20 19:55:40 +0800
19:55:40 web.1  | Started GET "/motor_admin/cable/" [WebSocket] for ::1 at 2023-05-20 19:55:40 +0800
19:55:40 web.1  | Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
19:55:40 web.1  | Motor::NotificationsChannel is transmitting the subscription confirmation
19:55:41 web.1  | Started GET "/motor_admin/" for ::1 at 2023-05-20 19:55:41 +0800
19:55:41 web.1  | Processing by Motor::UiController#show as HTML
19:55:41 web.1  |   SQL (12.8ms)  SELECT 'configs', MAX(updated_at) FROM "motor_configs" UNION SELECT 'resources', MAX(updated_at) FROM "motor_resources" UNION SELECT 'dashboards', MAX(updated_at) FROM "motor_dashboards" UNION SELECT 'alerts', MAX(updated_at) FROM "motor_alerts" UNION SELECT 'queries', MAX(updated_at) FROM "motor_queries" UNION SELECT 'forms', MAX(updated_at) FROM "motor_forms" UNION SELECT 'api_configs', MAX(updated_at) FROM "motor_api_configs"
19:55:41 web.1  |   Motor::Config Load (0.2ms)  SELECT "motor_configs".* FROM "motor_configs"
19:55:41 web.1  |   TRANSACTION (0.1ms)  BEGIN
19:55:41 web.1  |   Motor::Query Load (0.3ms)  SELECT "motor_queries".* FROM "motor_queries" WHERE "motor_queries"."deleted_at" IS NULL
19:55:41 web.1  |   Motor::Alert Load (0.3ms)  SELECT "motor_alerts".* FROM "motor_alerts" WHERE "motor_alerts"."deleted_at" IS NULL
19:55:41 web.1  |   Motor::Dashboard Load (0.2ms)  SELECT "motor_dashboards".* FROM "motor_dashboards" WHERE "motor_dashboards"."deleted_at" IS NULL
19:55:41 web.1  |   Motor::Form Load (0.2ms)  SELECT "motor_forms".* FROM "motor_forms" WHERE "motor_forms"."deleted_at" IS NULL
19:55:41 web.1  |   CACHE Motor::Config Load (0.0ms)  SELECT "motor_configs".* FROM "motor_configs"
19:55:41 web.1  |   Motor::Resource Load (0.2ms)  SELECT "motor_resources".* FROM "motor_resources"
19:55:41 web.1  |   Motor::ApiConfig Load (0.2ms)  SELECT "motor_api_configs".* FROM "motor_api_configs" WHERE "motor_api_configs"."deleted_at" IS NULL
19:55:41 web.1  |   TRANSACTION (1.4ms)  COMMIT
19:55:41 web.1  |   Rendering layout /Users/frexuz/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/motor-admin-0.4.11/app/views/layouts/motor/application.html.erb
19:55:41 web.1  |   Rendering /Users/frexuz/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/motor-admin-0.4.11/app/views/motor/ui/show.html.erb within layouts/motor/application
19:55:41 web.1  |   Motor::Audit Count (2.6ms)  SELECT COUNT(*) FROM "motor_audits"
19:55:41 web.1  | translation data {:assessment_started=>"Assessment started", :completed=>"Completed", :delivered=>"Package delivered", :delivery_sent=>"Package sent", :paid=>"Paid", :pending_assessor=>"Waiting for assessor", :pending_info=>"Waiting for case information", :pending_payment=>"Waiting for payment"} can not be used with :count => 1. key 'one' is missing.
19:55:41 web.1  |   CACHE Motor::Resource Load (0.0ms)  SELECT "motor_resources".* FROM "motor_resources"
19:55:41 web.1  |   CACHE Motor::Query Load (0.0ms)  SELECT "motor_queries".* FROM "motor_queries" WHERE "motor_queries"."deleted_at" IS NULL
19:55:41 web.1  |   CACHE Motor::Dashboard Load (0.0ms)  SELECT "motor_dashboards".* FROM "motor_dashboards" WHERE "motor_dashboards"."deleted_at" IS NULL
19:55:41 web.1  |   CACHE Motor::Alert Load (0.0ms)  SELECT "motor_alerts".* FROM "motor_alerts" WHERE "motor_alerts"."deleted_at" IS NULL
19:55:41 web.1  |   CACHE Motor::Form Load (0.0ms)  SELECT "motor_forms".* FROM "motor_forms" WHERE "motor_forms"."deleted_at" IS NULL
19:55:41 web.1  |   Rendered /Users/frexuz/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/motor-admin-0.4.11/app/views/motor/ui/show.html.erb within layouts/motor/application (Duration: 364.5ms | Allocations: 521912)
19:55:41 web.1  |   Rendered layout /Users/frexuz/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/motor-admin-0.4.11/app/views/layouts/motor/application.html.erb (Duration: 382.9ms | Allocations: 534961)
19:55:41 web.1  | Completed 200 OK in 499ms (Views: 318.3ms | ActiveRecord: 132.3ms | Allocations: 589139)
19:55:41 web.1  |
19:55:41 web.1  |
19:55:41 web.1  | Finished "/motor_admin/cable/" [WebSocket] for ::1 at 2023-05-20 19:55:41 +0800
19:55:41 web.1  | Started GET "/motor_admin/cable" for ::1 at 2023-05-20 19:55:41 +0800
19:55:41 web.1  | Started GET "/motor_admin/api/notifications?page%5Blimit%5D=0&page%5Boffset%5D=0&filter%5Bstatus%5D=pending&meta=count" for ::1 at 2023-05-20 19:55:41 +0800
19:55:41 web.1  | Started GET "/motor_admin/cable/" [WebSocket] for ::1 at 2023-05-20 19:55:41 +0800
19:55:41 web.1  | Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
19:55:41 web.1  | Processing by Motor::NotificationsController#index as HTML
19:55:41 web.1  |   Parameters: {"page"=>{"limit"=>"0", "offset"=>"0"}, "filter"=>{"status"=>"pending"}, "meta"=>"count"}
19:55:41 web.1  |   Motor::Notification Count (1.2ms)  SELECT COUNT(DISTINCT "motor_notifications"."id") FROM "motor_notifications" WHERE "motor_notifications"."recipient_id" IS NULL AND "motor_notifications"."status" = 'pending'
19:55:41 web.1  | Completed 200 OK in 11ms (Views: 0.1ms | ActiveRecord: 6.5ms | Allocations: 4191)
19:55:41 web.1  |
19:55:41 web.1  |
19:55:41 web.1  | Motor::NotificationsChannel is transmitting the subscription confirmation
Frexuz commented 1 year ago

FYI, I do have translations for that model:

---
en:
  activerecord:
    attributes:
      matter:
        status:
          assessment_started: Assessment started
          completed: Completed
          delivered: Package delivered
          delivery_sent: Package sent
          paid: Paid
          pending_assessor: Waiting for assessor
          pending_info: Waiting for case information
          pending_payment: Waiting for payment

What is it trying to translate, and whats the expected output?

Frexuz commented 1 year ago

Added the one key to the translations just to test. Getting this:

---
en:
  activerecord:
    attributes:
      matter:
        one: Matter
        other: Matters
        status:
          assessment_started: Assessment started
          completed: Completed
          delivered: Package delivered
          delivery_sent: Package sent
          one: One key <----------------------------------------------
          paid: Paid
          pending_assessor: Waiting for assessor
          pending_info: Waiting for case information
          pending_payment: Waiting for payment
image

Why is the 'one' key required? That's not needed in standard rails. You should check if the key is defined, and fallback to the default column text output

Looks like a motor bug to me

omohokcoj commented 1 year ago

@Frexuz i think i figured out what happened here: You added enum status name keys into 'activerecord.attributes.matter.status' i18n hash

The problem is that it breaks the rails convention for i18n - 'activerecord.attributes.matter.status' should contain a string (AR model attr name) or a hash with One/Two/Many keys (also for AR model attrs).

So basically storing enum keys i18n in 'activerecord.attributes.matter.status' was a bad idea since it breaks rails convention. It would be best to move those keys elsewhere - lets' say into 'enums.matter.status'

Closing this ticket since motor admin is built mostly on top of rails conventions which should be followed (handling edge cases which violate rails conventions is not a goal)