In my API, I am converting an ActiveRecord object into json via:
user.to_json :methods => :new_messages
Using irb, when I execute this statement, I get:
{someAttr: someValue, ....}
which is perfect. This is a single object so it's not wrapped in an array. Now when I run this in sinatra app like this:
get '/api/users/:fb_id' do |fb_id|
user = User.where :fb_id => fb_id
user.to_json :methods => :new_cookies
end
It wraps it in an array!!! Like this:
[{someAttr: someValue, ....}]
How can I fix this, and more importantly, why?!?
Simply using Hash.[]
Hash[{a: :b}]
# => {:a=>:b}
and more importantly, why?!?
Which ORM are you using in the second example? If it's ActiveRecord, then User.where :fb_id => fb_id returns ActiveRecord::Relation object which wraps into an array when you call .to_json. It can be fixed like so
get '/api/users/:fb_id' do |fb_id|
user = User.find_by_fb_id(fb_id)
user.to_json :methods => :new_cookies
end
replace this line:
user = User.where :fb_id => fb_id
with this line:
user = User.find_by_fb_id fb_id
Related
I want to know how to check if an array element exists inside of a MongoMapper Array. This question is the closest I could find, but it addresses queries rather than simply using a document you already have.
My User model contains the line
key :roles, Array
The 'roles' array contains strings such as 'admin' or 'user.' For authorization, I need to call something like the following method on an instance of User:
if user.roles.contains?('admin')
# Do administrative stuff.
end
But when I try to call 'contains?' Ruby complains that there is no such method:
NoMethodError (undefined method `contains?' for #<Array:0x007fc845cd8948>):
app/models/ability.rb:11:in `initialize'
app/controllers/settings_controller.rb:5:in `index'
If there's no way to do this, then how do I convert the Array into a Ruby array to call 'contains?'? Calling to_a isn't doing it:
if user.roles.to_a.contains?('admin') # etc...
I'm using Rails 3.2.13, Ruby-1.9.3-p392, and MongoMapper 0.12.0 on Mountain Lion.
the function you are looking for is include?, so the expression would be: user.roles.include?('admin')
However since you mentioned mongomapper, if you were preforming a query on the roles array you would do the fallowing:
User.where( :roles => 'admin' )
You can also search an array with an array
User.where( :roles.in => ['admin'] )
for a query with admin or user you can do:
User.where( :$or => [{:roles => 'admin'},{:roles => 'user'}] )
and you can do and just the same:
User.where( :$and => [{:roles => 'admin'},{:roles => 'user'}] )
In a rails app I have an action that returns a json representation of a collection of different models. It looks something like this:
respond_to :json
def index
#cars = Car.all
#vans = Van.all
respond_with({
:cars => #cars,
:vans => #vans
})
end
However, I want to customise the attributes and methods that are passed to the json object. A bit like:
respond_with({
:cars => #cars.to_json(:only => [:make, :model], :methods => [:full_name]),
:vans => #vans
})
Doing the above, causes the json representation of the "cars" to be escaped as one big string, like:
{
"cars":"[{\"car\":{\"make\":\"Ford\" ... etc
"vans": [{"van":{"make":"Citreon" ... vans not escaped
}
Obviously I'm approaching this the wrong way. Can anyone point me in the right direction?
Since you're nesting the to_json in another Hash, I think you need to use as_json (which returns a Hash instead of a String) instead:
respond_with({
:cars => #cars.as_json(:only => [:make, :model], :methods => [:full_name]),
:vans => #vans
})
I've got the following code
u = Client.get(:show_by_username, :username => username.downcase)
When a valid user is returned, they seem to be getting returned as a hash instead of an object that I can call methods on
e.g. I have to access values like
u['id']
instead of
u.id
How can I get it to return it as an object?
Thanks
As described in the docs for the ActiveResource 'get' method, it does not convert them into ActiveResource::Base instances. As it says, you need to use the find method instead:
u = Client.find(:all, :from => :show_by_username, :params => { :username => username.downcase })
I feel like this is a simple problem I'm having due to my misunderstanding of the new ActiveRecord query interface, but take this example:
>> Category.first.recipes
=> [ ... ] # array of recipes
However:
>> Category.where(:id => 1).recipes
=> NoMethodError: undefined method `recipes' for #<ActiveRecord::Relation:0x000001033dc9e0>
What's going on here? why does my where method return an ActiveRecord::Relation object? how can I retrieve the objects from the query here?
This is actually intentional.
Category.where(:id => 1)
# Is Equivalent to Category.all(:conditions => {:id => 1}})
Category.where(:id => 1).first
# Is equivalent of Category.first(:conditions => {:id => 1}})
The objects are only retrieved when special methods like first, each etc are called. This is called lazy loading which is a great when you want to cache your views. Read more about why here.
Category.where(:id => 1).recipes
Returns an array. If you simply do Category.where(:id => 1).first.recipes it should work.
But if you are just doing a where against the id, use the find method
Category.find(1) will return a Category object.
So:
Category.find(1).recipes
When using :methods in to_json, is there a way to rename the key? I'm trying to replace the real id with a base62 version of it, and I want the value of base62_id to have the key :id.
#obj.to_json(
:except => :id
:methods => :base62_id
)
I tried to do
#obj.to_json(
:except => :id
:methods => { :id => :base62_id }
)
but that didn't work.
Any advice?
The to_json serializer uses the name of the method as the key for serialization. So you can't use the methods option for this.
Unfortunately to_json method doesnt acceptblock` parameter, otherwise you could have done something similar to
#obj.to_json(:except => :id) {|json| json.id = base62_id }
So that leaves us with a ugly hack such as:
def to_json(options={})
oid, self.id = self.id, self.base62_id(self.id)
super
ensure
self.id = oid
end
Now to_json will return the expected result.