Skip to content

FEATURE: Can edit category/host relationships for embedding#10

Open
ShashankFC wants to merge 1 commit into
rest-serializer-enhancement-prefrom
rest-serializer-enhancement-post
Open

FEATURE: Can edit category/host relationships for embedding#10
ShashankFC wants to merge 1 commit into
rest-serializer-enhancement-prefrom
rest-serializer-enhancement-post

Conversation

@ShashankFC

@ShashankFC ShashankFC commented Jan 5, 2026

Copy link
Copy Markdown
Collaborator

Test 10

Summary by CodeRabbit

Release Notes

  • New Features

    • Added admin interface for managing embeddable hosts with per-host category assignment
    • Embeddable hosts can now be created, edited, and deleted with an associated category for embedded posts
  • Refactoring

    • Migrated embeddable hosts from site settings to a database-backed model for improved management and scalability

✏️ Tip: You can customize this high-level summary in your review settings.


Replicated from ai-code-review-evaluation/discourse-coderabbit#10

@ShashankFC

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jan 13, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jan 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Introduces a comprehensive embedding management system that migrates embeddable host configuration from site settings to a database-backed model, including new admin UI components, controllers, routes, and updates to the embed validation logic to use the new EmbeddableHost model.

Changes

Cohort / File(s) Summary
Frontend Admin Routing & Mapping
app/assets/javascripts/admin/routes/admin-route-map.js.es6
Added adminEmbedding resource under adminCustomize route with path /embedding
Frontend Admin Controllers
app/assets/javascripts/admin/controllers/admin-embedding.js.es6
New controller with saveChanges, addHost, and deleteHost actions for managing embedding data
Frontend Admin Routes
app/assets/javascripts/admin/routes/admin-embedding.js.es6
New route that fetches embedding model and assigns it to controller
Frontend Admin Adapters
app/assets/javascripts/admin/adapters/embedding.js.es6
New REST adapter extending RestAdapter, routing to /admin/customize/embedding
Frontend Admin Templates
app/assets/javascripts/admin/templates/embedding.hbs
New template rendering table of embeddable hosts with add host button
Frontend Admin Templates & Navigation
app/assets/javascripts/admin/templates/customize.hbs, app/assets/javascripts/admin/templates/components/embeddable-host.hbs
Added embedding navigation item; new embeddable-host component template with edit/view modes, category selector, and save/delete actions
Frontend Admin Components
app/assets/javascripts/admin/components/embeddable-host.js.es6
New component handling host editing workflow with buffered properties, category assignment, input focus management, and edit/save/delete/cancel actions
Frontend Core Adapter
app/assets/javascripts/discourse/adapters/rest.js.es6
Added embeddable-host to ADMIN_MODELS set; normalized type by replacing underscores with hyphens in admin path resolution
Frontend Core Store
app/assets/javascripts/discourse/models/store.js.es6
Extended _hydrateEmbedded method to support both singular and plural embedded IDs, mapping arrays to hydrated objects
Backend Admin Controllers
app/controllers/admin/embeddable_hosts_controller.rb, app/controllers/admin/embedding_controller.rb
New controllers with create/update/destroy actions for hosts and show/update for embedding with category defaulting
Backend Routes & Config
config/routes.rb, config/site_settings.yml
Added routes for embedding (GET/PUT) and embeddable_hosts resource; removed embeddable_hosts and embed_category site settings
Backend Models
app/models/embeddable_host.rb
New model with host validation/normalization, category association, and utility methods (record_for_host, host_allowed?)
Backend Model Updates
app/models/site_setting.rb
Removed allows_embeddable_host? class method
Backend Model Updates
app/models/topic.rb, app/models/topic_embed.rb
Simplified expandable_first_post? predicate (removed embeddable_hosts check); updated topic_embed to use EmbeddableHost.record_for_host for category assignment
Backend Embed Controller
app/controllers/embed_controller.rb
Replaced SiteSetting-based host validation with EmbeddableHost.host_allowed? check
Backend Serializers
app/serializers/embeddable_host_serializer.rb, app/serializers/embedding_serializer.rb
New serializers exposing embeddable host fields and has_many embeddable_hosts relationship
Backend Library
lib/topic_retriever.rb
Updated invalid_host? check to use EmbeddableHost.host_allowed? instead of SiteSetting method
Database Migration
db/migrate/20150818190757_create_embeddable_hosts.rb
Creates embeddable_hosts table and migrates data from site settings with category association
Localization
config/locales/client.en.yml, config/locales/server.en.yml
Added embedding-related translation keys (title, host, edit, category, add_host, confirm_delete); removed embeddable_hosts and embed_category keys
Test Specs & Fabricators
spec/controllers/admin/\\*_controller_spec.rb, spec/models/embeddable_host_spec.rb, spec/models/\\*_spec.rb
Added controller inheritance tests, new embeddable_host model tests (host normalization, host_allowed? behavior), updated existing tests to use EmbeddableHost fixtures
Test Fabricators
spec/fabricators/embeddable_host_fabricator.rb, spec/fabricators/category_fabricator.rb
Moved category fabricators to embeddable_host_fabricator.rb; added embeddable_host fabricator with host and category association
Test JavaScript
test/javascripts/helpers/create-pretender.js.es6, test/javascripts/models/store-test.js.es6
Updated API fixtures to include colors data and verify embedded collection hydration; updated embedded store tests for plural ID support

Sequence Diagram

