Right way to deal with one-to-many attributes in the same JSON... reflexive relations maybe?

We’re in the home stretch with the glossary app! But I’m having trouble working with a different kind of array than the other terms/letter/term.id and letter/:term routes @dknutsen has so generously helped me with.

Here’s what I’m working with.

Having finished loading up all the individual definitions, getting the terms to load on individual letter pages, and finally feeding them into alphabetical table grids I’m left with the “Disciplines” routes, like this Drilling page on SLB’s site.

There are the steps I took.

  1. Update the router to add category:
Router.map(function() {
  this.route("home", { path: "/" });
  this.route("terms", function() {
    this.route("letter", { path: "/:letter" }, function() {
      this.route("term_id", { path: "/:term_id" });
    });
  });
  this.route("term", function() {
    this.route("letter", { path: "/:letter" });
  });
  this.route("disciplines", function() {
    this.route("category", { path: "/:category" });
  });
});
  1. Add category to the model:
export default DS.Model.extend({
  term: DS.attr("string"),
  letter: DS.attr("string"),
  category: DS.attr(),
  definitions: DS.attr()
});
  1. Add disciplines to mirage.
export default function() {
  this.namespace = "api";
  this.get("/term", function({ terms }, { queryParams }) {
    let { term, letter } = queryParams;
    let results = terms.all();
    if (letter) {
      const match = letter.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    if (term) {
      const match = term.toLowerCase();
      results = results.filter(t => t.term.toLowerCase().includes(match));
    }
    return results;
  });
  this.get("/terms", function({ terms }, { queryParams }) {
    let { term, letter } = queryParams;
    let results = terms.all();
    if (letter) {
      const match = letter.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    if (term) {
      const match = term.toLowerCase();
      results = results.filter(t => t.term.toLowerCase().includes(match));
    }
    return results;
  });
  this.get("/disciplines", function({ terms }, { queryParams }) {
    let { category } = queryParams;
    let results = terms.all();
    if (category) {
      const match = category.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    return results;
  });
this.get("/terms/:id");
}
  1. Add the model params to disciplines/category/route.js.
import Route from '@ember/routing/route';

export default Route.extend({
  model(params) {
    return this.store.query('term', { category: params.category })
  }
});

This is where things started going sideways. Some terms only have one category and are very easy to work with, like this:

    {
      "id": "api_unit",
      "term": "API unit",
      "letter": "a",
      "definitions": [
        {
          "speech_type": "1. n.",
          "category": "Formation Evaluation",
          "definition": "The unit of radioactivity used for natural gamma ray logs. This unit is based on an artificially radioactive concrete block at the University of Houston, Texas, USA, that is defined to have a radioactivity of 200 American Petroleum Institute (<a class=\"text-blue-light no-underline\" href=\"/terms/a/api\">API</a>) units. This was chosen because it was considered to be twice the radioactivity of a typical <a class=\"text-blue-light no-underline\" href=\"/terms/s/shale\">shale</a>. The formation is the primary standard for calibrating gamma ray logs. However, even when properly calibrated, different gamma ray tools will not necessarily have identical readings downhole because their detectors can have different <a class=\"text-blue-light no-underline\" href=\"/terms/s/spectral\">spectral</a> sensitivities. They will read the same only if the downhole formation contains the same proportions of <a class=\"text-blue-light no-underline\" href=\"/terms/t/thorium\">thorium</a>, <a class=\"text-blue-light no-underline\" href=\"/terms/p/potassium\">potassium</a> and <a class=\"text-blue-light no-underline\" href=\"/terms/u/uranium\">uranium</a> as the Houston standard. For example, <a class=\"text-blue-light no-underline\" href=\"/terms/l/logging_while_drilling\">logging while drilling</a> (LWD) tools have thicker housings than <a class=\"text-blue-light no-underline\" href=\"/terms/w/wireline\">wireline</a> tools, causing a different spectral response to the three sources of radioactivity, and therefore a different total gamma ray reading in some formations.\n\nThe nuclear <a class=\"text-blue-light no-underline\" href=\"/terms/w/well_log\">well log</a> <a class=\"text-blue-light no-underline\" href=\"/terms/c/calibration\">calibration</a> facility at the University of Houston, known as the API pits, was opened in 1959 for the calibration of natural gamma ray and neutron logs. A facility for calibrating <a class=\"text-blue-light no-underline\" href=\"/terms/n/natural_gamma_ray_spectroscopy\">natural gamma ray spectroscopy</a> logs was added later.",
          "see": [
            {
              "title": "neutron log",
              "link": "/terms/n/neutron-log"
            }
          ],
          "more_details": [

          ],
          "synonyms": [

          ],
          "antonyms": [

          ]
        }
      ]
    },

This makes it easy to do something like…

{{#each model.definitions as |definition|}}
{{definition.speech_type}} [{{definition.category}}]
{{definition.definition}}
{{/each}}
(...)

… and get the correct response from the store.

But it turns out terms with one category are the exception, not the rule. Most have several categories, like this:

  {
    "id": "survey",
    "term": "survey",
    "letter": "s",
    "definitions": [
        {
            "speech_type": "1. n.",
            "category": "Geophysics",
            "definition": "<div class=\"definition-text\">\n A data set measured and recorded with reference to a particular area of the Earth's surface, such as a\n <a href=\"/en/Terms/s/seismic_survey.aspx\">\n  seismic survey\n </a>\n .\n</div>\n",
            "see": [
                {
                    "title": "accelerometer",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/a/accelerometer.aspx"
                },
                {
                    "title": "base station",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/base_station.aspx"
                },
                {
                    "title": "baseline",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/baseline.aspx"
                },
                {
                    "title": "baseline",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/baseline.aspx"
                },
                {
                    "title": "benchmark",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/benchmark.aspx"
                },
                {
                    "title": "benchmark",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/benchmark.aspx"
                },
                {
                    "title": "cultural noise",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/c/cultural_noise.aspx"
                },
                {
                    "title": "depth point",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/depth_point.aspx"
                },
                {
                    "title": "drift",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/drift.aspx"
                },
                {
                    "title": "electromagnetic method",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/e/electromagnetic_method.aspx"
                },
                {
                    "title": "free-air correction",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/f/free-air_correction.aspx"
                },
                {
                    "title": "gravity",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/g/gravity.aspx"
                },
                {
                    "title": "gravity survey",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/g/gravity_survey.aspx"
                },
                {
                    "title": "magnetics",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/m/magnetics.aspx"
                },
                {
                    "title": "monument",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/m/monument.aspx"
                },
                {
                    "title": "perpendicular offset",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/p/perpendicular_offset.aspx"
                },
                {
                    "title": "salt proximity survey",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/s/salt_proximity_survey.aspx"
                },
                {
                    "title": "seismic",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/s/seismic.aspx"
                },
                {
                    "title": "side-scan sonar",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/s/side-scan_sonar.aspx"
                },
                {
                    "title": "telluric-current method",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/t/telluric-current_method.aspx"
                }
            ],
            "more_details": [],
            "synonyms": [],
            "antonyms": [],
            "image": {
                "src": "https://www.glossary.oilfield.slb.com/en/Terms/s/en/~/media/PublicMedia/OGL98173.ashx",
                "caption": "A large survey might encompass deep marine, shallow marine, very shallow water and land areas, each of which requires a different acquisition technique."
            }
        },
        {
            "speech_type": "2. vb.",
            "category": "Geophysics",
            "definition": "<div class=\"definition-text\">\n To measure and record data according to location on the Earth's surface. In\n <a href=\"/en/Terms/g/geophysics.aspx\">\n  geophysics\n </a>\n , the term is used in the context of acquiring\n <a href=\"/en/Terms/s/seismic.aspx\">\n  seismic\n </a>\n , electrical,\n <a href=\"/en/Terms/g/gravity.aspx\">\n  gravity\n </a>\n or magnetic data to evaluate the subsurface.\n</div>\n",
            "see": [
                {
                    "title": "acquisition",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/a/acquisition.aspx"
                }
            ],
            "more_details": [],
            "synonyms": [],
            "antonyms": []
        },
        {
            "speech_type": "3. n.",
            "category": "Drilling",
            "definition": "<div class=\"definition-text\">\n A completed measurement of the inclination and azimuth of a location in a well (typically the total depth at the time of measurement). In both directional and straight holes, the position of the well must be known with reasonable\n <a href=\"/en/Terms/a/accuracy.aspx\">\n  accuracy\n </a>\n to ensure the correct wellbore path and to know its position in the event a relief well must be drilled. The measurements themselves include inclination from vertical, and the azimuth (or compass\n <a href=\"/en/Terms/h/heading.aspx\">\n  heading\n </a>\n ) of the wellbore if the direction of the path is critical. These measurements are made at discrete points in the well, and the approximate path of the wellbore computed from the discrete points. Measurement devices range from simple pendulum-like devices to complex electronic accelerometers and gyroscopes used more often as\n <a href=\"/en/Terms/m/mwd.aspx\">\n  MWD\n </a>\n becomes more popular. In simple pendulum measurements, the position of a freely hanging pendulum relative to a measurement\n <a href=\"/en/Terms/g/grid.aspx\">\n  grid\n </a>\n (attached to the\n <a href=\"/en/Terms/h/housing.aspx\">\n  housing\n </a>\n of the tool and assumed to represent the path of the wellbore) is captured on photographic film. The film is developed and examined when the tool is removed from the wellbore, either on\n <a href=\"/en/Terms/w/wireline.aspx\">\n  wireline\n </a>\n or the next time pipe is tripped out of the hole.\n</div>\n",
            "see": [
                {
                    "title": "azimuth",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/a/azimuth.aspx"
                },
                {
                    "title": "deviation survey",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/deviation_survey.aspx"
                },
                {
                    "title": "directional drilling",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/directional_drilling.aspx"
                },
                {
                    "title": "directional survey",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/directional_survey.aspx"
                },
                {
                    "title": "inclination",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/i/inclination.aspx"
                },
                {
                    "title": "measurements-while-drilling",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/m/measurements-while-drilling.aspx"
                },
                {
                    "title": "total depth",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/t/total_depth.aspx"
                },
                {
                    "title": "tripping pipe",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/t/tripping_pipe.aspx"
                }
            ],
            "more_details": [],
            "synonyms": [],
            "antonyms": []
        },
        {
            "speech_type": "4. n.",
            "category": "Drilling",
            "definition": "<div class=\"definition-text\">\n A precise and legally binding measurement of surface locations, referenced to known\n <a href=\"/en/Terms/b/benchmark.aspx\">\n  benchmark\n </a>\n locations.\n</div>\n",
            "see": [],
            "more_details": [],
            "synonyms": [],
            "antonyms": []
        },
        {
            "speech_type": "5. vb.",
            "category": "Drilling",
            "definition": "<div class=\"definition-text\">\n To make the measurements as in definitions 1 or 2.\n</div>\n",
            "see": [],
            "more_details": [],
            "synonyms": [],
            "antonyms": []
        },
        {
            "speech_type": "6. n.",
            "category": "Formation Evaluation",
            "definition": "<div class=\"definition-text\">\n The measurement versus depth or time, or both, of one or more physical quantities in or around a well. In early years, the term was used more often than log.\n</div>\n",
            "see": [],
            "more_details": [],
            "synonyms": [
                {
                    "title": "log",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/l/log.aspx"
                }
            ],
            "antonyms": [],
            "alternate_forms": "electrical survey"
        },
        {
            "speech_type": "7. vb.",
            "category": "Formation Evaluation",
            "definition": "<div class=\"definition-text\">\n To record a measurement versus depth or time, or both, of one or more physical quantities in or around a well. In early years, the term was used more often than log.\n</div>\n",
            "see": [],
            "more_details": [],
            "synonyms": [
                {
                    "title": "log",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/l/log.aspx"
                }
            ],
            "antonyms": []
        }
    ]
  }

This threw a wrench into simply duplicating the work from the other routes. After thinking it through I decide to switch the name from “category” to “group” and bring it to the top-level of the JSON thinking I could then group.title the way I did with definitions..., which looks like this:

  {
    "id": "survey",
    "term": "survey",
    "letter": "s",
    "group": [
      { "title": "geophysics" },
      { "title": "drilling" },
      { "title": "formation evaluation" },
    ],
    "definitions": [
        {
            "speech_type": "1. n.",
            "category": "Geophysics",
            "definition": "<div class=\"definition-text\">\n A data set measured and recorded with reference to a particular area of the Earth's surface, such as a\n <a href=\"/en/Terms/s/seismic_survey.aspx\">\n  seismic survey\n </a>\n .\n</div>\n",
            "see": [
                {
                    "title": "accelerometer",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/a/accelerometer.aspx"
                },
                {
                    "title": "base station",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/base_station.aspx"
                },
                {
                    "title": "baseline",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/baseline.aspx"
                },
                {
                    "title": "baseline",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/baseline.aspx"
                },
                {
                    "title": "benchmark",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/benchmark.aspx"
                },
                {
                    "title": "benchmark",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/b/benchmark.aspx"
                },
                {
                    "title": "cultural noise",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/c/cultural_noise.aspx"
                },
                {
                    "title": "depth point",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/depth_point.aspx"
                },
                {
                    "title": "drift",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/drift.aspx"
                },
                {
                    "title": "electromagnetic method",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/e/electromagnetic_method.aspx"
                },
                {
                    "title": "free-air correction",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/f/free-air_correction.aspx"
                },
                {
                    "title": "gravity",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/g/gravity.aspx"
                },
                {
                    "title": "gravity survey",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/g/gravity_survey.aspx"
                },
                {
                    "title": "magnetics",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/m/magnetics.aspx"
                },
                {
                    "title": "monument",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/m/monument.aspx"
                },
                {
                    "title": "perpendicular offset",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/p/perpendicular_offset.aspx"
                },
                {
                    "title": "salt proximity survey",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/s/salt_proximity_survey.aspx"
                },
                {
                    "title": "seismic",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/s/seismic.aspx"
                },
                {
                    "title": "side-scan sonar",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/s/side-scan_sonar.aspx"
                },
                {
                    "title": "telluric-current method",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/t/telluric-current_method.aspx"
                }
            ],
            "more_details": [],
            "synonyms": [],
            "antonyms": [],
            "image": {
                "src": "https://www.glossary.oilfield.slb.com/en/Terms/s/en/~/media/PublicMedia/OGL98173.ashx",
                "caption": "A large survey might encompass deep marine, shallow marine, very shallow water and land areas, each of which requires a different acquisition technique."
            }
        },
        {
            "speech_type": "2. vb.",
            "category": "Geophysics",
            "definition": "<div class=\"definition-text\">\n To measure and record data according to location on the Earth's surface. In\n <a href=\"/en/Terms/g/geophysics.aspx\">\n  geophysics\n </a>\n , the term is used in the context of acquiring\n <a href=\"/en/Terms/s/seismic.aspx\">\n  seismic\n </a>\n , electrical,\n <a href=\"/en/Terms/g/gravity.aspx\">\n  gravity\n </a>\n or magnetic data to evaluate the subsurface.\n</div>\n",
            "see": [
                {
                    "title": "acquisition",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/a/acquisition.aspx"
                }
            ],
            "more_details": [],
            "synonyms": [],
            "antonyms": []
        },
        {
            "speech_type": "3. n.",
            "category": "Drilling",
            "definition": "<div class=\"definition-text\">\n A completed measurement of the inclination and azimuth of a location in a well (typically the total depth at the time of measurement). In both directional and straight holes, the position of the well must be known with reasonable\n <a href=\"/en/Terms/a/accuracy.aspx\">\n  accuracy\n </a>\n to ensure the correct wellbore path and to know its position in the event a relief well must be drilled. The measurements themselves include inclination from vertical, and the azimuth (or compass\n <a href=\"/en/Terms/h/heading.aspx\">\n  heading\n </a>\n ) of the wellbore if the direction of the path is critical. These measurements are made at discrete points in the well, and the approximate path of the wellbore computed from the discrete points. Measurement devices range from simple pendulum-like devices to complex electronic accelerometers and gyroscopes used more often as\n <a href=\"/en/Terms/m/mwd.aspx\">\n  MWD\n </a>\n becomes more popular. In simple pendulum measurements, the position of a freely hanging pendulum relative to a measurement\n <a href=\"/en/Terms/g/grid.aspx\">\n  grid\n </a>\n (attached to the\n <a href=\"/en/Terms/h/housing.aspx\">\n  housing\n </a>\n of the tool and assumed to represent the path of the wellbore) is captured on photographic film. The film is developed and examined when the tool is removed from the wellbore, either on\n <a href=\"/en/Terms/w/wireline.aspx\">\n  wireline\n </a>\n or the next time pipe is tripped out of the hole.\n</div>\n",
            "see": [
                {
                    "title": "azimuth",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/a/azimuth.aspx"
                },
                {
                    "title": "deviation survey",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/deviation_survey.aspx"
                },
                {
                    "title": "directional drilling",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/directional_drilling.aspx"
                },
                {
                    "title": "directional survey",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/d/directional_survey.aspx"
                },
                {
                    "title": "inclination",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/i/inclination.aspx"
                },
                {
                    "title": "measurements-while-drilling",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/m/measurements-while-drilling.aspx"
                },
                {
                    "title": "total depth",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/t/total_depth.aspx"
                },
                {
                    "title": "tripping pipe",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/t/tripping_pipe.aspx"
                }
            ],
            "more_details": [],
            "synonyms": [],
            "antonyms": []
        },
        {
            "speech_type": "4. n.",
            "category": "Drilling",
            "definition": "<div class=\"definition-text\">\n A precise and legally binding measurement of surface locations, referenced to known\n <a href=\"/en/Terms/b/benchmark.aspx\">\n  benchmark\n </a>\n locations.\n</div>\n",
            "see": [],
            "more_details": [],
            "synonyms": [],
            "antonyms": []
        },
        {
            "speech_type": "5. vb.",
            "category": "Drilling",
            "definition": "<div class=\"definition-text\">\n To make the measurements as in definitions 1 or 2.\n</div>\n",
            "see": [],
            "more_details": [],
            "synonyms": [],
            "antonyms": []
        },
        {
            "speech_type": "6. n.",
            "category": "Formation Evaluation",
            "definition": "<div class=\"definition-text\">\n The measurement versus depth or time, or both, of one or more physical quantities in or around a well. In early years, the term was used more often than log.\n</div>\n",
            "see": [],
            "more_details": [],
            "synonyms": [
                {
                    "title": "log",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/l/log.aspx"
                }
            ],
            "antonyms": [],
            "alternate_forms": "electrical survey"
        },
        {
            "speech_type": "7. vb.",
            "category": "Formation Evaluation",
            "definition": "<div class=\"definition-text\">\n To record a measurement versus depth or time, or both, of one or more physical quantities in or around a well. In early years, the term was used more often than log.\n</div>\n",
            "see": [],
            "more_details": [],
            "synonyms": [
                {
                    "title": "log",
                    "link": "https://www.glossary.oilfield.slb.com/en/Terms/l/log.aspx"
                }
            ],
            "antonyms": []
        }
    ]
  }

This done, I updated the model as:

import DS from "ember-data";

export default DS.Model.extend({
  term: DS.attr("string"),
  letter: DS.attr("string"),
  group: DS.attr(),
  definitions: DS.attr()
});

Mirage as:

export default function() {
  this.namespace = "api";
  this.get("/term", function({ terms }, { queryParams }) {
    let { term, letter } = queryParams;
    let results = terms.all();
    if (letter) {
      const match = letter.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    if (term) {
      const match = term.toLowerCase();
      results = results.filter(t => t.term.toLowerCase().includes(match));
    }
    return results;
  });
  this.get("/terms", function({ terms }, { queryParams }) {
    let { term, letter } = queryParams;
    let results = terms.all();
    if (letter) {
      const match = letter.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    if (term) {
      const match = term.toLowerCase();
      results = results.filter(t => t.term.toLowerCase().includes(match));
    }
    return results;
  });
  this.get("/disciplines", function({ terms }, { queryParams }) {
    let { group, title } = queryParams;
    let results = terms.all();
    if (group) {
      const match = group.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    if (title) {
      const match = title.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    return results;
  });
this.get("/terms/:id");
}

And template.hbs with:

{{#each model as |group|}}
  {{group.group}}
{{/each}}

{{#each groups as |title|}}
  {{model.title}}
{{/each}}

This produced a bunch of object Object for the handful of terms I updated to arrays, along with one “drilling” for the term without an array. It also gets a response from store, but it was pulling back all of the terms in mirage instead of just the ones for this group.

After much Googling and plenty of reading, I understood this was a one-to-one vs. one-to-many problem. Since this one-to-many is within the same model, it looked like reflexive relations with explicitly defined inverse relationships was the way to go.

Update the model per the docs:

export default DS.Model.extend({
  term: DS.attr("string"),
  letter: DS.attr("string"),
  group: DS.hasMany("term", { inverse: "title"}),
  title: DS.belongsTo("term", { inverse: "group" }),
  definitions: DS.attr()
});

Noticed I didn’t have term for disciplines in mirage and add it:

  this.get("/disciplines", function({ terms }, { queryParams }) {
    let { group, title, term } = queryParams;
    let results = terms.all();
    if (group) {
      const match = group.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    if (title) {
      const match = title.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    if (term) {
      const match = title.toLowerCase();
      results = results.filter(t => t.term.toLowerCase().includes(match));
    }
    return results;
  });

Screen goes blank white and throws these errors:

So it’s getting the category and then promptly breaking with:

message: "Ember Data Request GET /api/terms returned a 500↵Payload (application/json)↵[object Object]"

Don’t know if the problem is mirage or the model, but I’d sure appreciate your input.

Thanks!

p.s. In case it helps, here is the latest repo and a link directly to the JSON.

Progress… put an an RSVP hash on the model.

export default Route.extend({
  model(params) {
    console.log(params)
    return RSVP.hash({
    group: this.store.query('term', { group: params.group }),
    title: this.store.query('term', { title: params.title }),
  })
}
});

It brought back the mirage response with a hint.

message: "Mirage: You're trying to create a term model and you passed in "[object Object],[object Object],[object Object]" under the group key, but that key is a HasMany relationship. You must pass in a Collection, PolymorphicCollection, array of Models, or null."

I win!! It’s all I do!!

image

The problem was in Mirage. I didn’t need a new this.get("/disciplines"... function, just needed to add group to the this.get("/terms"... function that was already there.

export default function() {
  this.namespace = "api";
  this.get("/term", function({ terms }, { queryParams }) {
    let { term, letter } = queryParams;
    let results = terms.all();
    if (letter) {
      const match = letter.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    if (term) {
      const match = term.toLowerCase();
      results = results.filter(t => t.term.toLowerCase().includes(match));
    }
    return results;
  });
  this.get("/terms", function({ terms }, { queryParams }) {
    let { term, letter, group } = queryParams;
    let results = terms.all();
    if (letter) {
      const match = letter.toLowerCase();
      results = results.filter(t => t.term.toLowerCase()[0] === match);
    }
    if (term) {
      const match = term.toLowerCase();
      results = results.filter(t => t.term.toLowerCase().includes(match));
    }
    if (group) {
      const match = group.toLowerCase();
      results = results.filter(t => t.term.toLowerCase().includes(match));
    }
    return results;
  });
this.get("/terms/:id");
}

I knew I was overcomplicating things… at least I learned a bunch of new stuff along the way.

Onward!

1 Like