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

fix: via resource class returns model classes vs resource classes #1293

Merged
merged 11 commits into from Oct 10, 2022
9 changes: 6 additions & 3 deletions app/components/avo/base_component.rb
Expand Up @@ -17,13 +17,16 @@ def field
end

# Fetch the resource and hydrate it with the model
def relation_resource
model_class_name = params[:via_resource_class] || params[:via_relation_class]
def association_resource
resource = ::Avo::App.get_resource(params[:via_resource_class])
model_class_name = params[:via_relation_class] || resource.model_class

model_klass = ::Avo::BaseResource.valid_model_class model_class_name

resource = ::Avo::App.get_resource_by_model_name model_klass
model = model_klass.find params[:via_resource_id]

resource = ::Avo::App.get_resource_by_model_name model_klass if resource.blank?

resource.dup.hydrate model: model
end

Expand Down
8 changes: 7 additions & 1 deletion app/components/avo/fields/belongs_to_field/edit_component.rb
Expand Up @@ -12,7 +12,7 @@ def disabled

# When visiting the record through it's association we keep the field disabled by default
# We make an exception when the user deliberately instructs Avo to allow detaching in this scenario
return !@field.allow_via_detaching if @field.target_resource.present? && @field.target_resource.model_class.name == params[:via_resource_class]
return !@field.allow_via_detaching if @field.target_resource.present? && visit_through_association?
return !@field.allow_via_detaching if @field.id.to_s == params[:via_relation].to_s

false
Expand Down Expand Up @@ -52,4 +52,10 @@ def polymorphic_record
def field_html_action
@field.get_html(:data, view: @resource.view, element: :input).fetch(:action, nil)
end

private

def visit_through_association?
@field.target_resource.class.to_s == params[:via_resource_class].to_s
end
end
Expand Up @@ -5,7 +5,7 @@ def resource_view_path
helpers.resource_view_path(
model: @field.value,
resource: @field.target_resource,
via_resource_class: @resource.model_class,
via_resource_class: @resource.class.to_s,
via_resource_id: @resource.model.id
)
end
Expand Down
6 changes: 4 additions & 2 deletions app/components/avo/fields/index_component.rb
Expand Up @@ -3,13 +3,15 @@
class Avo::Fields::IndexComponent < ViewComponent::Base
include Avo::ResourcesHelper

attr_reader :parent_resource
attr_reader :view

def initialize(field: nil, resource: nil, index: 0, parent_model: nil)
def initialize(field: nil, resource: nil, index: 0, parent_model: nil, parent_resource: nil)
@field = field
@resource = resource
@index = index
@parent_model = parent_model
@parent_resource = parent_resource
@view = :index
end

Expand All @@ -18,7 +20,7 @@ def resource_view_path

if @parent_model.present?
args = {
via_resource_class: @parent_model.class,
via_resource_class: @parent_resource.class,
via_resource_id: @parent_model.id
}
end
Expand Down
2 changes: 1 addition & 1 deletion app/components/avo/index/grid_item_component.rb
Expand Up @@ -32,7 +32,7 @@ def resource_view_path

if @parent_model.present?
args = {
via_resource_class: parent_resource.model_class,
via_resource_class: parent_resource.class.to_s,
via_resource_id: @parent_model.id
}
end
Expand Down
4 changes: 2 additions & 2 deletions app/components/avo/index/resource_controls_component.rb
Expand Up @@ -36,7 +36,7 @@ def show_path

if @parent_model.present?
args = {
via_resource_class: parent_resource.model_class,
via_resource_class: parent_resource.class.to_s,
via_resource_id: @parent_model.id
}
end
Expand All @@ -50,7 +50,7 @@ def edit_path

if @parent_model.present?
args = {
via_resource_class: parent_resource.model_class,
via_resource_class: parent_resource.class.to_s,
via_resource_id: @parent_model.id
}
end
Expand Down
2 changes: 1 addition & 1 deletion app/components/avo/index/table_row_component.html.erb
Expand Up @@ -17,7 +17,7 @@
</td>
<% end %>
<% @resource.get_fields(reflection: @reflection, only_root: true).each_with_index do |field, index| %>
<%= render field.component_for_view(:index).new(field: field, resource: @resource, index: index, parent_model: @parent_model) %>
<%= render field.component_for_view(:index).new(field: field, resource: @resource, index: index, parent_model: @parent_model, parent_resource: @parent_resource) %>
<% end %>
<% if Avo.configuration.resource_controls_on_the_right? %>
<td class="text-right whitespace-nowrap px-2" data-control="resource-controls">
Expand Down
2 changes: 1 addition & 1 deletion app/components/avo/views/resource_edit_component.rb
Expand Up @@ -31,7 +31,7 @@ def resources_path
end

