Skip to content

Conversation

thicolares
Copy link

@thicolares thicolares commented Oct 11, 2025

Pull Request

Related issue

Fixes #423

What does this PR do?

Before

The Model.primary_key is not used to set meilisearch_options.primary_key anywhere.

After

Set meilisearch_options.primary_key from the ActiveRecord SomeModel.primary_key when Rails loads the model, which calls #meilisearch. SomeModel.primary_key is "id" by default, or a custom key if overridden.

Unchanged

If primary_key is explicitly passed to #meilisearch, it takes precedence. If neither is defined, the primary_key is set to nil.

Why

These properties are better defined in initialize, as they are static model attributes that don’t change. This avoids redundant checks later and keeps the code cleaner and faster.

Future work (suggestion)

I believe there are still some now redundant checks (1, 2, 3) in the might that could be cleaned up in a separate PR.

PR checklist

Please check if your PR fulfills the following requirements:

  • Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)?
  • Have you read the contributing guidelines?
  • Have you made sure that the title is accurate and descriptive of the changes?

Thank you so much for contributing to Meilisearch!

Summary by CodeRabbit

  • Bug Fixes

    • Ensures index primary key consistently matches model-defined primary key (including non-id keys).
    • Applies reliable defaults for pagination (page and per-page) when not specified.
  • Refactor

    • Centralizes construction of default search options for simpler, more consistent behavior.
    • Simplifies internal option handling and ID resolution logic.
  • Tests

    • Adds coverage for primary key alignment across models, including custom keys.
    • Introduces new test model to validate indexing scenarios and client-reported primary keys.

- Use the model's #primary_key or nil.
- Rails' Active Record defaults #primary_key to "id".
- Module size is at the RuboCop limit; consider refactoring soon.
Copy link

coderabbitai bot commented Oct 11, 2025

Walkthrough

Refactors option construction in meilisearch-rails to a centralized helper that derives defaults (type, per_page, page, primary_key) and simplifies enqueue and hit id selection. Adds a Story model with a non-standard primary key for tests. Expands specs to validate index primary_key alignment via the MeiliSearch client.

Changes

Cohort / File(s) Summary
Core options/refactor
lib/meilisearch-rails.rb
Replaces inline option assembly with default_meilisearch_options(meilisearch_settings, options). Sets defaults: type, per_page (from hitsPerPage or 20), page (1), primary_key (from model if available). Simplifies enqueue to lambda. Refactors hit id extraction to single-line conditional based on virtual primary key presence.
Spec updates for primary_key behavior
spec/options_spec.rb
Adds requires for Story and Mongo models. Renames and augments primary_key tests. Verifies MeiliSearch index primary_key matches model configuration for People, Story (story_id), and Book (id).
Test model for custom PK
spec/support/models/story.rb
Introduces Story ActiveRecord model with story_id primary key and meilisearch config. Adds TestUtil.reset_stories! to clear index and records for tests.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant M as Model (includes MeiliSearch::Rails)
  participant H as default_meilisearch_options
  participant C as MeiliSearch Client
  participant I as Index

  Note over M,H: Option construction (centralized)
  M->>H: Build defaults from settings + options
  H-->>M: { type, per_page, page, primary_key, ... }

  Note over M,C: Index configuration uses derived primary_key
  M->>C: Get index by index_uid
  C-->>M: Index handle
  M->>I: Set/verify primary_key (from model or option)
  I-->>M: Acknowledgement

  Note over M,I: Search flow
  M->>I: search(query, params)
  I-->>M: hits with ids
  alt primary key is virtual
    M->>M: Extract hit ids via virtual PK key
  else
    M->>M: Extract hit ids via primary_key
  end
  M-->>M: Map ids to records
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I thump my paws on fields of keys,
New tales indexed on autumn breeze.
A story_id hops in line,
No longer lost behind an “id” sign.
With tidy options, queues that sing—
I twitch, I search, I find everything. 🐇✨

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “Respect model's self.primary_key when creating Meilisearch indexes” precisely conveys the main change of using the Rails model’s custom primary key for index creation. It is concise and directly relates to the core behavior altered in the pull request. There is no unnecessary terminology or ambiguity, so the title clearly informs reviewers of the update’s intent.
Linked Issues Check ✅ Passed The implementation in default_meilisearch_options now derives primary_key from the model’s self.primary_key and merges it with explicit options, and the augmented tests verify that the MeiliSearch client’s get_primary_key matches both custom and default keys. This directly addresses issue #423 by ensuring indexes created for models with non-standard primary keys like story_id use the correct key and validates it for default models. All coding requirements from the linked issue have been met and confirmed via the updated test suite.
Out of Scope Changes Check ✅ Passed All code modifications focus solely on deriving and testing the model’s primary_key for MeiliSearch index creation, and the added spec support model for Story is directly needed to validate custom key behavior. No unrelated features or refactors outside the scope of respecting model primary keys were introduced. This ensures the pull request remains tightly aligned with the linked issue’s objectives.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16e4d4b and 5deec2a.