sequenceDiagram
    participant Admin as Admin User
    participant UI as Embedding Admin UI
    participant Controller as Admin Controller
    participant Model as EmbeddableHost Model
    participant DB as Database

    Admin->>UI: Click "Add Host"
    UI->>Controller: addHost() action
    Controller->>Model: Create new embeddable_host record
    Model-->>Controller: New record instance
    Controller->>UI: Push to embedding.embeddable_hosts
    
    Admin->>UI: Fill host and category, click Save
    UI->>Controller: save() action with buffered data
    Controller->>Model: save(host, category_id)
    Model->>DB: INSERT/UPDATE embeddable_hosts
    DB-->>Model: Record persisted
    Model-->>Controller: Success
    Controller->>UI: Exit edit mode, refresh display
    
    Admin->>UI: Click delete icon
    UI->>Admin: Show confirmation
    Admin->>UI: Confirm delete
    UI->>Controller: deleteHost(host) action
    Controller->>Model: destroy(host_id)
    Model->>DB: DELETE from embeddable_hosts
    DB-->>Model: Record deleted
    Model-->>Controller: Success
    Controller->>UI: Remove from embedding.embeddable_hosts
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

The changes span multiple architectural layers (frontend components, controllers, routes; backend models, controllers, serializers; database migration) with heterogeneous modifications including new features (admin UI, model validation, relationships), refactoring of existing logic (site settings → database), and comprehensive test coverage across models, controllers, and fabricators. While individual changes follow consistent patterns, the breadth and interconnectedness of updates across the stack require careful validation of integration points.

Poem

🐰 Hops with glee

Embeddable hosts, now stored with care,
No more settings tangled in the air!
Database rows, so neat and fine,
Admin UI, a feature divine—
The bunny approves of this fine design! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature: enabling editing of category and host relationships for the embedding functionality, which is the central theme of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@ShashankFC

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jan 13, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Fix all issues with AI agents
In @app/assets/javascripts/admin/components/embeddable-host.js.es6:
- Around line 46-48: The delete action currently calls
this.get('host').destroyRecord() without error handling; append a
.catch(popupAjaxError) to the promise chain (matching the save action pattern)
so server errors surface to the user, and ensure the popupAjaxError helper is
imported/available in this component (referencing destroyRecord and
popupAjaxError and the existing sendAction('deleteHost', this.get('host'))
sequence).

In @app/assets/javascripts/admin/controllers/admin-embedding.js.es6:
- Around line 14-16: The deleteHost action only removes the host from the local
embedding.embeddable_hosts array and does not persist to the server; update
deleteHost to check the record state (e.g., host.get('isNew') or host.get('id'))
and for persisted hosts call host.destroyRecord() (or host.deleteRecord()
followed by host.save()) and only remove it from embedding.embeddable_hosts
after the destroy/save succeeds (handle promise .then/.catch to update the array
and surface errors); for new/unsaved hosts simply removeObject(host) as before.

In @app/controllers/admin/embeddable_hosts_controller.rb:
- Around line 9-12: The update action calls save_host with host =
EmbeddableHost.where(id: params[:id]).first but doesn't handle the case when
host is nil; add a nil check in the update method to return early and respond
appropriately (e.g., render head :not_found or redirect with a flash error) when
host is not found, and only call save_host(host) when host is present; reference
the update action and save_host method to implement this guard.
- Around line 14-18: The destroy action calls host.destroy without handling a
missing record; update the EmbeddableHostsController#destroy to fetch the record
via EmbeddableHost.where(id: params[:id]).first (or find_by) and return an
appropriate error/404 response when host is nil instead of calling destroy on
nil, otherwise call host.destroy and render success_json; ensure you reference
the same symbols (destroy, EmbeddableHost, params[:id], success_json) when
adding the nil check and response.

In @app/models/embeddable_host.rb:
- Around line 5-8: The before_validation callback currently calls self.host.sub!
twice which will raise NoMethodError when host is nil; update the callback in
embeddable_host.rb to guard against nil by checking presence of host (e.g.,
return unless host or use host.to_s) before calling sub! or operate on a safe
local string, ensuring you still strip leading http(s):// and trailing path
while not invoking sub! on nil; reference the before_validation block and
self.host.sub! occurrences when making the change.
- Line 2: The host validation regex in validates_format_of :host restricts TLDs
to 2–5 letters and will reject valid longer gTLDs; update the pattern used in
validates_format_of :host to allow TLDs of two or more letters (e.g., change
`[a-z]{2,5}` to `[a-z]{2,}`) or replace the simple regex with a more robust
domain validation helper that handles IDNs and new gTLDs, ensuring the change is
applied where validates_format_of :host is defined.
- Around line 10-18: The method record_for_host currently uses an inline rescue
modifier and returns false on failure which mixes return types; change it to
return nil on failure and replace the `rescue nil` with an explicit begin/rescue
that only rescues URI::InvalidURIError (or StandardError if necessary) so
exceptions aren't silently swallowed; extract the hostname via
URI.parse(host).host (or check host presence first), normalize it (e.g.,
downcase) and then perform the query using where(...).first; ensure callers
(e.g., host_allowed?) expect nil rather than false.

In @db/migrate/20150818190757_create_embeddable_hosts.rb:
- Around line 24-26: The migration directly interpolates the host string inside
the raw SQL in the records.each do |h| loop (the execute call), exposing an SQL
injection risk; change the insert to use a parameterized/quoted value instead of
string interpolation — e.g., use ActiveRecord's quote(h) or bind parameters when
building the INSERT in the execute call (keep the same embeddable_hosts columns
and category_id variable) so the host value is properly escaped before executing
the SQL.

In @spec/fabricators/embeddable_host_fabricator.rb:
- Around line 23-26: The after_build block currently calls cat.update! which
performs an immediate DB save; instead assign the attribute directly (set
cat.read_restricted = true) and keep building the association via
cat.category_groups.build(group_id: transients[:group].id, permission_type:
CategoryGroup.permission_types[:full]) so Fabrication handles persistence;
remove the update! call and use direct attribute assignment inside the
after_build callback.

In @spec/models/topic_spec.rb:
- Line 1407: The spec description contains a typo: change the string literal in
the spec block from "with an emeddable host" to "with an embeddable host" by
updating the describe block that currently reads 'with an emeddable host' to the
corrected 'with an embeddable host' (leave the surrounding describe ... do/end
intact).