def resource_view_path
helpers.resource_view_path(model: relation_resource.model, resource: relation_resource)
helpers.resource_view_path(model: association_resource.model, resource: association_resource)
end

def can_see_the_destroy_button?
Expand Down
3 changes: 1 addition & 2 deletions app/components/avo/views/resource_show_component.rb
Expand Up @@ -26,8 +26,7 @@ def title

def back_path
if via_resource?
model_class = ::Avo::BaseResource.valid_model_class params[:via_resource_class]
helpers.resource_path(model: model_class, resource: relation_resource, resource_id: params[:via_resource_id])
helpers.resource_path(model: association_resource.model_class, resource: association_resource, resource_id: params[:via_resource_id])
else
helpers.resources_path(resource: @resource)
end
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/avo/base_controller.rb
Expand Up @@ -84,7 +84,7 @@ def show

# If we're accessing this resource via another resource add the parent to the breadcrumbs.
if params[:via_resource_class].present? && params[:via_resource_id].present?
via_resource = Avo::App.get_resource_by_model_name(params[:via_resource_class]).dup
via_resource = Avo::App.get_resource(params[:via_resource_class]).dup
via_model = via_resource.class.find_scope.find params[:via_resource_id]
via_resource.hydrate model: via_model

Expand Down Expand Up @@ -371,7 +371,7 @@ def set_edit_title_and_breadcrumbs
last_crumb_args = {}
# If we're accessing this resource via another resource add the parent to the breadcrumbs.
if params[:via_resource_class].present? && params[:via_resource_id].present?
via_resource = Avo::App.get_resource_by_model_name(params[:via_resource_class]).dup
via_resource = Avo::App.get_resource(params[:via_resource_class]).dup
via_model = via_resource.class.find_scope.find params[:via_resource_id]
via_resource.hydrate model: via_model

Expand Down
2 changes: 1 addition & 1 deletion lib/avo/base_resource.rb
Expand Up @@ -124,7 +124,7 @@ def get_available_models

def valid_model_class(model_class)
get_available_models.find do |m|
m.to_s == model_class
m.to_s == model_class.to_s
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/avo/concerns/fetches_things.rb
Expand Up @@ -36,7 +36,7 @@ def get_resource(resource)
possible_resource = "#{resource}Resource".gsub "ResourceResource", "Resource"

resources.find do |available_resource|
possible_resource.safe_constantize == available_resource.class
possible_resource.to_s == available_resource.class.to_s
end
end

Expand Down
68 changes: 68 additions & 0 deletions spec/dummy/app/avo/resources/z_post_resource.rb
@@ -0,0 +1,68 @@
class ZPostResource < Avo::BaseResource
self.title = :name
self.search_query = -> do
scope.ransack(id_eq: params[:q], name_cont: params[:q], body_cont: params[:q], m: "or").result(distinct: false)
end
self.search_query_help = "- search by id, name or body"
self.includes = [:user]
self.default_view_type = :grid
self.model_class = "Post"

# self.show_controls = -> do
# detach_button
# edit_button
# link_to "google", "goolee"
# end

field :id, as: :id
field :name, as: :text, required: true, sortable: true
field :body,
as: :trix,
placeholder: "Enter text",
always_show: false,
attachment_key: :attachments,
hide_attachment_url: true,
hide_attachment_filename: true,
hide_attachment_filesize: true
field :tags,
as: :tags,
# readonly: true,
acts_as_taggable_on: :tags,
close_on_select: false,
placeholder: "add some tags",
suggestions: -> { Post.tags_suggestions },
enforce_suggestions: true,
help: "The only allowed values here are `one`, `two`, and `three`"
field :cover_photo, as: :file, is_image: true, as_avatar: :rounded, full_width: true, hide_on: [], accept: "image/*"
field :cover_photo, as: :external_image, name: "Cover photo", required: true, hide_on: :all, link_to_resource: true, as_avatar: :rounded, format_using: ->(value) { value.present? ? value&.url : nil }
field :audio, as: :file, is_audio: true, accept: "audio/*"
field :excerpt, as: :text, hide_on: :all, as_description: true do |model|
ActionView::Base.full_sanitizer.sanitize(model.body).truncate 130
rescue
""
end

