Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/better error for missing resource #2062

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
44adff4
Add locations table for an example
bryszard Nov 26, 2023
fd88b73
Autofix annotations
bryszard Nov 26, 2023
b99929e
Add association to Team
bryszard Nov 26, 2023
adfa514
Add example of failing association field on TeamResource
bryszard Nov 26, 2023
bcb94d0
Add custom error for missing resource on association field
bryszard Nov 26, 2023
dc03e14
Make message more generic
bryszard Nov 26, 2023
ba04526
Add link to documentation
bryszard Nov 26, 2023
4cbf6f5
Add example for has_and_belongs_to_many
bryszard Dec 6, 2023
ce7782d
Add newlines to the missing resource message
bryszard Dec 6, 2023
333e085
Move message to the MissingResourceError class
bryszard Dec 6, 2023
5eaed6e
Catch errors for field_resource and target_resource on HasBaseField a…
bryszard Dec 6, 2023
aeafeb1
Add spec for the has_many and has_and_belongs_to_many error handling
bryszard Dec 6, 2023
e15a547
Fix schema version
bryszard Dec 6, 2023
287835b
Add location_id reference to events for belongs_to showcase
bryszard Dec 6, 2023
cf5ae07
Add Event resource and menu item in order to showcase belongs_to example
bryszard Dec 6, 2023
78fb4e6
Add single seeds for Location and Event
bryszard Dec 6, 2023
bb8458c
Add factories for Event and Location
bryszard Dec 6, 2023
bac64c8
Move belongs_to :team to the Location instead of Event
bryszard Dec 6, 2023
2bd47f0
Move missing resource error specs to one place
bryszard Dec 6, 2023
6161fe8
Add spec for belongs_to case
bryszard Dec 6, 2023
872caad
Normalize name in the error message
bryszard Dec 6, 2023
8132ca5
Move migrations to the dummy app
bryszard Dec 6, 2023
bab373a
Add comment to Event resource for consistency
bryszard Dec 6, 2023
91f4b51
Add Store model and resource for has_one showcase
bryszard Dec 6, 2023
2c7b6d0
Adjust factories - add one for Store, remove city on Location
bryszard Dec 6, 2023
2a12594
Rename spec file to model_missing_resource_spec
bryszard Dec 6, 2023
87d0fb5
Add spec for has_one case
bryszard Dec 6, 2023
e56f32e
Ignore not related server errors which are handled in failing specs
bryszard Dec 6, 2023
4522289
Annotate new models
bryszard Dec 6, 2023
d5f5269
Make all associations nullable for flexibility
bryszard Dec 12, 2023
65cf80a
tweak error message
adrianthedev Dec 8, 2023
8b27acd
Hide locations under query param, remove suppression of server errors
bryszard Dec 12, 2023
d2b4fef
schema
Paul-Bob Dec 19, 2023
9bec1b8
fix resource_generator_spec
Paul-Bob Dec 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/controllers/avo/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ def detect_fields
end

def set_related_resource
raise Avo::MissingResourceError.new(related_resource_name) if related_resource.nil?

@related_resource = related_resource.new(params: params, view: action_name.to_sym, user: _current_user, record: @related_record).detect_fields
end

Expand Down
19 changes: 19 additions & 0 deletions db/factories.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,23 @@
status { "status" }
category { ::Product.categories.values.sample }
end

factory :location do
team { create :team }
name { Faker::Address.street_name }
address { Faker::Address.full_address }
size { ["small", "medium", "large"].sample }
end

factory :event do
location { create :location }
name { Faker::Lorem.sentence }
event_time { DateTime.now }
body { Faker::Lorem.paragraphs(number: rand(1...3)).join("\n") }
end

factory :store do
name { Faker::Company.name }
size { ["small", "medium", "large"].sample }
end
end
18 changes: 18 additions & 0 deletions lib/avo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,24 @@ class MissingGemError < StandardError; end

class DeprecatedAPIError < StandardError; end

class MissingResourceError < StandardError
def initialize(resource_name)
super(missing_resource_message(resource_name))
end

private

def missing_resource_message(resource_name)
name = resource_name.to_s.downcase

"Failed to find a resource while rendering the :#{name} field.\n" \
"You may generate a resource for it by running 'rails generate avo:resource #{name.singularize}'.\n" \
"\n" \
"Alternatively add the 'use_resource' option to the :#{name} field to specify a custom resource to be used.\n" \
"More info on https://docs.avohq.io/#{Avo::VERSION[0]}.0/resources.html."
end
end

