immaculate.pine
immaculate.pine

Reputation: 151

Tableless model JSON serialization in Rails

I have tableless model (like it was shown in #219 railscast):

class MyModel
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_accessor :attr1, :attr2, :attr3, :attr4

  private
    def initialize(attr1 = nil)
      self.attr1 = attr1
    end

    def persisted?
      false
    end
end

Then I'm trying to render JSON in controller:

@my_model = MyModel.new
render json: @my_model.to_json(only: [:attr1, :attr2])

but it renders JSON with all the attributes of the model.

I've tried to add

include ActiveModel::Serialization

but it didn't change rendered JSON.

How can I render JSON with only necessary attributes of my tableless model?

I'm using Rails 3.2.3

Update

Thanks, guys. It seems you're all almost right. I combined your solutions and got this:

Model:

include ActiveModel::Serialization

...

def to_hash
  {
    attr1: self.attr1,
    attr2: self.attr2,
    ...
  }
end

Controller:

render json: @my_model.to_hash.to_json(only: [:attr1, :attr2])

I really don't know whose answer to be accepted.

Update 2

Suddenly new strangeness appeared. One of the attributes is array of hashes. It was like this:

attr1: [[{name: "name", image: "image"}, {name: "name", image: "image"}],
        [{name: "name", image: "image"}, {name: "name", image: "image"}]]

But now it lost all its content and looks like this:

attr1: [[{}, {}], [{}, {}]]

Maybe anyone know how to fix it?

Update 3 :)

Erez Rabih's answer helped. Using slice instead of to_json solved the problem. So, final solution is:

render json: @my_model.to_hash.slice(:attr1, :attr2)

Upvotes: 1

Views: 604

Answers (3)

Jef
Jef

Reputation: 5474

You may mix your initial approach (including AM serialization modules) with Erez' one as the documentation suggests.

class MyModel
    include ActiveModel::Serialization::JSON
    ....
    def attributes
       {:attr1 => self.attr1.....}
    end
    ...
end

Upvotes: 0

Erez Rabih
Erez Rabih

Reputation: 15788

I know it isn't straight forward but how about:

render :json => @my_model.attributes.slice(:attr1, :attr2)

You will also be required to define an attributes method as:

def attributes
   {:attr1 => self.attr1.....}
end

Thanks for the comment bender.

Upvotes: 1

bender
bender

Reputation: 1428

I believe it's because Object::as_json is calling internally (look at this: http://apidock.com/rails/Object/as_json), and it has no options like :only or :except, so you can overide method to_hash in your class, e.g.:

def to_hash
  {:attr1 => self.attr1, :attr2 => self.attr2}
end

and to_json will do exactly what you want.

Certainly, another option is to override method to_json ...

Upvotes: 0

Related Questions