One Rails route that responds to html and json with different queries - ruby-on-rails

I have a simple index action in my controller that serves html and json formats.
def index
#records = Model.all
respond_to do |format|
format.html
format.json { render json: #records }
end
end
I've recently redone the HTML view in AngularJS backed by the JSON endpoint. I've noticed from the logs that when loading the HTML for this action that the query is still being made for the HTML view even though I've setup AngularJS to fetch the records at the JSON endpoint on load.
I'm not sure of the best way to handle this. I'd like to be able to not query if I'm just responding to HTML. The obvious way would be to only run the query if the format is JSON, but I have a feeling that's not the best way.

You can solve that simply by doing
def index
respond_to do |format|
format.html
format.json {
#records = Model.all
render json: #records
}
end
end

In Rails 3, calling all on a Model hits the database and retrieve the result.
In Rails 3 Model.all.class = Array[Class] of activerecord objects.
If you want your query to be run only when you iterate over the collection in your view don't call .all directly on your Model class. You can do something like:
#records = Model.scoped
and in your view, when you need to display your collection:
<% #records.each do |record| %>
<%= record.inspect %>
<% end %>
In Rails 4, all returns an ActiveRecord_Relation object and not hits the database until you iterate over your collection.
More info at: http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html#method-i-all

Related

Filtering nested model collections in to_json include in Rails

To start out I have already looked at this thread and this thread.
I have a piece of code that has a couple different postgres calls, and then appends on another model collection named Category within our response. I want to filter out certain pieces of response depending on a search param passed in by the json. My current code is here:
def clues
....
clues = clues.where("category_id = ?", params[:category]) if params[:category].present?
offset = params[:offset].present? ? params[:offset] : 0
#result = clues.limit(100).offset(offset)
respond_to do |format|
if(!params[:category_keyword])
format.json { render :json => #result.to_json(:include => :category) }
else
format.json { render :json => #result.to_json(:include => Category.where("title LIKE ?", '%' + params[:category_keyword] + '%')) }
end
end
end
Right now, the end if statement in the respond_to do is broken, as I don't think my :include for the else statement is in a correct format to filter out, as it just doesn't append the nested model to my json response. What is the best way to filter out these nested calls?

Insert another field into GET response JSON

I have the following code that responds to GET /something.json:
def index
#something = Something.all
respond_to do |format|
format.json { render json: #something }
end
end
That runs a SELECT * FROM something in the database, formats the result into a JSON, and responds with it.
The request might ask for another field through a query parameter, which is in a different table than something. I managed to retrieve the desired field doing this:
def index
#something = Something.all
if params[:get_field_from_some_other_table] == "true"
#something.each do |i|
some_other_table = SomeOtherTable.find(i.some_other_table_id)
the_field_i_want = some_other_table.the_field
end
end
respond_to do |format|
format.json { render json: #something }
end
end
But I haven't found a way to add the field to the JSON string. How can I do that? Or is there a better way to retrieve the field with the contents of the something table through a JOIN or something like that?
something and other_table should be related at active_record somehow... maybe a has_one?
Try that and then just use #something.all.includes(:other_table_attribute)
Apart from that, please post your code properly with some readable examples, that helps a lot and will give you faster responses :)

Render different controller methods as JSON in Rails 5.2

I have a resource that renders as JSON perfectly fine at localhost:3000/gins.json from #gins = Gin.order(name: :desc).
Which will return ALL gins. However, I'd like to have a JSON response that only returns the last 4 gins, to use elsewhere. In the controller I also have:
#latestgins = Gin.order("created_at DESC").first(4)
The above would work in an index.html.erb view with <%= #latestgins.name %>, but how do I get the JSON for this? I have tried render json: #latestgins but navigating to localhost:3000/latestings.json, of course, gives a routing error.
I suspect I'm attacking this in completely the wrong way, but only just starting out with Rails API.
you can add respond to format json in your index method:
def index
#gins = Gin.order(name: :desc)
#latestgins = Gin.order("created_at DESC").first(4)
respond_to do |format|
format.html
format.json { render json: #latestgins }
end
end
your #latestgins is now available here : localhost:3000/gins.json
Edit
If you want a custom route to display your data, just add it in your routes:
defaults format: :json do
get 'last4gins', to: "gins#index"
end
Your data for the last 4 entries is available at http://localhost:3000/last4gins.json, at http://localhost:3000/last4gins but also at localhost:3000/gins.json
If you want to keep the gins index route clean, you can also create a custom method and remove the #latestgins from your index:
# routes
get 'last4gins', to: "gins#last4gins"
#controller
def index
#gins = Gin.order(name: :desc)
end
def last4gins
#latestgins = Gin.order("created_at DESC").first(4)
render json: #latestgins
end
Now the data is no more available at /gins.json

how do you get paperclip url to json in rails?

I'm aware of the other questions pertaining to this subject, but none seem to help. I want the paperclip image url passed to json so I can render it in a reactjs component. I obviously cannot use Rails' image_tag helper.
I've defined this method in my items model
def image_url
image.url(:thumb)
end
And this in my controller
def index
#items = Item.all
render :json => #items.to_json(:methods => [:image_url])
end
But literally all that does is replace the rendered page with json. How should I go about this? It doesn't make sense to create a migration and model validation specifically for the image url.
Just needed to format the html.
respond_to do |format|
format.html
format.json { render :json => #items.to_json(:methods => [:image_url]) }
end
Still doesn't solve the part where I'm trying to use that method in a reactjs component, but that's another issue.

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.

Resources