Conversation
rsamoilov
left a comment
There was a problem hiding this comment.
Hi @anuj-pal27
That's a great start! I've left some comments. Please let me know if you have any questions.
|
hii @rsamoilov I have one question that I updated render plain: to use |
Exactly! Which is why you would need to assign the default |
|
@rsamoilov , Done — changed __define_custom_renderers to iterate with @renderers.each since _finalize already guards if @Renderers. Thank you for the clear pointers/review — they helped a lot. |
lib/rage/controller/api.rb
Outdated
| end # class << self | ||
|
|
||
| DEFAULT_CONTENT_TYPE = "application/json; charset=utf-8" | ||
| DEFAULT_PLAIN_CONTENT_TYPE = "text/plain; charset=utf-8" |
There was a problem hiding this comment.
We don't need this value as a constant.
| DEFAULT_PLAIN_CONTENT_TYPE = "text/plain; charset=utf-8" |
There was a problem hiding this comment.
Sorry about that — you’re right. I’ll remove DEFAULT_PLAIN_CONTENT_TYPE and keep only the default JSON content-type as a constant, and update the plain branch to override only when it’s still the default.
lib/rage/controller/api.rb
Outdated
| else | ||
| @__headers["content-type"] = "text/plain; charset=utf-8" | ||
| ct = @__headers["content-type"] | ||
| @__headers["content-type"] = DEFAULT_PLAIN_CONTENT_TYPE if ct.nil? || ct == DEFAULT_CONTENT_TYPE |
There was a problem hiding this comment.
| @__headers["content-type"] = DEFAULT_PLAIN_CONTENT_TYPE if ct.nil? || ct == DEFAULT_CONTENT_TYPE | |
| @__headers["content-type"] = "text/plain; charset=utf-8" if ct.nil? || ct == DEFAULT_CONTENT_TYPE |
lib/rage/configuration.rb
Outdated
| end | ||
|
|
||
| RageController::API.class_eval <<~RUBY | ||
| def render_#{name}(*args, status: nil, **kwargs) |
There was a problem hiding this comment.
I'm really sorry, I didn't realise that return if @__rendered will prevent the code from going into render and raising the exception. We actually need it, could you please add it back? Sorry again.
| def render_#{name}(*args, status: nil, **kwargs) | |
| def render_#{name}(*args, status: nil, **kwargs) | |
| raise "Render was called multiple times in this action." if @__rendered |
There was a problem hiding this comment.
No problem — I’ll add the raise Render was called multiple times in this action.if @__rendered back at the start of render_#{name} (and keep return if @__rendered after the block).
There was a problem hiding this comment.
This looks great!
Thinking about responsibilities, there's one more thing I'd love to improve. Currently, the configuration class defines the custom renderer methods on RageController::API. Ideally though, we want the configuration class to simply hold the data and know as little about the outside world as possible.
- Let's update the
renderermethod to not callRage::Internal.define_dynamic_method- all it should do is just store the block in aRendererEntry - In
__define_custom_renderers, let's move everything inside theRageController::API.method_defined?condition into a dedicated method inRageController::API, e.g.__register_rederer
This way, Configuration won't know the internal details of RageController::API, and the loop inside __define_custom_renderers will simply iterate over the renderers, call __register_rederer and flip the applied flag.
There was a problem hiding this comment.
Sounds good — I’ll refactor so Configuration#renderer only stores the block in RendererEntry, and move the method-definition/conflict-check logic into RageController::API.__register_renderer. Then __define_custom_renderers will just iterate, call __register_renderer, and mark the entry as applied.
Summary
Implements the
config.renderer(:name) { ... }DSL proposed in the issue.Registers custom renderer blocks and generates
render_<name>methods onRageController::APIat boot time.Key behavior
config.renderer(:csv) { |obj, **opts| ... }registers a renderer block__finalize, every controller automatically getsrender_csv,render_phlex, etc.status:as both Symbol (:created) and Integer (201)ArgumentErrorinstead of setting nil statusheaders,request,paramsall workrendercallRageController::API.__custom_renderersregistry makes finalize idempotent across re-runsTests
9 specs covering:
renderinternallyNotes
Renderer blocks are converted to named methods via
define_dynamic_methodratherthan using
instance_execper request — this keeps the hot path allocation-freeand consistent with how Rage handles action methods internally.
Fixes: #234
Screenshots
CSV renderer:

Phlex renderer:
