passing values into as_json via options hash? - ruby-on-rails

I'm trying to pass an object (the current user) to be used when rendering the json for a collection.
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #items }
format.json { render :json => #items.to_a.as_json(:user => current_user) }
end
However, this seems to have no effect as options[:user] is nil in the as_json method.
JSON_ATTRS = ['id', 'created_at', 'title', 'content']
def as_json(options={})
# options[:user] is nil!
attributes.slice(*JSON_ATTRS).merge(:viewed => viewed_by?(options[:user]))
end
Anyone know why this doesn't work, or can suggest a more elegant way to have the json renderer be aware of the current user?
Thanks,
Wei

you are calling as_json on an Array (#items.to_a), are you sure that is what you want?
If you are trying to call it on your models then you need to do something like #items.to_a.map{|i| i.to_json(:user => current_user)} (and you probably don't need the to_a).
And it is to_json you should be calling. It will invoke as_json to get your properties, passing along whatever options you provide it with, but return a properly formated json-string (as_json returns a ruby object).

BTW, if you want to pass the options on down to "child" associations, I found that this worked (at least on a mongo_mapper backed project):
def as_json(options={})
{
:field1 => self.field1,
:field2 => self.field2,
:details => self.details.map{|d| d.to_json(options)}
}
end

Related

how can i get the values using include with conditions in rails?

I have the shop with has_many association and include items to it so that the items belonging to that shop is received
format.json { render json: {:shop => #shops.as_json(:include => :items)}}
now it gives all the items that belongs to that shop but i want to get items with specific condition, say item_type = "accessories". so how can i do this? please help me.
EDIT
I have put a new question in How to get the value of include with conditions?
You should filter the data with ActiveRecord, and then call the as_json on the filtered data.
You can do something like:
#shops = Shop.includes(:items).where("items.itemp_type = ?", 'accesories')
format.json { render json: { :shop => #shops.as_json(:include => :items) } }
One way you could do this is to create a hash with the objects you want to render, and then pass that to the render method. Like so:
respond_to do |format|
format.json { render :json => {:shops => #shops,
:items => #items }}
end
If the models aren't associated through active record, that's probably your best solution.
If an association does exist, you can pass an :include argument to the render call, like so:
respond_to do |format|
format.json { render :json => #shops.to_json(:include => [:items])}
end
Note that you wouldn't have to retrieve the #items variable in the section above if you take this approach, Rails will automatically load it from the #shops variable.

How to pass an argument in an method which in being represented as symbol?

I have an action as :
def get_data
#people = Person.all
respond_to do |format|
format.json do
render :json => {
:success => true,
:people => #people.as_json({
:only => [:person_name, :text_description, :text_heading],
:methods => [:title,:age_group],
})
}
end
end
end
Here title and age_group are my methods in model Person
def age_group
self.name
end
Now i want to method to look like this
def age_group(age)
# ...
end
How do i pass this argument from the controller as the methods representation there is as symbol.
Hi as per my suggestion you can override method or create a instance method depending upon options it will generate hash or json.If you want to use as_json then you can dig into code this line is helpful for digging code https://github.com/rails/rails/blob/2-3-stable/activerecord/lib/active_record/serialization.rb#L33 which will give you how methods being passed.

Rails JSON callback - Sphinx

Im using thinking sphinx and it has become necessary to pull out the search results as JSON array with callback (JSONP). In my other functions like show, adding .json?callback=asd to the url allows this. But not for what i have retrieved with thinking_sphinx. This is what my index looks like
def index
#profiles = Profile.search params[:search], :match_mode => :any
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #profiles, :callback => params[:callback] }
end
end
Ive been able to say /profiles.json?search=what to get a json. But how do i get a callback
What kind of url do i need to send, or other change i need to make, to get the right format for my models -- wrapperFunction(arrayOfJSONs)
Just add the callback as another query parameter:
/profiles.json?search=<query>&callback=<callbackname>
Just substitute <query> and <callbackname> with your values.

Overriding as_json method with params

First of all, I'm using Rails 3.0.6 and Ruby 1.9.2
I have a controller with two different actions, both should return a json object, but with different formats. Therefore I'm overriding the as_json method to write the JSON object in my own format. Problem is that I don't know how to pass params to as_json method since it's being automatically called by Rails.
My code looks like this:
class MyController < ApplicationController
def action1
# my code
respond_to do |format|
# Render with :json option automatically calls to_json and this calls as_json
format.js { render :json => #myobjects }
end
end
def action2
# a different code
respond_to do |format|
# This action should return a JSON object but using a different format
format.js { render :json => #myobjects }
end
end
end
class MyModel < ActiveRecord::Base
def as_json(options = {})
# I would like to add a conditional statement here
# to write a different array depending on one param from the controller
{
:id => self.id,
:title => self.description,
:description => self.description || "",
:start => start_date1.rfc822,
:end => (start_date1 && start_date1.rfc822) || "",
:allDay => true,
:recurring => false
}
end
end
Note that #myobjects are a collection of objects which class is MyModel.
Any help would be appreciated. Thank you!
Call it explicitly in controller and pass params. as_json will return string and calling as_json on string returns itself. It is quite common practice.
respond_to do |format|
# Render with :json option automatically calls to_json and this calls as_json
format.js { render :json => #myobjects.as_json(params) }
end

How to DRY up Rails 3 controllers by overriding methods like respond_with?

I'm trying to create a JSONP API for my Rails 3 application. Right now in my controllers, I have a lot of actions which follow this pattern:
# This is from my users_controller.rb, as an example
def index
#users = User.all
respond_with(#users, :callback => params[:callback])
end
While this works as is, I would like to DRY it up by not having to repeat the :callback => params[:callback] in every action's call to respond_with. How can I do this?
Update: One thing I've realized that is ugly about my above code is that the :callback => params[:callback] option will be passed for any response format, not just JSON. The following code is probably more correct:
def index
#users = User.all
respond_with(#users) do |format|
format.json { render :json => #users, :callback => params[:callback]}
end
end
There are a couple ways I've considered to address this problem, but I can't figure out how to make them work:
Override render (perhaps in the application controller) so that it accepts a :jsonp option that automatically includes the :callback => params[:callback] parameter. This way I could change the above code to the following, which is somewhat shorter:
def index
#users = User.all
respond_with(#users) do |format|
format.json { render :jsonp => #users}
end
end
Create a responder that overrides to_json in order to solve my problem. That way I could leave out the block and just call respond_with(#users, :responder => 'MyResponder') to solve the issue. Or perhaps I could include this code in an application responder using plataformatec's responders gem so that respond_with(#users) by itself would be sufficient.
Note that technically, it is incorrect to render JSON with a callback parameter, since you get a JavaScript response (a function call to the JSON-P callback) rather than a JSON result.
So if you have
render :json => my_object, :callback => params[:callback]
and a request for /users?callback=func comes in, Rails would answer
func({…})
with content type application/json, which is incorrect, since the above response is clearly not JSON but JavaScript.
The solution I use is
def respond_with_json(item)
respond_with do |format|
format.json { render :json => item }
format.js { render :json => item, :callback => params[:callback] }
end
end
which responds correctly with or without callback. Applying this to the aforementioned solution, we get:
def custom_respond_with(*resources, &block)
options = resources.extract_options!
if params[:callback]
old_block = block
block = lambda do |format|
old_block.call(format) if block_given?
format.js { render :json => resources[0], :callback => params[:callback] }
end
end
respond_with(*(resources << options), &block)
end
Also note the correction to resources[0], otherwise you end up wrapping resources in an extra array as a result of the splat operator.
THere's a gem that can do this to: rack-jsonp-middleware.
The setup instructions are pretty scant on the site, but I did create a little Rails project that uses it - which you can take a look at the commits and see what I did to get the middleware up and running.
https://github.com/rwilcox/rack_jsonp_example
This is bit 'low-tech' compared to the reponder solution, but what about just creating a private method in your appliation_controller.rb to handle this. The params variable will be available to it and you could pass the #users object to it.
#application_controller.rb
private
def jsonp(my_object)
render :json => my_object, :callback => params[:callback]
end
#controller
def index
#users = User.all
respond_with(#users) do |format|
format.json { jsonp(#users)}
end
end
Thanks to samuelkadolph for helping me in the #rubyonrails IRC channel today. He provided a solution in this gist, copied below for convenience:
def custom_respond_with(*resources, &block)
options = resources.extract_options!
if options[:callback]
old_block = block
block = lambda do |format|
old_block.call(format) if block_given?
format.json { render :json => [] }
end
end
respond_with(*(resources << options), &block)
end
I haven't tried this in my application yet, but I can see that it should work. He also confirmed that I could similarly override the respond_with method itself simply by changing the name of this method and changing the last line of the definition to super(*(resources << options), &block).
I think this will work for me. However, I'm still interested in knowing how to write a custom responder to do the job. (It would be a more elegant solution, IMHO.)
Update: I tried this in my application and it works with some minor changes. Here is the version I'm using now in the private section of my ApplicationController, designed to automatically provide the :callback => params[:callback] option to JSON requests:
def custom_respond_with(*resources, &block)
options = resources.extract_options!
if params[:callback]
old_block = block
block = lambda do |format|
old_block.call(format) if block_given?
format.json { render :json => resources, :callback => params[:callback] }
end
end
respond_with(*(resources << options), &block)
end
Note that I had to change if options[:callback] to if params[:callback] in order to get it working.
You can also check out this answer. basically you can create a "default" respond_to for your controller so you can just make your all your actions default to responding to json.
was that what you were asking?

Resources