In @test/javascripts/models/store-test.js.es6:
- Around line 109-121: The test named "find embedded" is asserting colors for
fruit id 2 (banana) but fixture data in create-pretender.js.es6 shows banana has
color_ids [3]; update the test to be consistent by either calling
store.find('fruit', 1) to test apple (which has color_ids [1,2]) or adjust the
assertions after store.find('fruit', 2) (inside the test('find embedded')
callback) to expect a single color with id 3 (and length 1) and update the
corresponding id checks and messages accordingly; ensure createStore() usage and
the assertions on f.get('colors') are changed to match the chosen fruit.
🧹 Nitpick comments (15)
db/migrate/20150818190757_create_embeddable_hosts.rb (1)

1-32: Migration is not reversible.

This migration lacks a down method, making rollback impossible. Consider adding a reversible block or explicit up/down methods if rollback support is needed.

♻️ Suggested reversible implementation
class CreateEmbeddableHosts < ActiveRecord::Migration
  def up
    # ... current change method content ...
  end

  def down
    # Re-create site_settings entries if needed, or just drop table
    drop_table :embeddable_hosts
  end
end
app/assets/javascripts/discourse/models/store.js.es6 (1)

196-201: Potential undefined values in hydrated colors array.

If _lookupSubType returns undefined for any ID (e.g., if a color ID references a non-existent color), the resulting array will contain undefined elements. The || [] fallback on line 200 only applies if the entire hydrated variable is falsy, not individual elements.

♻️ Proposed fix: filter out undefined values
         if (m[2]) {
           const hydrated = obj[k].map(function(id) {
             return self._lookupSubType(subType, type, id, root);
-          });
-          obj[self.pluralize(subType)] = hydrated || [];
+          }).filter(Boolean);
+          obj[self.pluralize(subType)] = hydrated;
           delete obj[k];
app/assets/javascripts/discourse/adapters/rest.js.es6 (1)

22-22: replace('_', '-') only replaces the first underscore.

The current implementation only replaces the first underscore occurrence. While this works for embeddable_hostembeddable-host, it would fail for types with multiple underscores (e.g., some_admin_modelsome-admin_model).

♻️ Proposed fix: replace all underscores
-    if (ADMIN_MODELS.indexOf(type.replace('_', '-')) !== -1) { return "/admin/"; }
+    if (ADMIN_MODELS.indexOf(type.replace(/_/g, '-')) !== -1) { return "/admin/"; }
spec/controllers/admin/embeddable_hosts_controller_spec.rb (1)

3-7: Test coverage is minimal - only inheritance is tested.

The spec only verifies that EmbeddableHostsController inherits from AdminController. Consider adding tests for the controller actions (create, update, destroy) to ensure proper authorization and behavior.

Do you want me to help generate test cases for the controller actions?

spec/controllers/admin/embedding_controller_spec.rb (1)

3-9: Remove extra empty lines per RuboCop conventions.

The static analysis flagged extra empty lines at block body beginning (line 4) and end (line 8).

♻️ Proposed fix
 describe Admin::EmbeddingController do
-
   it "is a subclass of AdminController" do
     expect(Admin::EmbeddingController < Admin::AdminController).to eq(true)
   end
-
 end

Note: The test coverage is minimal—only verifying class inheritance. Consider adding tests for the show and update actions mentioned in the AI summary to ensure proper functionality and authorization checks.

Would you like me to help generate additional test cases for the controller actions?

spec/models/embeddable_host_spec.rb (2)

3-40: Minor style issues flagged by RuboCop.

The test logic and coverage are good. However, RuboCop has flagged extra empty lines at the block body boundaries (lines 4-5, 37-38, 39-40).

🧹 Proposed fix for style consistency
 describe EmbeddableHost do
-
   it "trims http" do
     end
-
   end
-
 end

26-30: Consider a more descriptive test name.

The test name "works as expected" is vague. Consider something like "allows HTTP and HTTPS for registered host and rejects unregistered hosts" to improve readability.

app/assets/javascripts/admin/controllers/admin-embedding.js.es6 (1)

5-7: Consider adding user feedback for save operation.

The saveChanges action calls update({}) but doesn't handle success/failure responses. Users won't know if the save succeeded or failed.

Proposed improvement
     saveChanges() {
-      this.get('embedding').update({});
+      this.get('embedding').update({}).then(() => {
+        // Show success notification
+      }).catch((error) => {
+        // Handle error
+      });
     },
app/controllers/admin/embedding_controller.rb (1)

3-3: Consider using before_action instead of before_filter.

before_filter is deprecated in Rails 4.x. While it still works, before_action is the preferred method name.

Proposed change
-  before_filter :ensure_logged_in, :ensure_staff, :fetch_embedding
+  before_action :ensure_logged_in, :ensure_staff, :fetch_embedding
app/controllers/admin/embeddable_hosts_controller.rb (1)

22-32: Consider using find_by instead of where(...).first.

The idiomatic Rails approach is to use find_by(id: params[:id]) which is cleaner and has the same behavior.

Also, consider using strong parameters for safer param handling.

Proposed refactor for update/destroy
   def update
-    host = EmbeddableHost.where(id: params[:id]).first
+    host = EmbeddableHost.find_by(id: params[:id])
+    return render_json_error(I18n.t('not_found')) unless host
     save_host(host)
   end

   def destroy
-    host = EmbeddableHost.where(id: params[:id]).first
+    host = EmbeddableHost.find_by(id: params[:id])
+    return render_json_error(I18n.t('not_found')) unless host
     host.destroy
     render json: success_json
   end
spec/fabricators/category_fabricator.rb (1)

1-4: File naming inconsistency: fabricator doesn't match filename.

This file is named category_fabricator.rb but defines Fabricator(:embeddable_host). According to the AI summary, the category fabricators were moved to embeddable_host_fabricator.rb, suggesting the content and filename may have been swapped. This could cause confusion when developers look for fabricators by convention.

