3

I'm not sure if I'm at fault here or if my approach is wrong with this.

I want to fetch a user (limiting columns/fields only to name, email, id):

@user = User.first(:api_key => request.env["HTTP_API_KEY"], :fields => [:id, :name, :email])

The output in the command line is correct as follows:

SELECT "id", "name", "email" FROM "users" WHERE "api_key" = '90e20c4838ba3e1772ace705c2f51d4146656cc5' ORDER BY "id" LIMIT 1

Directly after the above query, I have this code:

render_json({
    :success => true,
    :code    => 200,
    :user    => @user
})

render_json() looks like this, nothing special:

def render_json(p)
  status p[:code] if p.has_key?(:code)
  p.to_json
end

The problem at this point is that the @user variable contains the full user object (all other fields included) and DataMapper has made an additional query to the database to fetch the fields not included in the :fields constraint, from the logs:

SELECT "id", "password", "api_key", "premium", "timezone", "verified", "notify_me", "company", "updated_at" FROM "users" WHERE "id" = 1 ORDER BY "id"

My question is this: how do I stop DM from performing the additional query? I know it has to do with it's lazy loading architecture and that returning the @user variable in JSON assumes that I want the whole user object. I particularly don't want the password field to be visible in any output representation of the user object.

The same behaviour can be seen when using DM's own serialisation module.

ghstcode
  • 2,902
  • 1
  • 20
  • 30

1 Answers1

2

I think you should use an intermediate object for json rendering.

First, query the user from database :

db_user = User.first(:api_key => request.env["HTTP_API_KEY"], :fields => [:id, :name, :email])

Then, create a "json object" to manipulate this user :

@user = { id: db_user.id, name: db_user.name, email: db_user.email }
Michel
  • 706
  • 3
  • 6
  • I had the same idea, but it's not very elegant - especially when creating an API that has many resources, lot's of unnecessary code to write when you already have the data scoped in another local object. – ghstcode Oct 14 '13 at 15:01