Haystack whoosh models() not narrowing models - models

I have the following query
locations = SearchQuerySet().filter_or(content__in=words).models(Location)
but it's returning other models as well, I would only want to see Location instances.
Using Haystack 2.1.0 and whoosh 2.5
Any ideas?

My current work around is to use filter(django_ct='app_name.model')

I ran into the same issue with Model filtering being ignored. I was able to get .models() working by downgrading to Haystack 2.0.0 and Whoosh 2.4.1

This is based partly on James Lims answer, but this should work for any versions of Haystack and Whoosh. Unfortunately neither party is really coming to the rescue on this, but the below solution doesn't seem to be too bad.
class MySearchQuerySet(SearchQuerySet):
def models(self,*mods):
# We have to redefine this because Whoosh & Haystack don't play well with model filtering
from haystack.utils import get_model_ct
mods = [get_model_ct(m) for m in mods]
return self.filter(django_ct__in=mods)
Then where ever SearchQuerySet use MySearchQuerySet instead:
MySearchQuery().filter(name="foo").models(my_models.bar,my_models.baz)

Related

Ruby on Rails ActiveRecord filter issue [duplicate]

I am working on an app that allows Members to take a survey (Member has a one to many relationship with Response). Response holds the member_id, question_id, and their answer.
The survey is submitted all or nothing, so if there are any records in the Response table for that Member they have completed the survey.
My question is, how do I re-write the query below so that it actually works? In SQL this would be a prime candidate for the EXISTS keyword.
def surveys_completed
members.where(responses: !nil ).count
end
You can use includes and then test if the related response(s) exists like this:
def surveys_completed
members.includes(:responses).where('responses.id IS NOT NULL')
end
Here is an alternative, with joins:
def surveys_completed
members.joins(:responses)
end
The solution using Rails 4:
def surveys_completed
members.includes(:responses).where.not(responses: { id: nil })
end
Alternative solution using activerecord_where_assoc:
This gem does exactly what is asked here: use EXISTS to to do a condition.
It works with Rails 4.1 to the most recent.
members.where_assoc_exists(:responses)
It can also do much more!
Similar questions:
How to query a model based on attribute of another model which belongs to the first model?
association named not found perhaps misspelled issue in rails association
Rails 3, has_one / has_many with lambda condition
Rails 4 scope to find parents with no children
Join multiple tables with active records
You can use SQL EXISTS keyword in elegant Rails-ish manner using Where Exists gem:
members.where_exists(:responses).count
Of course you can use raw SQL as well:
members.where("EXISTS" \
"(SELECT 1 FROM responses WHERE responses.member_id = members.id)").
count
You can also use a subquery:
members.where(id: Response.select(:member_id))
In comparison to something with includes it will not load the associated models (which is a performance benefit if you do not need them).
If you are on Rails 5 and above you should use left_joins. Otherwise a manual "LEFT OUTER JOINS" will also work. This is more performant than using includes mentioned in https://stackoverflow.com/a/18234998/3788753. includes will attempt to load the related objects into memory, whereas left_joins will build a "LEFT OUTER JOINS" query.
def surveys_completed
members.left_joins(:responses).where.not(responses: { id: nil })
end
Even if there are no related records (like the query above where you are finding by nil) includes still uses more memory. In my testing I found includes uses ~33x more memory on Rails 5.2.1. On Rails 4.2.x it was ~44x more memory compared to doing the joins manually.
See this gist for the test:
https://gist.github.com/johnathanludwig/96fc33fc135ee558e0f09fb23a8cf3f1
where.missing (Rails 6.1+)
Rails 6.1 introduces a new way to check for the absence of an association - where.missing.
Please, have a look at the following code snippet:
# Before:
Post.left_joins(:author).where(authors: { id: nil })
# After:
Post.where.missing(:author)
And this is an example of SQL query that is used under the hood:
Post.where.missing(:author)
# SELECT "posts".* FROM "posts"
# LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
# WHERE "authors"."id" IS NULL
As a result, your particular case can be rewritten as follows:
def surveys_completed
members.where.missing(:response).count
end
Thanks.
Sources:
where.missing official docs.
Pull request.
Article from the Saeloun blog.
Notes:
where.associated - a counterpart for checking for the presence of an association is also available starting from Rails 7.
See offical docs and this answer.

ActiveStorage::Attachment find resource by blob_id