Consider either:

  1. Renaming this file to match its content, or
  2. Moving the embeddable_host fabricator to embeddable_host_fabricator.rb and keeping category fabricators here.
app/serializers/embeddable_host_serializer.rb (1)

4-14: Redundant method definitions.

The explicit id, host, and category_id methods are unnecessary. ActiveModelSerializers automatically delegates declared attributes to the underlying object. These methods can be removed without changing behavior.

Suggested simplification
 class EmbeddableHostSerializer < ApplicationSerializer
   attributes :id, :host, :category_id
-
-  def id
-    object.id
-  end
-
-  def host
-    object.host
-  end
-
-  def category_id
-    object.category_id
-  end
 end
spec/fabricators/embeddable_host_fabricator.rb (1)

1-27: File naming inconsistency: contains category fabricators, not embeddable_host.

This file is named embeddable_host_fabricator.rb but defines category-related fabricators (category, diff_category, happy_category, private_category). The embeddable_host fabricator is in category_fabricator.rb. The file contents appear to be swapped.

app/assets/javascripts/admin/components/embeddable-host.js.es6 (2)

43-51: sendAction is deprecated; prefer closure actions.

sendAction is deprecated in Ember. The component should accept a closure action (e.g., deleteHost) and invoke it directly. This also improves clarity and type safety.

Suggested approach
     delete() {
       bootbox.confirm(I18n.t('admin.embedding.confirm_delete'), (result) => {
         if (result) {
           this.get('host').destroyRecord().then(() => {
-            this.sendAction('deleteHost', this.get('host'));
+            this.deleteHost(this.get('host'));
           });
         }
       });
     },

Then in the template, pass the action as: deleteHost=(action "removeHost")


13-17: Replace deprecated this.$() with native DOM APIs.

this.$() is deprecated in modern Ember. Use this.element.querySelector() instead:

_focusOnInput() {
  Ember.run.schedule('afterRender', () => { this.element.querySelector('.host-name').focus(); });
}

Alternatively, use the {{did-insert}} modifier in the template to simplify DOM access.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 913c3d6 and d1c6918.

📒 Files selected for processing (36)
  • app/assets/javascripts/admin/adapters/embedding.js.es6
  • app/assets/javascripts/admin/components/embeddable-host.js.es6
  • app/assets/javascripts/admin/controllers/admin-embedding.js.es6
  • app/assets/javascripts/admin/routes/admin-embedding.js.es6
  • app/assets/javascripts/admin/routes/admin-route-map.js.es6
  • app/assets/javascripts/admin/templates/components/embeddable-host.hbs
  • app/assets/javascripts/admin/templates/customize.hbs
  • app/assets/javascripts/admin/templates/embedding.hbs
  • app/assets/javascripts/discourse/adapters/rest.js.es6
  • app/assets/javascripts/discourse/models/store.js.es6
  • app/controllers/admin/embeddable_hosts_controller.rb
  • app/controllers/admin/embedding_controller.rb
  • app/controllers/embed_controller.rb
  • app/models/embeddable_host.rb
  • app/models/site_setting.rb
  • app/models/topic.rb
  • app/models/topic_embed.rb
  • app/serializers/embeddable_host_serializer.rb
  • app/serializers/embedding_serializer.rb
  • config/locales/client.en.yml
  • config/locales/server.en.yml
  • config/routes.rb
  • config/site_settings.yml
  • db/migrate/20150818190757_create_embeddable_hosts.rb
  • lib/topic_retriever.rb
  • spec/controllers/admin/embeddable_hosts_controller_spec.rb
  • spec/controllers/admin/embedding_controller_spec.rb
  • spec/controllers/embed_controller_spec.rb
  • spec/fabricators/category_fabricator.rb
  • spec/fabricators/embeddable_host_fabricator.rb
  • spec/models/embeddable_host_spec.rb
  • spec/models/site_setting_spec.rb
  • spec/models/topic_embed_spec.rb
  • spec/models/topic_spec.rb
  • test/javascripts/helpers/create-pretender.js.es6
  • test/javascripts/models/store-test.js.es6
💤 Files with no reviewable changes (4)
  • config/site_settings.yml
  • config/locales/server.en.yml
  • app/models/site_setting.rb
  • spec/models/site_setting_spec.rb
🧰 Additional context used
🧬 Code graph analysis (11)
lib/topic_retriever.rb (1)
app/models/embeddable_host.rb (1)
  • host_allowed? (20-22)
app/controllers/embed_controller.rb (1)
app/models/embeddable_host.rb (1)
  • host_allowed? (20-22)
app/serializers/embedding_serializer.rb (2)
app/serializers/embeddable_host_serializer.rb (2)
  • attributes (1-15)
  • id (4-6)
app/serializers/about_serializer.rb (1)
  • has_many (1-15)
spec/models/topic_spec.rb (1)
app/models/topic.rb (1)
  • expandable_first_post? (868-870)
spec/fabricators/category_fabricator.rb (1)
app/serializers/embeddable_host_serializer.rb (1)
  • host (8-10)
db/migrate/20150818190757_create_embeddable_hosts.rb (1)
app/serializers/embeddable_host_serializer.rb (1)
  • category_id (12-14)
app/controllers/admin/embeddable_hosts_controller.rb (3)
app/controllers/admin/embedding_controller.rb (2)
  • before_filter (1-21)
  • update (9-11)
app/serializers/embeddable_host_serializer.rb (2)
  • host (8-10)
  • category_id (12-14)
app/controllers/application_controller.rb (3)
  • success_json (362-364)
  • render_serialized (238-240)
  • render_json_error (357-360)
app/models/topic_embed.rb (1)
app/models/embeddable_host.rb (1)
  • record_for_host (10-18)
app/controllers/admin/embedding_controller.rb (2)
app/controllers/admin/embeddable_hosts_controller.rb (2)
  • before_filter (1-34)
  • update (9-12)
