Repository navigation
Ask the model for its DOM name instead of approximating it - #56
Merged
Merged
Conversation
Follow-up to #53, from the same review. #53 fixed how a *label* becomes a CSS class; these are the two remaining derivations of the same kind, where a *model* becomes one. Arbre builds a record's DOM name from `record.class.model_name.singular` (html/tag.rb:164-168) and ActiveAdmin builds the index table id from `active_admin_config.resource_name.plural` (index_as_table.rb:240) — both of which underscore a namespace. The gem used `gsub(' ', '_').downcase` plus an unconditional singularize/pluralize, which leaves the `::` alone: have_attributes_table(model: 'Billing::Employee') => div.attributes_table.billing::employee have_table(resource_name: Billing::Employee) => table#index_table_billing::employees Neither is a selector. Under cuprite the first aborts the example with Ferrum::JavaScriptError, under rack_test with Nokogiri::CSS::SyntaxError — in both cases with nothing naming the cause. `table_selector` also had no class branch at all, so passing a model class was broken for every namespaced model. Verified against real rendered pages: the dummy renders `<div class="attributes_table billing_employee">` and `<table id="index_table_business_employees">`, and the new system spec asserts both. Restoring the old derivation fails it. Note the two names have different sources: the table id follows the name a resource was *registered* under (`as: 'Business Employee'`), so a renamed resource cannot be addressed by its class. Documented at the call site rather than papered over. Also fixes six dead `have_table_cell` examples in README.md, which still showed a positional-text signature the matcher has never had — they raise TypeError or ArgumentError as written.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #53, from the same review. #53 fixed how a label becomes a CSS class; this is the other half — how a model becomes one.
The bug
Arbre derives a record's DOM name from
record.class.model_name.singular, falling back toname.underscore.gsub('/', '_')(arbre html/tag.rb:164-168), and ActiveAdmin builds the index table id fromactive_admin_config.resource_name.plural(index_as_table.rb:240). Both underscore a namespace.The gem used
gsub(' ', '_').downcaseplus an unconditionalsingularize/pluralize, which leaves::in place:Neither is a selector. Under cuprite the first aborts the example with
Ferrum::JavaScriptError, under rack_test withNokogiri::CSS::SyntaxError— in both cases with nothing pointing at the cause, so it reads as a driver problem rather than a bad selector.table_selectoralso had no class branch at all: it called.to_son whatever it was given, so passing a model class was broken for every namespaced model.Secondary: the unconditional
singularizemangles irregulars even on the happy path —parse_model_name('Statistics')returnedstatistic.What it renders, measured
Printed from the dummy app with a real browser rather than reasoned about:
Note the two come from different sources: the table id follows the name the resource was registered under (
register Billing::Employee, as: 'Business Employee'), while the attributes-table class follows the model class. A renamed resource therefore cannot be addressed by its class — that is ActiveAdmin's design, not something this PR can fix, so it is documented at the call site instead of papered over.The fix
parse_model_nameasks the model when it can, and otherwise mirrors Arbre's fallback:with
dom_model_namedoingunderscore.tr('/', '_').tr(' ', '_').table_selectornow routes through it instead of carrying its own copy.Verification
Six unit examples, plus
spec/system/namespaced_model_names_spec.rbasserting both names against a real rendered page — restoring the old derivation fails it:Suite: 42 examples, 0 failures.
Also
Six dead
have_table_cellexamples inREADME.md(lines 58-68). The matcher has always beenhave_table_cell(options = {})reading:column, but the README showshave_table_cell('John Doe', row_id: …, col_name: …), which raisesTypeError: no implicit conversion of Symbol into StringorArgumentError: wrong number of arguments.docs/guide/README.mdalready uses the correct form; only the top-level README was stale.Depends on
Nothing, but it overlaps #55 in spirit — that one adds the missing
require 'capybara/active_admin/util'to these same two selector files. Different hunks, so they do not conflict; either order merges.Left out deliberately
The review also flagged
table_scope_selectoras a bareli.scopewhileActiveAdmin::Scoperenders its id as a class. I measured it on a real page:have_table_scope(title)keys onexact_text: title, which cannot match whilescopes_show_countis on by default. But the class is not reliably derivable from the title either —Scope#initializetakes the id from the method when one is given (scope 'Pending Review', :awaiting→awaiting), and only otherwise from the name. Fixing it properly means deciding on an API, so it wants a maintainer's call rather than a guess from me.