class << self
attr_reader :logger
attr_reader :cache_store
Expand Down
6 changes: 6 additions & 0 deletions lib/avo/fields/base_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ def on_create?
def in_action?
@action.present?
end

def get_resource_by_model_class(model_class)
resource = Avo.resource_manager.get_resource_by_model_class(model_class)

resource || (raise Avo::MissingResourceError.new(model_class))
end
end
end
end
6 changes: 3 additions & 3 deletions lib/avo/fields/belongs_to_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ def target_resource

if is_polymorphic?
if value.present?
return Avo.resource_manager.get_resource_by_model_class(value.class)
return get_resource_by_model_class(value.class)
else
return nil
end
Expand All @@ -243,9 +243,9 @@ def target_resource
reflection_key = polymorphic_as || id

if @record._reflections[reflection_key.to_s].klass.present?
Avo.resource_manager.get_resource_by_model_class @record._reflections[reflection_key.to_s].klass.to_s
get_resource_by_model_class(@record._reflections[reflection_key.to_s].klass.to_s)
elsif @record._reflections[reflection_key.to_s].options[:class_name].present?
Avo.resource_manager.get_resource_by_model_class @record._reflections[reflection_key.to_s].options[:class_name]
get_resource_by_model_class(@record._reflections[reflection_key.to_s].options[:class_name])
else
App.get_resource_by_name reflection_key.to_s
end
Expand Down
6 changes: 3 additions & 3 deletions lib/avo/fields/has_base_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def initialize(id, **args, &block)
end

def field_resource
resource || Avo.resource_manager.get_resource_by_model_class(@record.class)
resource || get_resource_by_model_class(@record.class)
end

def turbo_frame
Expand Down Expand Up @@ -57,9 +57,9 @@ def field_label

def target_resource
if @record._reflections[id.to_s].klass.present?
Avo.resource_manager.get_resource_by_model_class @record._reflections[id.to_s].klass.to_s
get_resource_by_model_class(@record._reflections[id.to_s].klass.to_s)
elsif @record._reflections[id.to_s].options[:class_name].present?
Avo.resource_manager.get_resource_by_model_class @record._reflections[id.to_s].options[:class_name]
get_resource_by_model_class(@record._reflections[id.to_s].options[:class_name])
else
Avo.resource_manager.get_resource_by_name id.to_s
end
Expand Down
5 changes: 5 additions & 0 deletions spec/dummy/app/avo/resources/course.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ def fields

field :links, as: :has_many, searchable: true, placeholder: "Click to choose a link",
discreet_pagination: true

if params[:show_location_field] == '1'
# Example for error message when resource is missing
field :locations, as: :has_and_belongs_to_many
end
end

def filters
Expand Down
15 changes: 15 additions & 0 deletions spec/dummy/app/avo/resources/event.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Avo::Resources::Event < Avo::BaseResource
self.title = :name
self.description = "An event that happened at a certain time."
self.includes = [:location]

def fields
field :name, as: :text, link_to_record: true, sortable: true, stacked: true
field :event_time, as: :datetime, sortable: true

if params[:show_location_field] == '1'
# Example for error message when resource is missing
field :location, as: :belongs_to
end
end
end
14 changes: 14 additions & 0 deletions spec/dummy/app/avo/resources/store.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Avo::Resources::Store < Avo::BaseResource
self.includes = [:location]

def fields
field :id, as: :id
field :name, as: :text
field :size, as: :text

if params[:show_location_field] == '1'
# Example for error message when resource is missing
field :location, as: :has_one
end
end
end
7 changes: 6 additions & 1 deletion spec/dummy/app/avo/resources/team.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Avo::Resources::Team < Avo::BaseResource
self.includes = [:admin, :team_members]
self.includes = [:admin, :team_members, :locations]
self.search = {
query: -> { query.ransack(id_eq: params[:q], name_cont: params[:q], m: "or").result(distinct: false) }
}
Expand Down Expand Up @@ -79,6 +79,11 @@ def fields
field :admin, as: :has_one
field :team_members, as: :has_many, through: :memberships, translation_key: "avo.resource_translations.team_members"
field :reviews, as: :has_many

if params[:show_location_field] == '1'
# Example for error message when resource is missing
field :locations, as: :has_many
end
end