field :is_featured, as: :boolean, visible: ->(resource:) { context[:user].is_admin? }
field :is_published, as: :boolean do |model|
model.published_at.present?
end
field :user, as: :belongs_to, placeholder: "—"
field :status, as: :select, enum: ::Post.statuses, display_value: false
field :comments, as: :has_many, use_resource: PhotoCommentResource

grid do
cover :cover_photo, as: :file, is_image: true, link_to_resource: true
title :name, as: :text, required: true, link_to_resource: true
body :excerpt, as: :text do |model|
ActionView::Base.full_sanitizer.sanitize(model.body).truncate 130
rescue
""
end
end

filter FeaturedFilter
filter PublishedFilter
filter PostStatusFilter

action TogglePublished
end
2 changes: 2 additions & 0 deletions spec/dummy/app/controllers/avo/z_posts_controller.rb
@@ -0,0 +1,2 @@
class Avo::ZPostsController < Avo::ResourcesController
end
2 changes: 1 addition & 1 deletion spec/dummy/app/models/comment.rb
Expand Up @@ -16,7 +16,7 @@ class Comment < ApplicationRecord
validate :body_different

has_one_attached :photo

belongs_to :commentable, polymorphic: true, optional: true
belongs_to :user, optional: true

Expand Down
3 changes: 2 additions & 1 deletion spec/dummy/config/initializers/avo.rb
Expand Up @@ -26,7 +26,7 @@

## == Customization ==
config.id_links_to_resource = true
config.full_width_container = true
config.full_width_container = false
config.buttons_on_form_footers = false
# config.resource_controls_placement = ENV["AVO_RESOURCE_CONTROLS_PLACEMENT"]&.to_sym || :right
config.resource_default_view = :show
Expand Down Expand Up @@ -95,6 +95,7 @@
end

group "Blog", collapsable: true do
# resource :z_posts
resource :posts
resource :comments
resource :photo_comments, visible: -> do
Expand Down
22 changes: 11 additions & 11 deletions spec/features/avo/allow_via_detaching_spec.rb
@@ -1,18 +1,18 @@
require 'rails_helper'
require "rails_helper"

RSpec.feature "AllowViaDetachings", type: :feature do
describe "when allowed" do
let(:team) { create :team }
let(:review) { create :review, reviewable: team }

it "is enabled" do
visit "/admin/resources/reviews/#{review.id}/edit?via_resource_class=Team&via_resource_id=#{team.id}"
visit "/admin/resources/reviews/#{review.id}/edit?via_resource_class=TeamResource&via_resource_id=#{team.id}"

expect(page).to have_field 'review_reviewable_type', type: :select, disabled: false
# review_reviewable_id is disabled because it's a searchable field
expect(page).to have_field 'review_reviewable_id', type: :text, disabled: true
# review_user_id is disabled because it's a searchable field
expect(page).to have_field 'review_user_id', type: :text, disabled: true
expect(page).to have_field "review_reviewable_type", type: :select, disabled: false
# review_reviewable_id is disabled because it"s a searchable field
expect(page).to have_field "review_reviewable_id", type: :text, disabled: true
# review_user_id is disabled because it"s a searchable field
expect(page).to have_field "review_user_id", type: :text, disabled: true
end
end

Expand All @@ -21,11 +21,11 @@
let(:comment) { create :comment, commentable: post }

it "is enabled" do
visit "/admin/resources/comments/#{comment.id}/edit?via_resource_class=Post&via_resource_id=#{post.id}"
visit "/admin/resources/comments/#{comment.id}/edit?via_resource_class=PostResource&via_resource_id=#{post.id}"

expect(page).to have_field 'comment_commentable_type', type: :select, disabled: true
expect(page).to have_field 'comment_commentable_id', type: :select, disabled: true
expect(page).to have_field 'comment_user_id', type: :select, disabled: false
expect(page).to have_field "comment_commentable_type", type: :select, disabled: true
expect(page).to have_field "comment_commentable_id", type: :select, disabled: true
expect(page).to have_field "comment_user_id", type: :select, disabled: false
end
end
end
6 changes: 3 additions & 3 deletions spec/features/avo/belongs_to_spec.rb
Expand Up @@ -39,7 +39,7 @@
describe "with user attached" do
let!(:post) { create :post, user: admin }