app/controllers/application_controller.rb (1)
  • render_serialized (238-240)
app/serializers/embeddable_host_serializer.rb (1)
app/serializers/embedding_serializer.rb (2)
  • attributes (1-8)
  • id (5-7)
spec/models/embeddable_host_spec.rb (2)
app/serializers/embeddable_host_serializer.rb (1)
  • host (8-10)
app/models/embeddable_host.rb (1)
  • host_allowed? (20-22)
🪛 RuboCop (1.82.1)
app/models/embeddable_host.rb

[convention] 11-11: Avoid using rescue in its modifier form.

(Style/RescueModifier)

spec/controllers/admin/embeddable_hosts_controller_spec.rb

[convention] 4-5: Extra empty line detected at block body beginning.

(Layout/EmptyLinesAroundBlockBody)


[convention] 8-9: Extra empty line detected at block body end.

(Layout/EmptyLinesAroundBlockBody)

spec/controllers/admin/embedding_controller_spec.rb

[convention] 4-5: Extra empty line detected at block body beginning.

(Layout/EmptyLinesAroundBlockBody)


[convention] 8-9: Extra empty line detected at block body end.

(Layout/EmptyLinesAroundBlockBody)

db/migrate/20150818190757_create_embeddable_hosts.rb

[convention] 2-32: Assignment Branch Condition size for change is too high. [<7, 22, 8> 24.43/23]

(Metrics/AbcSize)

spec/models/embeddable_host_spec.rb

[convention] 4-5: Extra empty line detected at block body beginning.

(Layout/EmptyLinesAroundBlockBody)


[convention] 37-38: Extra empty line detected at block body end.

(Layout/EmptyLinesAroundBlockBody)


[convention] 39-40: Extra empty line detected at block body end.

(Layout/EmptyLinesAroundBlockBody)

🔇 Additional comments (29)
test/javascripts/helpers/create-pretender.js.es6 (2)

42-51: LGTM! Test fixture data properly extended with color relationships.

The fruits now include color_ids arrays referencing the new colors dataset. The data is consistent: fruit 1 (apple) has colors [1,2] (Red, Green), fruit 2 (banana) has [3] (Yellow), and fruit 3 (grape) has [2] (Green).


226-233: LGTM! API responses correctly include the colors collection.

Both the single fruit (/fruits/:id) and collection (/fruits) endpoints now return the colors array alongside fruits and farmers, supporting the store's embedded relationship hydration.

test/javascripts/models/store-test.js.es6 (1)

123-135: LGTM! findAll embedded test correctly validates colors on the first fruit.

The test correctly asserts that fruits.objectAt(0) (apple, id 1) has 2 colors with ids 1 and 2, which matches the fixture data.

app/assets/javascripts/discourse/models/store.js.es6 (1)

189-211: LGTM! Hydration logic correctly extended for plural ID arrays.

The implementation properly distinguishes between singular _id and plural _ids suffixes, hydrating single objects vs arrays accordingly. This enables proper embedded relationship resolution for the new embeddable hosts feature.

app/assets/javascripts/discourse/adapters/rest.js.es6 (1)

1-1: LGTM! embeddable-host correctly added to admin models.

This ensures that requests for embeddable hosts are routed through the /admin/ base path.

app/models/topic.rb (1)

868-870: LGTM! Simplified predicate aligns with the new EmbeddableHost model.

Removing the embeddable_hosts presence check is appropriate since the embedding configuration has moved from site settings to the database-backed EmbeddableHost model. The remaining conditions (embed_truncate? and has_topic_embed?) are sufficient to determine if the first post is expandable.

spec/models/topic_embed_spec.rb (2)

37-38: Good coverage for category assignment.

This assertion validates the core functionality where topics created via embedding are assigned to the category configured on the matching EmbeddableHost record.


15-15: ✓ Fabricator correctly set up with matching host.

The embeddable_host fabricator (spec/fabricators/embeddable_host_fabricator.rb) correctly defines host "eviltrout.com", which matches the test URL. The let! ensures the embeddable_host is created before the test runs, and EmbeddableHost.record_for_host(url) will properly find the match for category assignment.

lib/topic_retriever.rb (1)

15-17: LGTM! Clean migration to database-backed host validation.

The change correctly delegates host validation to EmbeddableHost.host_allowed?, which internally uses record_for_host(host).present? per the relevant code snippet. This aligns with the PR's migration from site settings to the database-backed EmbeddableHost model.

app/assets/javascripts/admin/adapters/embedding.js.es6 (1)

1-7: LGTM!

The adapter follows Discourse's standard pattern for custom REST adapters, cleanly extending RestAdapter and overriding pathFor() to point to the embedding endpoint. The server-side routes at /admin/customize/embedding are properly defined with both GET and PUT methods.

app/assets/javascripts/admin/templates/customize.hbs (1)

8-8: LGTM!

The navigation item follows the established pattern and integrates cleanly with the existing admin navigation structure. The i18n key admin.embedding.title is properly defined in the locale files, and the adminEmbedding route is configured correctly.

app/models/topic_embed.rb (1)

36-43: LGTM! Host-based category assignment is correctly implemented.

The migration from static SiteSetting.embed_category to dynamic EmbeddableHost.record_for_host(url) lookup is well done. Using eh.try(:category_id) safely handles the case when record_for_host returns false (no matching host) by passing nil to PostCreator, which will use the default category behavior.

config/routes.rb (2)

138-139: LGTM! Routes follow existing conventions.

The embedding routes are correctly placed within the admin namespace with AdminConstraint.new, consistent with other customize-related routes in this file.


153-153: LGTM! RESTful resource declaration is appropriate.

The embeddable_hosts resource correctly inherits the admin constraint, providing standard CRUD operations for managing embeddable hosts.

config/locales/client.en.yml (1)

2494-2501: LGTM! Locale entries are well-structured.