def filters
Expand Down
2 changes: 2 additions & 0 deletions spec/dummy/app/controllers/avo/events_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Avo::EventsController < Avo::ResourcesController
end
2 changes: 2 additions & 0 deletions spec/dummy/app/controllers/avo/stores_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Avo::StoresController < Avo::ResourcesController
end
3 changes: 1 addition & 2 deletions spec/dummy/app/models/city.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@
# features :json
# metadata :json
# image_url :string
# description :text
# status :string
# tiny_description :text
# created_at :datetime not null
# updated_at :datetime not null
# latitude :float
# longitude :float
# latitude :float
# city_center_area :json
#
class City < ApplicationRecord
Expand Down
2 changes: 2 additions & 0 deletions spec/dummy/app/models/course.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class Course < ApplicationRecord

has_many :links, -> { order(position: :asc) }, class_name: "Course::Link", inverse_of: :course

has_and_belongs_to_many :locations, inverse_of: :courses

validates :name, presence: true

def has_skills
Expand Down
14 changes: 9 additions & 5 deletions spec/dummy/app/models/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
#
# Table name: events
#
# id :bigint not null, primary key
# name :string
# event_time :datetime
# created_at :datetime not null
# updated_at :datetime not null
# id :bigint not null, primary key
# name :string
# event_time :datetime
# created_at :datetime not null
# updated_at :datetime not null
# body :text
# location_id :bigint
#
class Event < ApplicationRecord
has_rich_text :body

belongs_to :location, optional: true
end
19 changes: 19 additions & 0 deletions spec/dummy/app/models/location.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# == Schema Information
#
# Table name: locations
#
# id :bigint not null, primary key
# team_id :bigint not null
# name :text
# address :string
# size :string
# created_at :datetime not null
# updated_at :datetime not null
# store_id :bigint
#
class Location < ApplicationRecord
belongs_to :store, optional: true
belongs_to :team, optional: true

has_and_belongs_to_many :courses, inverse_of: :locations
end
13 changes: 13 additions & 0 deletions spec/dummy/app/models/store.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# == Schema Information
#
# Table name: stores
#
# id :bigint not null, primary key
# name :string
# size :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Store < ApplicationRecord
has_one :location
end
1 change: 1 addition & 0 deletions spec/dummy/app/models/team.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Team < ApplicationRecord

has_many :memberships, class_name: "TeamMembership"
has_many :team_members, through: :memberships, class_name: "User", source: :user, inverse_of: :teams
has_many :locations

has_one :admin_membership, -> { where level: :admin }, class_name: "TeamMembership", dependent: :destroy
has_one :admin, through: :admin_membership, source: :user, inverse_of: :teams
Expand Down
2 changes: 2 additions & 0 deletions spec/dummy/config/initializers/avo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,12 @@

section "Store", icon: "currency-dollar" do
resource :products
resource :stores
end

group "Other", collapsable: true, collapsed: true do
resource :fish, label: "Fishies"
resource :events
end
end

Expand Down
12 changes: 12 additions & 0 deletions spec/dummy/db/migrate/20231126035843_create_locations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateLocations < ActiveRecord::Migration[6.1]
def change
create_table :locations do |t|
t.references :team, null: false, foreign_key: true
t.text :name
t.string :address
t.string :size

t.timestamps
end
end
end
10 changes: 10 additions & 0 deletions spec/dummy/db/migrate/20231205153910_create_courses_locations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateCoursesLocations < ActiveRecord::Migration[6.1]
def change
create_table :courses_locations do |t|
t.references :user, null: false, foreign_key: true
t.references :course, null: false, foreign_key: true

t.timestamps
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddLocationToEvents < ActiveRecord::Migration[6.1]
def change
add_reference :events, :location, null: true, foreign_key: true
end
end
10 changes: 10 additions & 0 deletions spec/dummy/db/migrate/20231206112806_create_stores.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateStores < ActiveRecord::Migration[6.1]
def change
create_table :stores do |t|
t.string :name
t.string :size

t.timestamps
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddStoreToLocations < ActiveRecord::Migration[6.1]
def change
add_reference :locations, :store, foreign_key: true
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class MakeTeamIdNullableOnLocations < ActiveRecord::Migration[6.1]
def change
change_column :locations, :team_id, :bigint, null: true
end
end
Loading
Loading