Mike Crittenden
Mike Crittenden

Reputation: 5917

Include arbitrary field in Rails model JSON output

I'm using Rails as a REST server, and one of my models has a description field. In that model's JSON representation, I need to output both the regular description field AND an arbitrary non-DB attribute called description_markdown that is just the description run through a markdown filter. I already know how to run text through markdown using redcarpet, like:

@post = Post.find(params[:id])
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :autolink => true, :space_after_headers => true, :fenced_code_blocks => true, :lax_html_blocks => true)
description_markdown = markdown.render(@post.description).html_safe

But what I really need is to make description_markdown an attribute on @post (like @post.description_markdown), and have it output in @post's JSON representation.

Upvotes: 2

Views: 2407

Answers (3)

streetlogics
streetlogics

Reputation: 4730

Just wanted to add an alternative in case you're defining what fields/data you need in the controller (like you might in a Rails 4 app), like so:

Post.to_json(only: [], methods: [:generate_markdown])

in your Post code, add:

def generate_markdown
    markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :autolink => true, :space_after_headers => true, :fenced_code_blocks => true, :lax_html_blocks => true)
    return markdown.render(@post.description).html_safe

Upvotes: 0

Simon Bagreev
Simon Bagreev

Reputation: 2859

I normally use RABL gem to build JSON views for my APIs -- it gives you a lot of flexibility on building JSON responses, such as creating custom child nodes, adding arbitrary code. Check it out. But, to answer your question, you can probably overwrite as_json method of Post to include the return of description_markdown. Something like (not tested):

#post.rb
class Post < ActiveRecord::Base

  def description_markdown
    ...
  end
  ...
  def as_json(options)
    super(:only => [:attributes_you_want], :methods => [:description_markdown])
  end
  ...
end

Then, in controller:

render :json => @post

Hope, it helps.

Upvotes: 4

mu is too short
mu is too short

Reputation: 434685

You could add description_markdown to your model:

def description_markdown
    markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :autolink => true, :space_after_headers => true, :fenced_code_blocks => true, :lax_html_blocks => true)
    markdown.render(description).html_safe
end

Then add that to your model's as_json using :methods:

def as_json(options = { })
    super((options || { }).merge({
        :methods => [:description_markdown]
    }))
end

That would add your description_markdown output to your model's standard JSON representation. The options || { } is there in case someone hands you a nil for options, then we merge our :methods into the options, and hand it off to ActiveRecord::Base for the heavy lifting. You'll need more complicated merging for options if you want outsiders to be able to send in their own :methods values.

Upvotes: 2

Related Questions