The new embedding translation keys are appropriately named and follow the existing conventions in this file. The strings support the new admin embedding UI functionality.

app/controllers/embed_controller.rb (1)

58-67: LGTM! Access control correctly migrated to EmbeddableHost model.

The change from SiteSetting-based host validation to EmbeddableHost.host_allowed?(request.referer) properly integrates with the new database-backed embeddable host management. The host_allowed? method handles edge cases like nil or invalid referers gracefully by returning false, which triggers the appropriate InvalidAccess exception.

app/assets/javascripts/admin/templates/components/embeddable-host.hbs (1)

1-19: LGTM! Well-structured component template with clear editing/view modes.

The template correctly implements the two-state UI pattern for editing embeddable hosts. The use of buffered.host for the input allows for cancel functionality without mutating the original record, and the button states (cantSave, host.isSaving) provide appropriate feedback. The category-chooser binding pattern matches existing usage in split-topic.hbs and bulk_change_category.hbs, confirming it's the correct approach for binding primitive ID values to the component.

app/assets/javascripts/admin/templates/embedding.hbs (1)

1-15: LGTM!

The template structure is correct. The conditional rendering for the hosts table and the always-visible "Add Host" button provide good UX. The component integration with embeddable-host and the action bindings (deleteHost, addHost) align with the controller defined in admin-embedding.js.es6.

Minor note: The inline style attributes on lines 4-6 could be extracted to CSS classes for better maintainability, but this is a minor preference.

app/assets/javascripts/admin/routes/admin-route-map.js.es6 (1)

30-30: LGTM!

The new adminEmbedding resource follows the established naming convention and is appropriately placed within the adminCustomize route group alongside related resources.

spec/controllers/embed_controller_spec.rb (2)

21-21: LGTM!

Good migration from SiteSetting to the database-backed EmbeddableHost model using fabricators.


66-98: Good coverage of multiple hosts and path normalization.

The multi-host context properly tests:

  • Multiple allowed hosts
  • Path stripping during host normalization (line 87 uses a different path than line 70, correctly validating normalization behavior)
  • Rejection of unregistered hosts
app/assets/javascripts/admin/routes/admin-embedding.js.es6 (1)

1-9: LGTM!

The route correctly fetches the embedding model and assigns it to the controller. The setupController properly populates controller.embedding which aligns with the template's {{#if embedding.embeddable_hosts}} usage. The global Ember.Route.extend pattern is consistent throughout the admin routes in this codebase.

app/controllers/admin/embedding_controller.rb (1)

15-20: LGTM!

The fetch_embedding method appropriately constructs an embedding object with a fixed ID and ordered embeddable hosts for serialization.

app/serializers/embedding_serializer.rb (1)

1-8: LGTM!

The serializer correctly exposes the embedding ID and establishes the has_many relationship with embeddable hosts using ID embedding, which aligns with the REST serializer pattern used in this codebase.

spec/models/topic_spec.rb (2)

1241-1241: LGTM!

Removing the unused topic variable assignment is a good cleanup.


1399-1427: No issues found. The test expectations align correctly with the implementation. When no embeddable host exists, has_topic_embed? returns false (no TopicEmbed record for a newly built topic), causing expandable_first_post? to correctly return false without requiring an explicit EmbeddableHost presence check.

app/controllers/admin/embeddable_hosts_controller.rb (1)

5-7: LGTM!

The create action correctly instantiates a new EmbeddableHost and delegates to save_host.

app/models/embeddable_host.rb (1)

20-22: LGTM!

The host_allowed? method correctly delegates to record_for_host and uses .present? to handle the result.

app/assets/javascripts/admin/components/embeddable-host.js.es6 (1)

30-41: LGTM!

The save action properly validates via cantSave, extracts buffered properties, persists to server, updates the local category reference, and handles errors with popupAjaxError.

Comment on lines +46 to +48
this.get('host').destroyRecord().then(() => {
this.sendAction('deleteHost', this.get('host'));
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing error handling for destroyRecord.

Unlike the save action which uses .catch(popupAjaxError), the delete action doesn't handle failures from destroyRecord(). If the server returns an error, the user won't see any feedback.

Suggested fix
           this.get('host').destroyRecord().then(() => {
             this.sendAction('deleteHost', this.get('host'));
-          });
+          }).catch(popupAjaxError);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
this.get('host').destroyRecord().then(() => {
this.sendAction('deleteHost', this.get('host'));
});
this.get('host').destroyRecord().then(() => {
this.sendAction('deleteHost', this.get('host'));
}).catch(popupAjaxError);
🤖 Prompt for AI Agents
In @app/assets/javascripts/admin/components/embeddable-host.js.es6 around lines
46 - 48, The delete action currently calls this.get('host').destroyRecord()
without error handling; append a .catch(popupAjaxError) to the promise chain
(matching the save action pattern) so server errors surface to the user, and
ensure the popupAjaxError helper is imported/available in this component
(referencing destroyRecord and popupAjaxError and the existing
sendAction('deleteHost', this.get('host')) sequence).

