undefined method `paginate' for #<PG::Result:0x007f8f096a3390 (Converting arel result) - ruby-on-rails

I have the following method:
#vulnerabilities = Vulnerability.details(filter_version_param,
filter: filter,
sort: order)
.paginate(page: page_param, per_page: 10)
The internals of this method uses arel to find the relevant information to display on a page. However when I run into the .page method from the will_paginate gem, I receive the following error:
`undefined method `paginate' for #<PG::Result:0x007f8f096a3390>`
This is due of course to the fact that the object returned is not a class from ActiveRecord. My question is whether there is a way to convert the PG class into an ActiveRecord model? A previous implementation on the application from another developer creates a Struct.new() class and feeds the values into it. I was wondering though if there was an easier way to do this.

You have two options:
for Kaminary gem as an example : convert the query result into an
array and use Kaminary.paginate_array(array_of_result).page(#pagenumber).per(#elemnts per page), but this way could have problems with large data tables since you need to load the hole table for example, then slice the page!
you can build an object that has the sufficient methods needed for the paginator to do its job.
for more explanation and information about the above two points, please chick this link.

Related

Using combined models with pagy, getting undefined method 'offset' error

I am using pagy. I combined two models into one, and I used pagy on that combined model. I am getting this error:
undefined method `offset' for #<Array:0x00007f886f88b3b0>
With the last line of the code below highlighted.
My code:
#problems = Problem.me_and_friends(current_user)
#activities = Activity.me_and_friends(current_user)
#combine = (#problems + #activities).sort{|a,b| a.created_at <=> b.created_at }
#pagy, #combined = pagy_countless(#combine, items:100, link_extra: 'class="" style="color:black; margin:3px;"')
It worked fine with using pagination on #problems alone.
I'd appreciate any help.
As soon as you call the (#problems + #activities), you transform the ActiveRecord::Relation into an array (which is also not good because you are loading all the database rows into memory, sorting and then paginating them). Pagy expects an ActiveRecord::Relation to work, hence the error.
You can consider multiple solutions,
Change your UI to show problems and activities in separate UIs, then you can paginate them separately
Update your models to store both problems and activities in the same table (maybe just a reference table which points to either a Problem or an Activity)
If either of these is not feasible, you can consider rolling out a custom solution for the pagination, but it will be tricky.
Update: June 21, 2021
If you are using Rails 6, it introduces the concept of Delegated Types which fits well into this scenario. The example given in the link mentions the issue of pagination across different tables.

Rails4: Get an ActiveRecord::Relation from a model or an already chained relation

I'm writing a module for ActiveRecord models. In short it's a method that can call a series of where, join and order statements. The statements are not known at the time of writing so it is not possible to use scopes. So far it works well but there is one point I'd like to improve.
Here is my method:
def filter
rel = respond_to?(:filter_scope) ? filter_scope : where(1)
# Do other stuffs with `rel`
# ...
rel
end
It first call filter_scope if it is defined, or it obtain an ActiveRecord::Relation from the target model. To do so I use where(1) to force the model to return a relation object. This works well whenever I call filter directly on the model (User.filter) or on a relation (User.order(:name).filter, User.my_scope.filter.order(:age) etc...)
But using where(1) fells a bit dirty. In Rails 3 I would be using all instead but it's depreciated in Rails 4. Any idea on how to improve this?
Thanks in advance
Note: I cannot substitute where(1) by self because there is a possibility that self would be returned from filter and User.filter would be a class, therefore not usable as a query object.
In Rails 3 I would be using all instead but it's depreciated in Rails 4.
I don't think all is depreciated, it used to return an Array (rails 3) and now returns an ActiveRecord::Relation so you should be able to use it for chaining queries.
see http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html#method-i-all
Returns an ActiveRecord::Relation scope object.

Mongoid returning object as array

I am using tire/elasticsearch for searching with mongoid, when I update the index of my documents I am getting the error undefined method 'as_document':
#document.tire.update_index
undefined method `as_document' for #<Array:0x10a40f870>
I have researched the mongoid method 'as_document' and found out that it only accepts single objects. When my document objects do not have comments, "#document.as_document" returns a single object and there is no error, however when the document has comments, "#document.as_document" seems to return an array and returns the error "undefined method `as_document' for #".
It seems that when #document has comments, it returns an array of hashes.
Is there any way that I can return the array (Array:0x10a40f870) so I can see where it is coming from?
How can I convert #document (which seems to be an array) back into a single object so that it can pass through as_document?
Why am I getting an 'undefined method as_document'
I have a Document model with a has_many relationship to comments
Rails: 3.2.12,
Mongoid: 3.1.4
1. Logger is your homie. I would recommend printing this wherever your logic exists so you can see exactly what array you are returning.
Something like this:
# your logic here
#your_array = ..set
logger.debug "MY ARRAY: #{#your_array}"
This will give you at least a good look at what you are dealing with if you can take a look at Webrick or whatever setup you have.
2+3. Mongoid stores Documents as an array of hashes so that is what you are probably looking at (but I haven't seen the exact code).
I dont believe there is anything wrong with your document definitions but I would take a better look at the [Relations Sections] of the Mongoid docs1
More specifically to question 2: take a look at the operations section.

Can I access the collection an instance method was called on in ruby on rails

I'm working on implementing a search form in a ruby on rails application. The general idea is to use form_tag to submit the search fields (via params) to a search function in the model of the class I'm trying to search. The search function will then iterate through each of the params and execute a scoping function if the name of the function appears in params.
The issue is that when I call the search on a collection like so:
#calendar.reservations.search({:search_email => "test"})
I don't know how to refer to the collection of #calendar.reservations from within the search function.
Additionally I'm confused as to why #calendar.reservations.search(...) works, but Reservations.all.search gives me an error saying you can't call an instance method on an array.
I've got the details of the search method over here: https://gist.github.com/783964
Any help would be greatly appreciated!
I don't know how to refer to the
collection of #calendar.reservations
from within the search function.
If you use self (or Reservation, it's the same object) inside the classmethod, you will access the records with the current scope, so in your case you will see only the reservations of a particular calendar.
[edit] I looked at you search function, and I think what you want is:
def self.search(search_fields)
search_fields.inject(self) do |scope, (key, value)|
scope.send(key, value)
end
end
Additionally I'm confused as to why
#calendar.reservations.search(...)
works, but Reservations.all.search
gives me an error saying you can't
call an instance method on an array.
#calendar.reservations does not return a standard array but a (lazy) AssociationCollection, where you can still apply scopes (and classmethods as your filter). On the other hand Reservation.all returns a plain array, so you cannot execute search there (or any scope, for that matter).
You don't really need a search method at all, as far as I can tell.
Simply use where:
#calendar.reservations.where(:search_email => 'test')
I would strongly encourage you to look at the MetaSearch GEM by Ernie Miller. It handles the kind of thing you're working on very elegantly and is quite easy to implement. I suspect that your view code would almost accomplish what the GEM needs already, and this would take care of all your model searching needs very nicely.
Take a look and see if it will solve your problem. Good luck!
Reservation.all.search doesn't work because it returns all the results as an array, while Reservation.where(..) returns an ActiveRecord object (AREL). Reservation.all actually fetches the results instead of just building the query further, which methods like where, limit etc do.

find_or_create_by_facebook_id method not found

I'm trying to find out where this function comes from. Any one have any clue? It's used by this:
http://github.com/fluidtickets/facebooker-authlogic-bridge
with a working example here:
http://facebooker-authlogic-bridge.heroku.com
Downloading the code, it throws: undefined method 'find_or_create_by_facebook_id' for #<Class:0xb04dd1c>
I have no clue where this function comes from.
Thanks all!
ActiveRecord creates dynamic finders based on columns in your database. So for example if you have a user with a username attribute then activerecord creates a number of dynamic finders:
find_by_username
find_or_initialize_by_username #=> calls new if not found
find_or_create_by_username #=> calls create if not found
You can string a few attributes together like
find_by_username_and_email
To get back to your problem - I suspect that you haven't run some required migration that adds the facebook_id to your users table in the db and therefore ActiveRecord isn't adding the dynamic finder for facebook_id to the class.

Resources