it { is_expected.to have_link admin.name, href: "/admin/resources/users/#{admin.slug}?via_resource_class=Post&via_resource_id=#{post.id}" }
it { is_expected.to have_link admin.name, href: "/admin/resources/users/#{admin.slug}?via_resource_class=PostResource&via_resource_id=#{post.id}" }
end

describe "without user attached" do
Expand All @@ -66,7 +66,7 @@
click_on "Save"

expect(current_path).to eql "/admin/resources/posts/#{post.id}"
expect(page).to have_link admin.name, href: "/admin/resources/users/#{admin.slug}?via_resource_class=Post&via_resource_id=#{post.id}"
expect(page).to have_link admin.name, href: "/admin/resources/users/#{admin.slug}?via_resource_class=PostResource&via_resource_id=#{post.id}"
end
end

Expand All @@ -85,7 +85,7 @@
click_on "Save"

expect(current_path).to eql "/admin/resources/posts/#{post.id}"
expect(page).to have_link second_user.name, href: "/admin/resources/users/#{second_user.slug}?via_resource_class=Post&via_resource_id=#{post.id}"
expect(page).to have_link second_user.name, href: "/admin/resources/users/#{second_user.slug}?via_resource_class=PostResource&via_resource_id=#{post.id}"
end

it "nullifies the user" do
Expand Down
8 changes: 4 additions & 4 deletions spec/features/avo/has_many_field_spec.rb
Expand Up @@ -59,14 +59,14 @@

## Table Rows
# show link
show_path = "/admin/resources/posts/#{post.id}?via_resource_class=User&via_resource_id=#{user.id}"
show_path = "/admin/resources/posts/#{post.id}?via_resource_class=UserResource&via_resource_id=#{user.id}"
expect(page).to have_css("a[data-control='show'][href='#{show_path}']")

# id field show link
expect(field_element_by_resource_id("id", post.id)).to have_css("a[href='/admin/resources/posts/#{post.id}?via_resource_class=User&via_resource_id=#{user.id}']")
expect(field_element_by_resource_id("id", post.id)).to have_css("a[href='/admin/resources/posts/#{post.id}?via_resource_class=UserResource&via_resource_id=#{user.id}']")

# edit link
edit_path = "/admin/resources/posts/#{post.id}/edit?via_resource_class=User&via_resource_id=#{user.id}"
edit_path = "/admin/resources/posts/#{post.id}/edit?via_resource_class=UserResource&via_resource_id=#{user.id}"
expect(page).to have_selector("[data-component='resources-index'] a[data-control='edit'][data-resource-id='#{post.id}'][href='#{edit_path}']")

# detach form
Expand Down Expand Up @@ -136,7 +136,7 @@
expect(link.link).to eq "https://google.com"
expect(link.course.id).to eq course.id

visit "/admin/resources/course_links/#{link.id}/edit?via_resource_class=Course&via_resource_id=#{course.id}"
visit "/admin/resources/course_links/#{link.id}/edit?via_resource_class=CourseResource&via_resource_id=#{course.id}"
fill_in "course_link_link", with: "https://apple.com"
click_on "Save"
link.reload
Expand Down
6 changes: 3 additions & 3 deletions spec/features/avo/skip_show_view_spec.rb
Expand Up @@ -85,7 +85,7 @@
expect(current_path).to eql "/admin/resources/courses/#{course.id}/edit"

# Delete
visit "/admin/resources/course_links/#{course.links.first.id}/edit?via_resource_class=Course&via_resource_id=#{course.id}"
visit "/admin/resources/course_links/#{course.links.first.id}/edit?via_resource_class=CourseResource&via_resource_id=#{course.id}"

click_on "Delete"

Expand Down Expand Up @@ -172,10 +172,10 @@
expect(current_path).to eql "/admin/resources/courses/#{course.id}"

# Delete
visit "/admin/resources/course_links/#{course.links.first.id}/edit?via_resource_class=Course&via_resource_id=#{course.id}"
visit "/admin/resources/course_links/#{course.links.first.id}/edit?via_resource_class=CourseResource&via_resource_id=#{course.id}"
expect(page).to_not have_selector("[data-control='destroy']")

visit "/admin/resources/course_links/#{course.links.first.id}?via_resource_class=Course&via_resource_id=#{course.id}"
visit "/admin/resources/course_links/#{course.links.first.id}?via_resource_class=CourseResource&via_resource_id=#{course.id}"
click_on "Delete"

expect(page).to have_text("Record destroyed")
Expand Down