I have the controller below that returns 100+ results and I want to be able to only pass 10 results with the json call and some sort of method that if more results are desired another request should be made but I'm not sure how to go about doing this.
Here's an except of my controller
def list(){
def results = Domain.list(max: 10)
withFormat {
json (render results as JSON)
}
}
Can someone point me in the write direction where I can read on documentation or see sample codes that might do this.
Thanks!
The default scaffolding templates would be a good place to look as they show how to do pagination in the list action. How about this:
def list(){
// max 10 unless something else was requested
if(!params.max) params.max=10
def results = Domain.list(params)
withFormat {
json (render results as JSON)
}
}
To request the next page of results you'd use .../list?offset=10&max=10, for the next use offset=20, etc.
Refer docs for list() method on how pagination parameters work.
Try this,
def c = Domain.createCriteria()
def results = c.list(max: 10, offset: 10) {
order("some", "desc")
}
withFormat {
json { render results as JSON }
}
Refer
Related
Introduction
Correcting a legacy code, there is an index of object LandingPage where most columns are supposed to be sortable, but aren't. This was mostly corrected, but few columns keep posing me trouble.
Theses columns are the one needing an aggregation, because based on a count of other documents. To simplify the explanation of the problem, I will speak only about one of them which is called Visit, as the rest of the code will just be duplication.
The code fetch sorted and paginate data, then modify each object using LandingPage methods before sending the json back. It was already like this and I can't modify it.
Because of that, I need to do an aggregation (to sort LandingPage by Visit counts), then get the object as LandingPage instance to let the legacy code work on them.
The problem is the incapacity to transform Mongoid::Document to a LandingPage instance
Here is the error I got:
Mongoid::Errors::UnknownAttribute:
Message:
unknown_attribute : message
Summary:
unknown_attribute : summary
Resolution:
unknown_attribute : resolution
Here is my code:
def controller_function
landing_pages = fetch_landing_page
landing_page_hash[:data] = landing_pages.map do |landing_page|
landing_page.do_something
# Do other things
end
render json: landing_page_hash
end
def fetch_landing_page
criteria = LandingPage.where(archived: false)
columns_name = params[:columns_name]
column_direction = params[:column_direction]
case order_column_name
when 'visit'
order_by_visits(criteria, column_direction)
else
criteria.order_by(columns_name => column_direction).paginate(
per_page: params[:length],
page: (params[:start].to_i / params[:length].to_i) + 1
)
end
def order_by_visit(criteria, order_direction)
def order_by_visits(landing_pages, column_direction)
LandingPage.collection.aggregate([
{ '$match': landing_pages.selector },
{ '$lookup': {
from: 'visits',
localField: '_id',
foreignField: 'landing_page_id',
as: 'visits'
}},
{ '$addFields': { 'visits_count': { '$size': '$visits' }}},
{ '$sort': { 'visits_count': column_direction == 'asc' ? 1 : -1 }},
{ '$unset': ['visits', 'visits_count'] },
{ '$skip': params[:start].to_i },
{ '$limit': params[:length].to_i }
]).map { |attrs| LandingPage.new(attrs) { |o| o.new_record = false } }
end
end
What I have tried
Copy and past the hash in console to LandingPage.new(attributes), and the instance was created and valid.
Change the attributes key from string to symbole, and it still didn't work.
Using is_a?(hash) on any element of the returned array returns true.
Put it to json and then back to a hash. Still got a Mongoid::Document.
How can I make the return of the Aggregate be a valid instance of LandingPage ?
Aggregation pipeline is implemented by the Ruby MongoDB driver, not by Mongoid, and as such does not return Mongoid model instances.
An example of how one might obtain Mongoid model instances is given in documentation.
I have a method:
def nameToCode(nameStr){
def ret = resortService.getResort("all")
//this gets like 180 objects with various properties like name, code, etc.
def resorts = [name: ret.prName, code: ret.prProductIndex]
def code = resorts.findByName(nameStr) //this doesn't work
println(code)
return code
}
I'm trying to call this method and send it a name. It's then supposed to go find the name in the map, if it finds it it's supposed to return the name's code. This is supposed to be simple but I've been searching everywhere and can't figure out how to do this. I'll appreciate any help. Thanks
you are using a gorm method on a standard map:
Instead of :
def resorts = [name: ret.prName, code: ret.prProductIndex]
def code = resorts.findByName(nameStr) //this doesn't work
Try:
def resorts = [name: ret.prName, code: ret.prProductIndex]
def code = resorts.findAll{name==nameStr}
I am trying to alter the default index action for a Grails controller to enable some basic search criteria.
I have two main issues:
The paginate control at the bottom of the page forgets my search criteria.
How can I use the grails criteria createCriteria().list() operation with variable criteria. In particular, how should I account for things like null (ignored) criteria?
edit: I am adding my controller code:
def index(Integer max) {
session.alarmFilter = params.alarmFilter == null ? (session.alarmFilter == null ? [] : session.alarmFilter) : params.alarmFilter
params.max = Math.min(max ?: 10, 100)
def c = Alarm.createCriteria()
def results = c.list (params) {
if(session?.alarmFilter?.channelInterface != null) {
sqlRestriction("channel_interface_id = ${session.alarmFilter.channelInterface.id}")
}
}
respond results, model:[alarmFilter: session.alarmFilter, alarmInstanceCount: results.totalCount]
}
I'm not fond of saving the search criteria (alarmFilter) in the session since it doesn't really feel like session information. In particular, returning to this page will remember previous search criteria.
Also the if statement is causing an 'SQLException' when the criteria is not selected.
My Grails code has a search function that redirects to another controller action after performing a findAllBy query:
def results = Foo.findAllByBar(baz)
redirect(action: "result", params: [results: results])
findAllByBar returns an ArrayList with models, as expected, but after the redirect the receiving action gets a String array. Worse, when there is only one result it doesn't even get an array, it just gets a String.
Given that I have to iterate through the results in the receiving view, doing it on a string will meticulously print every letter individually. We can all agree that that's probably not the ideal behaviour.
A redirect results in a new GET request with the parameters in the querystring, e.g. /controller/result?foo=bar&baz=123 - you can't put objects there since it's just a string.
You could put the ids of the objects in the params and load them in the result action:
def action1 = {
def results = Foo.findAllByBar(baz)
redirect(action: "result", params: [resultIds: results.id.join(',')])
}
def result = {
def resultIds = params.resultIds.split(',')*.toLong()
def results = Foo.getAll(resultIds)
}
or put them in Flash scope:
def action1 = {
flash.results = Foo.findAllByBar(baz)
redirect(action: "result")
}
def result = {
def results = flash.results
}
It sounds like you want to use the chain method instead of the redirect method. Chain lets you pass a model as a parameter similar to render.
An example would be:
chain(action:'result',model:[results:results])
Heres a link for further information:
http://www.grails.org/doc/latest/ref/Controllers/chain.html
Hi I have a JSON string that looks like this (Usingt Rails and a REST service)
{
person:
{
name:"Pepe",
last:"Smith"
hats:[ { team:"lakers", color:"purple"}, { team:"heats", color:"red" }] } }
I want to be able to able to get that JSON, and save the Person to the database, but I want to save the "hats".. as a string to the database; without parsing it or anything like that
i.e. I want to save this to SQL:
hats = "[ { team:"lakers", color:"purple"}, { team:"heats", color:"red" }] }"
Is there a way to do this in rails?
The JSON string gets converted to params hash before a controller action is invoked.
You could make to_json call on the hats attribute to get an equivalent json string.
def create
params[:person][:hats] = (params[:person][:hats]||{}).to_json
p = Person.new(params[:person])
if p.save
#success
else
#error
end
end