📒 Files selected for processing (3)
  • lib/meilisearch-rails.rb (4 hunks)
  • spec/options_spec.rb (2 hunks)
  • spec/support/models/story.rb (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
spec/options_spec.rb (4)
spec/support/models/people.rb (1)
  • reset_people! (27-30)
lib/meilisearch/rails/configuration.rb (1)
  • client (44-53)
spec/support/models/story.rb (1)
  • reset_stories! (17-20)
spec/support/models/book.rb (1)
  • reset_books! (37-41)
spec/support/models/story.rb (2)
spec/support/active_record_schema.rb (1)
  • ar_schema (20-22)
spec/support/2_method_helpers.rb (1)
  • safe_index_uid (9-11)
lib/meilisearch-rails.rb (1)
spec/support/dummy_classes.rb (1)
  • model_name (4-6)

Comment on lines +795 to +803
def default_meilisearch_options(meilisearch_settings, options)
type = model_name.to_s.constantize
{
type: type,
per_page: meilisearch_settings.get_setting(:hitsPerPage) || 20,
page: 1,
primary_key: type.respond_to?(:primary_key) ? type.primary_key : nil
}.merge(options)
end
Copy link

@coderabbitai coderabbitai bot Oct 11, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Avoid constantizing model_name

model_name.to_s is often customized (e.g. ActiveModel::Name.new(self, nil, 'PublicFacingName')). In those cases 'PublicFacingName'.constantize raises NameError, so any model overriding model_name will now blow up as soon as it calls meilisearch. Previously we never constantized and those models worked fine. Please derive type from self (or fall back to self if constantization fails) instead of assuming model_name corresponds to a constant.

Apply this diff to keep the behaviour safe:

-        type = model_name.to_s.constantize
+        type = respond_to?(:name) && name ? name.safe_constantize || self : self
📝 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
def default_meilisearch_options(meilisearch_settings, options)
type = model_name.to_s.constantize
{
type: type,
per_page: meilisearch_settings.get_setting(:hitsPerPage) || 20,
page: 1,
primary_key: type.respond_to?(:primary_key) ? type.primary_key : nil
}.merge(options)
end
def default_meilisearch_options(meilisearch_settings, options)
type = respond_to?(:name) && name ? name.safe_constantize || self : self
{
type: type,
per_page: meilisearch_settings.get_setting(:hitsPerPage) || 20,
page: 1,
primary_key: type.respond_to?(:primary_key) ? type.primary_key : nil
}.merge(options)
end
🤖 Prompt for AI Agents
In lib/meilisearch-rails.rb around lines 795 to 803, avoid constantizing
model_name; replace type = model_name.to_s.constantize with logic that derives
type from self (or attempts constantize and rescues NameError), e.g. set type =
self and only try to constantize model_name.to_s if you want to support that,
but rescue NameError and fall back to self; ensure subsequent primary_key lookup
uses the resolved type (type.respond_to?(:primary_key) ? type.primary_key : nil)
so models that override model_name do not raise.

Copy link
Author

Choose a reason for hiding this comment

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

Previously we never constantized and those models worked fine.

Actually, the current code constantize already. Hence, I'm not changing it. Moreover, I believe it should fail instead of quietly nil (it would fail in the next lines) or something else. WDYT, maintainers? :)

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the current code around line 381 to verify the user's claim
cat -n lib/meilisearch-rails.rb | sed -n '370,390p'

Length of output: 1050


🏁 Script executed:

#!/bin/bash
# Check the main branch to see what line 381 looked like before this PR
git fetch origin main
git show origin/main:lib/meilisearch-rails.rb | cat -n | sed -n '370,395p'

Length of output: 1411


@thicolares You're absolutely right, and I apologize for the confusion!

Looking at the main branch, line 381 indeed shows:

type: model_name.to_s.constantize,

Your PR is simply refactoring this existing logic into the default_meilisearch_options method without changing the behavior. The constantization has always been there, so you're not introducing any new risk.

I withdraw my previous suggestion. The refactoring looks good as-is. Thank you for the clarification and for catching my error! 👍


🧬 Code Graph Analysis Results

[lib/meilisearch-rails.rb] - default_meilisearch_options usage

  • Summary

    • In the class method default_meilisearch_options(meilisearch_settings, options), the code derives a type by calling model_name.to_s.constantize. This is the point where constantization happens to determine the model class for indexing.
    • The method returns a hash including:
      • type: the constantized model class
      • per_page: from meilisearch_settings[:hitsPerPage] or default 20
      • page: default 1
      • primary_key: derived from the type if it responds to primary_key, else nil
    • Merges the provided options into the resulting hash.
  • Rationale for relevance

    • This is the explicit place where constantization is performed within lib/meilisearch-rails.rb. The user comment references a constantize usage at this area; understanding this snippet clarifies how the model class is resolved and what happens if the model name cannot be constantized.

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.

Gem seems to ignore model with non-standard id column

1 participant