jb icon indicating copy to clipboard operation
jb copied to clipboard

Rendering with layouts

Open johnpaulashenfelter opened this issue 9 years ago • 1 comments

I may be doing something wrong, but I'm trying to add a layout so I can standardize some metadata in the JSON output.

I've got an layouts\api.jb file and I've requested that layout in the controller generating the json output.

ArgumentError in Api::PostsController#show
unknown keywords: id, title, slug, blurb, classification, higher_ed, sponsor_label, comment_count, share_count, tags, authors, image, date, content, description, schema, meta, chartbeat

Extracted source (around line #172):
    def initialize(*)
      @html_safe = true
      super
    end

    def initialize_copy(other)
....
.bundle/gems/activesupport-4.2.7.1/lib/active_support/core_ext/string/output_safety.rb:172:in `initialize'
.bundle/gems/activesupport-4.2.7.1/lib/active_support/core_ext/string/output_safety.rb:172:in `initialize'
.bundle/gems/actionview-4.2.7.1/lib/action_view/flows.rb:18:in `new'
.bundle/gems/actionview-4.2.7.1/lib/action_view/flows.rb:18:in `set'
.bundle/gems/actionview-4.2.7.1/lib/action_view/renderer/template_renderer.rb:65:in `render_with_layout'
.bundle/gems/skylight-0.10.6/lib/skylight/probes/action_view.rb:32:in `block in render_with_layout'
.bundle/gems/actionview-4.2.7.1/lib/action_view/renderer/abstract_renderer.rb:39:in `block in instrument'
.bundle/gems/activesupport-4.2.7.1/lib/active_support/notifications.rb:164:in `block in instrument'
.bundle/gems/activesupport-4.2.7.1/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
.bundle/gems/activesupport-4.2.7.1/lib/active_support/notifications.rb:164:in `instrument'
.bundle/gems/actionview-4.2.7.1/lib/action_view/renderer/abstract_renderer.rb:39:in `instrument'
.bundle/gems/skylight-0.10.6/lib/skylight/probes/action_view.rb:31:in `render_with_layout'
.bundle/gems/actionview-4.2.7.1/lib/action_view/renderer/template_renderer.rb:52:in `render_template'

I've tried ERB layout template, using content_for, assigning the template output to variables (including instance vars) and using yield or ERB rendering. All lead to similar issues.

Am I totally missing something simple @amatsuda ?

johnpaulashenfelter avatar Oct 03 '16 14:10 johnpaulashenfelter

Sadly, #10 only works for legacy Rails applications (v5 and prior).

For anyone wondering, my current workaround for an SPA is to define a layout helper and use this in all views:

app/helpers/layout_helper.rb
module LayoutHelper
  def layout(**meta)
    meta[:notices]  = @notices  if @notices.any?      # show flash messages
    meta[:redirect] = @redirect if @redirect.present? # trigger frontend routing

    { meta:, data: yield }
  end
end
app/views/users/show.json.jb
layout do
  current_user.attributes.slice("id", "name", "email") if user_signed_in?
end
notes on the protocol
  • API responses always have this shape:

    interface APIResponse<T = any> {
      meta: {
        notices?: string[]
        redirect?: string
      }
      data: T
    }
    
  • the API client first extracts and processes the meta property (by passing it into various stores)

  • the API client then extracts and returns the data property to the caller

I've tried to update #10 to get to work with at least the current Rails version (7.2), but wasn't able to yet.

dmke avatar Aug 29 '24 14:08 dmke