I have the following model
class Document
has_many_attached :previews
...
end
And I'm trying to find single elements there.
The problem is if I do:
#document.previews.find_by(blob_id: 22)
I get this error: undefined method `find_by' for #<ActiveStorage::Attached::Many>
So I'm kind of forced to loop through enumerable:
#document.previews.find { |p| p.blob_id == 22 }
Is there any other (better/prettier) way to do this?
#ntonnelier I have a similar model, and with Rails 7.0.3 your first example works fine for me:
#document.previews.find_by(blob_id: 22)
Another couple of options that work are:
#document.previews.where(blob_id: 22)
#document.previews.blobs.find_by_id(22)
You should be able to access the blobs for a particular record via the blobs method, which gets you an ActiveRecord collection, and you can use find on that one.
Something like #document.previews.blobs.find(22) might work in your particular case.

How to Fix Document Not Found errors with find

I have a collection of Person, stored in a legacy mongodb server (2.4) and accessed with the mongoid gem via the ruby mongodb driver.
If I perform a
Person.where(email: 'some.existing.email#server.tld').first
I get a result (let's assume I store the id in a variable called "the_very_same_id_obtained_above")
If I perform a
Person.find(the_very_same_id_obtained_above)
I got a
Mongoid::Errors::DocumentNotFound
exception
If I use the javascript syntax to perform the query, the result is found
Person.where("this._id == #{the_very_same_id_obtained_above}").first # this works!
I'm currently trying to migrate the data to a newever version. Currently mongodbrestore-ing on amazon documentdb to make tests (mongodb 3.6 compatible) and the issue remains.
One thing I noticed is that those object ids are peculiar:
5ce24b1169902e72c9739ff6 this works anyway
59de48f53137ec054b000004 this requires the trick
The small number of zeroes toward the end of the id seems to be highly correlated with the problem (I have no idea of the reason).
That's the default:
# Raise an error when performing a #find and the document is not found.
# (default: true)
raise_not_found_error: true
Source: https://docs.mongodb.com/mongoid/current/tutorials/mongoid-configuration/#anatomy-of-a-mongoid-config
If this doesn't answer your question, it's very likely the find method is overridden somewhere in your code!

How can I temporarily disable PaperTrail when reifying a version?

I am using paper_trail for undo/redo functionality in my site and am having a problem when I call reify.save on a version in that on save and new PaperTrail::Version gets created.
Is there a way to turn off PaperTrail during the saving of a reified object?
I understand that PaperTrail.enabled = false is possible, but I don't want other changes being made a the same time to not be recorded.
My ideal solution would be something along the lines of:
PaperTrail.disable { version.reify.save }
I once accomplished something similar by mixing in something like this:
def without_papertrail
PaperTrail.disable
yield if block_given?
PaperTrail.enable
end
Then you can do something similar to your objective
without_papertrail { version.reify.save }
You can disable paper trail for a particular model, using either of two syntaxes:
m = MyModel.find(123)
m.paper_trail.without_versioning do
# No versioning of `m` happens in this block
end
Note: Since it is called on a model instance, it seems as though this might naturally disable versioning on just that instance, but this syntax disables versioning on the entire model.
The other syntax:
MyModel.paper_trail.disable
# No versioning of MyModel happens here
MyModel.paper_trail.enable
As of today, gem version 10.3.0, the correct way to achieve this is, as per the gem documentation:
PaperTrail.request.disable_model(Banana)
# changes to Banana model do not create versions,
# but eg. changes to Kiwi model do.
PaperTrail.request.enable_model(Banana)
from the readme: https://github.com/paper-trail-gem/paper_trail#7-testing
PaperTrail.enabled = false

how to use fireAnbu in laravel 3?

I've installed the bundle fireAnbu in my local laravel 3 app, but I can't figure out how to use it! (feeling silly)
I've got 'fireanbu' => array('auto' => true), in bundles.php and 'profiler' => true, in fireanbu/config/fireanbu.php, and I've tried:
fireanbu::log('something');
$fireanbu->log('something');
FirePHP::log('something');
$FirePHP->log('something');
FB::log('something');
$fb->log('something');
I've had a look in fireanbu/start.php for clues, but I'm guessing :(
The best clue I've had so far is:
Non-static method FirePHP::log() should not be called statically, assuming $this from incompatible context
I've looked at http://www.firephp.org/HQ/Use.htm and it looks like fireanbu is using the OO API..
What am I doing wrong / how should I call it within my controllers?
I also created a Laravel 4 version for this if anyone finds this thread looking for a L4 version (like I did, and in the absence of finding one created my own):
https://packagist.org/packages/p3in/firephp
There no need to do anything. It would listen to event from Laravel's own Log class and attach it to FirePHP.
Log::info('foo'); would just work nicely.

Resources