Search code examples
ruby-on-railsrubyjsonrabl

Reduce complexity of RABL template


My RABL template seems to be very un-DRY and over complex. Because of this I think I may be using it wrong, or that there are better ways at generating my desired output.

As you can see from the show.rabl code, I have to turn the plugins_vulnerability.vulnerability association into a JSON hash, explicitly selecting which keys I need, then merge the plugins_vulnerability.fixed_in value into the hash, and finally adding the new hash, which now contains the fixed_in value, to the vulnerabilities_array array.

I'm doing this because I want the fixed_in value to be within the vulnerability node.

plugins_controller.rb

class Api::V1::PluginsController < Api::V1::BaseController
  def show
    @plugin = Plugin.friendly.includes(:plugins_vulnerability, :vulnerabilities).find(params[:id])
  end
end

show.rabl:

object @plugin
cache @plugin if Rails.env == 'production'

attributes :name

# Add the 'vulnerabilities' node.
node :vulnerabilities do |vulnerabilities|
  vulnerabilities_array = []

  # turn the plugins_vulnerability association into an array
  vulnerabilities.plugins_vulnerability.to_a.each do |plugins_vulnerability|
    vulnerability = plugins_vulnerability.vulnerability.as_json # turn the plugins_vulnerability.vulnerability association into json
    vulnerability = vulnerability.select {|k,v| %w(id title references osvdb cve secunia exploitdb created_at updated_at metasploit fixed_in).include?(k) } # only select needed keys

    vulnerabilities_array << { 
      :vulnerability => vulnerability.merge(:fixed_in => plugins_vulnerability.fixed_in)
    } # merge the fixed_in attribute into the vulnerability hash and add them to an array (fixed_in is from plugins_vulnerabilities)
  end

  vulnerabilities_array
end

output.json

{
  "plugin": {
    "name": "simple-share-buttons-adder",
    "vulnerabilities": [
      {
        "vulnerability": {
          "id": 88157,
          "title": "Simple Share Buttons Adder 4.4 - options-general.php Multiple Admin Actions CSRF",
          "references": "https:\/\/security.dxw.com\/advisories\/csrf-and-stored-xss-in-simple-share-buttons-adder\/,http:\/\/packetstormsecurity.com\/files\/127238\/",
          "osvdb": "108444",
          "cve": "2014-4717",
          "secunia": "",
          "exploitdb": "33896",
          "created_at": "2014-07-15T17:16:51.227Z",
          "updated_at": "2014-07-15T17:16:51.227Z",
          "metasploit": "",
          "fixed_in": "4.5"
        }
      },
      {
        "vulnerability": {
          "id": 88158,
          "title": "Simple Share Buttons Adder 4.4 - options-general.php ssba_share_text Parameter Stored XSS Weakness",
          "references": "https:\/\/security.dxw.com\/advisories\/csrf-and-stored-xss-in-simple-share-buttons-adder\/,http:\/\/packetstormsecurity.com\/files\/127238\/",
          "osvdb": "108445",
          "cve": "",
          "secunia": "",
          "exploitdb": "33896",
          "created_at": "2014-07-15T17:16:51.341Z",
          "updated_at": "2014-07-15T17:16:51.341Z",
          "metasploit": "",
          "fixed_in": "4.5"
        }
      }
    ]
  }
}

Solution

  • I guess you can do something like this:

    object @plugin
    cache @plugin if Rails.env == 'production'
    
    attributes :name
    
    child(@plugin.vulnerabilities => :vulnerabilities) {
      attributes :id, :title, :references, :osvdb, :cve, :secunia, :exploitdb, :created_at, :updated_at, :metasploit
    
      # Add the 'fixed_in' node.
      node :fixed_in do |vulnerability|
        @plugin.plugins_vulnerability.fixed_in
      end
    
    }
    

    This should create the same output that you need. And it doesn't look awefully complex to me.