Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/generators/ruby.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
<li>next</li>
<li>nil</li>
<li>not</li>
<li>object_id</li>
<li>or</li>
<li>post_body</li>
<li>query_params</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,11 @@ public RubyClientCodegen() {
// default HIDE_GENERATION_TIMESTAMP to true
hideGenerationTimestamp = Boolean.TRUE;

// local variable names used in API methods (endpoints)
// local variable names used in API methods (endpoints), plus core methods that
// generated model accessors must not override
for (String word : Arrays.asList(
"local_var_path", "query_params", "header_params", "_header_accept", "_header_accept_result",
"_header_content_type", "form_params", "post_body", "auth_names", "send")) {
"_header_content_type", "form_params", "post_body", "auth_names", "send", "object_id")) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: Escaping object_id to _object_id can silently shadow a sibling property in specs that legitimately define both. toVarName only escapes names that exactly match a reserved word, so a schema with both object_id and _object_id produces two attr_accessor :_object_id lines, and Ruby lets the later definition silently win — one of the two accessors and its attribute_map entry become unreachable. The same collision risk already exists for other reserved words, but this change extends it to a far more common JSON key.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RubyClientCodegen.java, line 142:

<comment>Escaping `object_id` to `_object_id` can silently shadow a sibling property in specs that legitimately define both. `toVarName` only escapes names that exactly match a reserved word, so a schema with both `object_id` and `_object_id` produces two `attr_accessor :_object_id` lines, and Ruby lets the later definition silently win — one of the two accessors and its `attribute_map` entry become unreachable. The same collision risk already exists for other reserved words, but this change extends it to a far more common JSON key.</comment>

<file context>
@@ -135,10 +135,11 @@ public RubyClientCodegen() {
         for (String word : Arrays.asList(
                 "local_var_path", "query_params", "header_params", "_header_accept", "_header_accept_result",
-                "_header_content_type", "form_params", "post_body", "auth_names", "send")) {
+                "_header_content_type", "form_params", "post_body", "auth_names", "send", "object_id")) {
             reservedWords.add(word.toLowerCase(Locale.ROOT));
         }
</file context>

reservedWords.add(word.toLowerCase(Locale.ROOT));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.ObjectSchema;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import org.apache.commons.io.FileUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.languages.RubyClientCodegen;
Expand Down Expand Up @@ -912,4 +914,28 @@ public void testEnumBuildFromHashRaisesByDefault() throws Exception {
" raise \"Invalid ENUM value #{value} for class #Type\"\n" +
" end");
}

@Test(description = "a property named object_id must not override Object#object_id")
public void objectIdPropertyIsEscapedTest() throws Exception {
final File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();

final Schema schema = new ObjectSchema().addProperty("ObjectId", new StringSchema());
final OpenAPI openAPI = TestUtils.createOpenAPIWithOneSchema("Association", schema);
final RubyClientCodegen codegen = new RubyClientCodegen();
codegen.setOutputDir(output.getAbsolutePath());
codegen.setOpenAPI(openAPI);

CodegenProperty objectId = codegen.fromModel("Association", schema).getVars().get(0);
Assert.assertEquals(objectId.name, "_object_id");
Assert.assertEquals(objectId.baseName, "ObjectId");

ClientOptInput clientOptInput = new ClientOptInput().openAPI(openAPI).config(codegen);
new DefaultGenerator().opts(clientOptInput).generate();

Path association = new File(output, "lib/openapi_client/models/association.rb").toPath();
TestUtils.assertFileContains(association, "attr_accessor :_object_id");
TestUtils.assertFileContains(association, ":'_object_id' => :'ObjectId'");
TestUtils.assertFileNotContains(association, "attr_accessor :object_id");
}
}
Loading