Comment on lines +14 to +16
deleteHost(host) {
this.get('embedding.embeddable_hosts').removeObject(host);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

deleteHost does not persist deletion to the server.

The action only removes the host from the local array but doesn't delete it from the database. If the host was previously saved, it will reappear after page refresh.

Proposed fix
     deleteHost(host) {
+      if (host.get('id')) {
+        host.destroyRecord();
+      }
       this.get('embedding.embeddable_hosts').removeObject(host);
     }
🤖 Prompt for AI Agents
In @app/assets/javascripts/admin/controllers/admin-embedding.js.es6 around lines
14 - 16, The deleteHost action only removes the host from the local
embedding.embeddable_hosts array and does not persist to the server; update
deleteHost to check the record state (e.g., host.get('isNew') or host.get('id'))
and for persisted hosts call host.destroyRecord() (or host.deleteRecord()
followed by host.save()) and only remove it from embedding.embeddable_hosts
after the destroy/save succeeds (handle promise .then/.catch to update the array
and surface errors); for new/unsaved hosts simply removeObject(host) as before.

Comment on lines +9 to +12
def update
host = EmbeddableHost.where(id: params[:id]).first
save_host(host)
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing nil check for host in update action.

If params[:id] doesn't match any record, host will be nil, causing a NoMethodError in save_host when accessing host.host=.

Proposed fix
   def update
     host = EmbeddableHost.where(id: params[:id]).first
+    return render_json_error(I18n.t('not_found')) unless host
     save_host(host)
   end
🤖 Prompt for AI Agents
In @app/controllers/admin/embeddable_hosts_controller.rb around lines 9 - 12,
The update action calls save_host with host = EmbeddableHost.where(id:
params[:id]).first but doesn't handle the case when host is nil; add a nil check
in the update method to return early and respond appropriately (e.g., render
head :not_found or redirect with a flash error) when host is not found, and only
call save_host(host) when host is present; reference the update action and
save_host method to implement this guard.

Comment on lines +14 to +18
def destroy
host = EmbeddableHost.where(id: params[:id]).first
host.destroy
render json: success_json
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing nil check for host in destroy action.

If the host is not found, calling destroy on nil will raise a NoMethodError.

Proposed fix
   def destroy
     host = EmbeddableHost.where(id: params[:id]).first
+    return render_json_error(I18n.t('not_found')) unless host
     host.destroy
     render json: success_json
   end
🤖 Prompt for AI Agents
In @app/controllers/admin/embeddable_hosts_controller.rb around lines 14 - 18,
The destroy action calls host.destroy without handling a missing record; update
the EmbeddableHostsController#destroy to fetch the record via
EmbeddableHost.where(id: params[:id]).first (or find_by) and return an
appropriate error/404 response when host is nil instead of calling destroy on
nil, otherwise call host.destroy and render success_json; ensure you reference
the same symbols (destroy, EmbeddableHost, params[:id], success_json) when
adding the nil check and response.

Comment on lines +9 to +11
def update
render_serialized(@embedding, EmbeddingSerializer, root: 'embedding', rest_serializer: true)
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

update action does not perform any actual update.

The action renders the same serialized data as show without processing any input parameters or persisting changes. This appears to be incomplete implementation.

Comment on lines +10 to +18
def self.record_for_host(host)
uri = URI(host) rescue nil
return false unless uri.present?

host = uri.host
return false unless host.present?

where("lower(host) = ?", host).first
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Inconsistent return types and rescue modifier style.

  1. The method returns false on failure but an EmbeddableHost instance (or nil) on success. This mixed return type can lead to subtle bugs since host_allowed? calls .present? which works, but callers expecting a record may not handle false correctly.

  2. RuboCop flags the inline rescue nil as it silently swallows all exceptions, making debugging difficult.

Suggested fix
   def self.record_for_host(host)
-    uri = URI(host) rescue nil
-    return false unless uri.present?
+    begin
+      uri = URI(host)
+    rescue URI::InvalidURIError
+      return nil
+    end
+    return nil unless uri.present?
 
-    host = uri.host
-    return false unless host.present?
+    parsed_host = uri.host
+    return nil unless parsed_host.present?
 
-    where("lower(host) = ?", host).first
+    where("lower(host) = ?", parsed_host).first
   end
🧰 Tools
🪛 RuboCop (1.82.1)

[convention] 11-11: Avoid using rescue in its modifier form.

(Style/RescueModifier)

🤖 Prompt for AI Agents
In @app/models/embeddable_host.rb around lines 10 - 18, The method
record_for_host currently uses an inline rescue modifier and returns false on
failure which mixes return types; change it to return nil on failure and replace
the `rescue nil` with an explicit begin/rescue that only rescues
URI::InvalidURIError (or StandardError if necessary) so exceptions aren't
silently swallowed; extract the hostname via URI.parse(host).host (or check host
presence first), normalize it (e.g., downcase) and then perform the query using
where(...).first; ensure callers (e.g., host_allowed?) expect nil rather than
false.

Comment on lines +24 to +26
records.each do |h|
execute "INSERT INTO embeddable_hosts (host, category_id, created_at, updated_at) VALUES ('#{h}', #{category_id}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

SQL injection vulnerability: host value is directly interpolated.

The host value h from site_settings is directly interpolated into the SQL string without sanitization. While this is a migration operating on internal data, it's still a security risk if the embeddable_hosts setting ever contained malicious content.

🔒 Proposed fix: use parameterized query
           records.each do |h|
-            execute "INSERT INTO embeddable_hosts (host, category_id, created_at, updated_at) VALUES ('#{h}', #{category_id}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
+            execute sanitize_sql_array(["INSERT INTO embeddable_hosts (host, category_id, created_at, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)", h, category_id])
           end

Alternatively, use ActiveRecord's quote method:

execute "INSERT INTO embeddable_hosts (host, category_id, created_at, updated_at) VALUES (#{quote(h)}, #{category_id}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
🤖 Prompt for AI Agents
In @db/migrate/20150818190757_create_embeddable_hosts.rb around lines 24 - 26,
The migration directly interpolates the host string inside the raw SQL in the
records.each do |h| loop (the execute call), exposing an SQL injection risk;
change the insert to use a parameterized/quoted value instead of string
interpolation — e.g., use ActiveRecord's quote(h) or bind parameters when
building the INSERT in the execute call (keep the same embeddable_hosts columns
and category_id variable) so the host value is properly escaped before executing
the SQL.

Comment on lines +23 to +26
after_build do |cat, transients|
cat.update!(read_restricted: true)
cat.category_groups.build(group_id: transients[:group].id, permission_type: CategoryGroup.permission_types[:full])
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid update! in after_build callback.

Using update! inside after_build forces an immediate database save before the fabrication completes. This can cause issues if the record isn't fully built yet. Use direct attribute assignment instead, and let Fabrication handle persistence.

Suggested fix
   after_build do |cat, transients|
-    cat.update!(read_restricted: true)
+    cat.read_restricted = true
     cat.category_groups.build(group_id: transients[:group].id, permission_type: CategoryGroup.permission_types[:full])
   end
🤖 Prompt for AI Agents
In @spec/fabricators/embeddable_host_fabricator.rb around lines 23 - 26, The
after_build block currently calls cat.update! which performs an immediate DB
save; instead assign the attribute directly (set cat.read_restricted = true) and
keep building the association via cat.category_groups.build(group_id:
transients[:group].id, permission_type: CategoryGroup.permission_types[:full])
so Fabrication handles persistence; remove the update! call and use direct
attribute assignment inside the after_build callback.

Comment thread spec/models/topic_spec.rb
SiteSetting.embed_truncate = false
expect(topic.expandable_first_post?).to eq(false)
end
describe 'with an emeddable host' do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typo: "emeddable" should be "embeddable".

Proposed fix
-    describe 'with an emeddable host' do
+    describe 'with an embeddable host' do
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
describe 'with an emeddable host' do
describe 'with an embeddable host' do
🤖 Prompt for AI Agents
In @spec/models/topic_spec.rb at line 1407, The spec description contains a
typo: change the string literal in the spec block from "with an emeddable host"
to "with an embeddable host" by updating the describe block that currently reads
'with an emeddable host' to the corrected 'with an embeddable host' (leave the
surrounding describe ... do/end intact).

Comment on lines +109 to 121
test('find embedded', function(assert) {
const store = createStore();
return store.find('fruit', 1).then(function(f) {
ok(f.get('farmer'), 'it has the embedded object');
ok(f.get('category'), 'categories are found automatically');
return store.find('fruit', 2).then(function(f) {
assert.ok(f.get('farmer'), 'it has the embedded object');

const fruitCols = f.get('colors');
assert.equal(fruitCols.length, 2);
assert.equal(fruitCols[0].get('id'), 1);
assert.equal(fruitCols[1].get('id'), 2);

assert.ok(f.get('category'), 'categories are found automatically');
});
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Test data mismatch: fruit id 2 does not have color_ids [1, 2].

The test fetches fruit with id: 2 (banana), but asserts that it has 2 colors with ids 1 and 2. According to the fixture data in create-pretender.js.es6:

  • Fruit id 1 (apple): color_ids: [1, 2]
  • Fruit id 2 (banana): color_ids: [3]

The assertions on lines 115-117 will fail because banana only has one color (Yellow, id 3).

🐛 Proposed fix: use fruit id 1 or fix assertions

Option 1: Change to fruit id 1 (apple):

-  return store.find('fruit', 2).then(function(f) {
+  return store.find('fruit', 1).then(function(f) {

Option 2: Fix assertions for fruit id 2 (banana):

     const fruitCols = f.get('colors');
-    assert.equal(fruitCols.length, 2);
-    assert.equal(fruitCols[0].get('id'), 1);
-    assert.equal(fruitCols[1].get('id'), 2);
+    assert.equal(fruitCols.length, 1);
+    assert.equal(fruitCols[0].get('id'), 3);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('find embedded', function(assert) {
const store = createStore();
return store.find('fruit', 1).then(function(f) {
ok(f.get('farmer'), 'it has the embedded object');
ok(f.get('category'), 'categories are found automatically');
return store.find('fruit', 2).then(function(f) {
assert.ok(f.get('farmer'), 'it has the embedded object');
const fruitCols = f.get('colors');
assert.equal(fruitCols.length, 2);
assert.equal(fruitCols[0].get('id'), 1);
assert.equal(fruitCols[1].get('id'), 2);
assert.ok(f.get('category'), 'categories are found automatically');
});
});
test('find embedded', function(assert) {
const store = createStore();
return store.find('fruit', 1).then(function(f) {
assert.ok(f.get('farmer'), 'it has the embedded object');
const fruitCols = f.get('colors');
assert.equal(fruitCols.length, 2);
assert.equal(fruitCols[0].get('id'), 1);
assert.equal(fruitCols[1].get('id'), 2);
assert.ok(f.get('category'), 'categories are found automatically');
});
});
Suggested change
test('find embedded', function(assert) {
const store = createStore();
return store.find('fruit', 1).then(function(f) {
ok(f.get('farmer'), 'it has the embedded object');
ok(f.get('category'), 'categories are found automatically');
return store.find('fruit', 2).then(function(f) {
assert.ok(f.get('farmer'), 'it has the embedded object');
const fruitCols = f.get('colors');
assert.equal(fruitCols.length, 2);
assert.equal(fruitCols[0].get('id'), 1);
assert.equal(fruitCols[1].get('id'), 2);
assert.ok(f.get('category'), 'categories are found automatically');
});
});
test('find embedded', function(assert) {
const store = createStore();
return store.find('fruit', 2).then(function(f) {
assert.ok(f.get('farmer'), 'it has the embedded object');
const fruitCols = f.get('colors');
assert.equal(fruitCols.length, 1);
assert.equal(fruitCols[0].get('id'), 3);
assert.ok(f.get('category'), 'categories are found automatically');
});
});
🤖 Prompt for AI Agents
In @test/javascripts/models/store-test.js.es6 around lines 109 - 121, The test
named "find embedded" is asserting colors for fruit id 2 (banana) but fixture
data in create-pretender.js.es6 shows banana has color_ids [3]; update the test
to be consistent by either calling store.find('fruit', 1) to test apple (which
has color_ids [1,2]) or adjust the assertions after store.find('fruit', 2)
(inside the test('find embedded') callback) to expect a single color with id 3
(and length 1) and update the corresponding id checks and messages accordingly;
ensure createStore() usage and the assertions on f.get('colors') are changed to
match the chosen fruit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants