undefined method `take' for #<ActiveRecord::QueryMethods::WhereChain:0x00000107609598> - ruby-on-rails

I am trying to select all profiles where a.blocked?(p) returns false!
However I am getting an error.
in a method in model
p = self.find_by_email(email)
all.find_by { |a| a.blocked?(p) }.order('random()')
error
undefined method `take' for #<ActiveRecord::QueryMethods::WhereChain:0x00000107609598>

find_by does not take a block, but rather conditions in the form of a hash, array, or string. See the documentation: http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find_by
If you can't replicate blocked? in SQL, you'll have to do the filtering in Ruby like:
all.find_all { |a| a.blocked?(p) }.shuffle
Because that's doing the filtering and sorting in Ruby rather than SQL, it will be slower.

Related

NoMethodError for nil object on sort_by, and all objects exist

So I have a bunch of users, who all have user.dj_name attributes. It's a validated necessity on the model, but I'm still being cautious here because I'm running into problems.
I want to get a bunch of users, then order them by their dj_name. Something like this:
#djs = Event.all.map { |e| e.program.user }.sort_by {|x,y| x.dj_name <=> y.dj_name }
where it's pulling all DJs who have Events (shows). It fails with "NoMethodError: undefined method `dj_name' for nil:NilClass"
So I tried:
#djs = Event.all.map { |e| e.program.user }
#djs.compact.sort_by! {|x,y| x.dj_name <=> y.dj_name rescue nil}
And it doesn't sort. Without the "rescue nil" clause, I get the same error.
And if I do a reject! if the object is nil I get nothing.
> #djs.reject! {|d| d.nil? }
=> nil
It seems like none of the objects in the array are nil, the sorting mechanism is giving me errors, and rescuing it just stops the sorting process and returns an unchanged array.
halp?
Use sort!, not sort_by!.
sort_by! passes a single argument into its block. So, when you call .sort_by! {|x,y| ... }, y is always nil.
The purpose of sort_by! is to sort by keys instead of elements. The block gets a single element and must return the element's key to use for sorting.
In this code:
#djs.compact.sort_by! {|x,y| x.dj_name <=> y.dj_name rescue nil}
the block returns nil as a key for every element. As result, no sorting happens.
BTW, I agree with #MurifoX that in this particular case you should you database-provided sorting.
Use the database sort for this kind of task. You can resume your queries by using:
Event.all(:include => {:program => :user}, :order => 'users.dj_name')
Decoupling this query would result in the include method making the join associations on your models and the order creating an ORDER BY on your query.

Rails 3 - NoMethodError: undefined method for nil:NilClass in each Iteration

I'm iterating over an array of instances of a Rails model. Here is my code:
product_details.each do |product_detail|
product_detail.label = Backend::ProductGroup.where(product_group_number: product_detail.product_group).first.label
end
The attribute 'label' from 'product_detail' isn't an attribute from my Rails ActiveRecord model. I added it with attr_accessor in my class definition. I did this, because I wanted to add this attribute dynamically, only when I need to do this. When I ran the code without the 'each' iteration in my rails console it works just fine. But when I execute the above code I get the following error message:
NoMethodError: undefined method 'label' for nil:NilClass
Did I do something obviously wrong?
Many thanks in advance.
You likely have several product_detail items that have no matching product_group. So calling .first on the empty collection returns nil. To get around the error, you can test if the product_group was found before proceeding:
product_details.each do |product_detail|
product_group = Backend::ProductGroup.where(product_group_number: product_detail.product_group).first
product_detail.label = product_group.label if product_group
end
You can also do this more efficiently like so:
group_labels = BackEnd::ProductGroup.
where(product_group_number: product_details.map(&:product_group)).
inject({}){|m, g| m[g.product_group_number] = g.label; m}
product_details.each do |product_detail|
product_detail.label = group_labels[product_detail.product_group]
end
This will result in a single database call to grab all related groups, and put the labels in a keyed hash for easy discovery and assignment.

How to catch an "undefined method `[]' for nil:NilClass" error?

I get an nested array from facebook via omniauth and wanna check if it's empty?/nil?/exists?
the depending line looks like:
unless omniauth['extra']['raw_info']['location']['name'].nil?
This should check if this part of the array is empty or exists.
But always this error was thrown:
undefined method `[]' for nil:NilClass
Do I check arrays wrong?
I tried it with "has_key" "nil?" "empty?" "exists?" "blank?"
But no one of these works!
Please help me, many thanks in advance!
Ideally you should check each nested level to see if it is nil, however, this will also work.
unless (omniauth['extra']['raw_info']['location']['name'] rescue nil).nil?
You can also rescue the NoMethodError specifically.
This error is raised because one of the hash values in the chain of omniauth['extra']['raw_info']['location']['name'].nil? returns nil and it is not the last call ['name'].
If for example omniauth['extra']['raw_info'] returns nil, you're actually trying to call nil['location'] which raises an error in ruby.
You can catch this error simply:
res = omniauth['extra']['raw_info']['location']['name'].nil? rescue true
unless res
#your code here
end
Please notice that the code block above will fill the variable res with true if the ['name'] hash value is nil or any other hash value in the chain returns nil.
A bit late to the party, but, as pointed in this answer, Ruby 2.3.0 introduced a new method called dig, which would return nil if one of the chained keys is nil. Your omniauth auth hash could then be presented as:
omniauth = {
...
"extra"=>{ "raw_info"=>
{ "location"=>"New York",
"gravatar_id"=>"123456789"}}
...
}
omniauth.dig('extra',
'raw_info',
'location',
'name',
'foo',
'bar',
'baz') #<= nil

Cannot access data in active record using dot notation

I created a model in Ruby and am stuck on a n00b issue. In Rails Console:
s = Survey.where(:keyword => 'foo')
=> [#]
s.inittxtmsg
NoMethodError: undefined method inittxtmsg' for #<ActiveRecord::Relation:0x10350f8f8>
from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.5/lib/active_record/relation.rb:371:inmethod_missing'
from (irb):3
Shouldn't I be able to see the values by typing s.Survey_id, s.inittxtmsg, s.keyword, s.store?
Thank you!
Survey.where(:keyword => 'foo')
returns an array of results, so you are really calling .inittxtmsg on an array, which obviously doesn't exist.
You could do something like:
Survey.where(:keyword => 'foo').first.inittxtmsg, in which it is calling it on the actual model object.
Or if you know that there is only one survey with the keyword = foo... you can use the find method to only return a single model object:
s = Survery.find_by_keyword("foo")
s.inittxtmsg

Rails 3 - Undefined method on certain collections

I have a search method written for my model Link.
I've been able to called this method without error until implementing voting. For example, these all work:
Link.search(params[:search])
current_user.links.search(params[:search])
current_account.links.search(params[:search])
The following does not work:
#links = current_user.votes.collect {|vote| vote.voteable}
#favorites = #links.search(params[:search])
and return this error:
undefined method `search' for #<Array:0x00000006919ac8>
I've done some testing, to see if my class is wrong, in the console:
links = user.votes.map {|vote| vote.voteable}
links.class
=> Array
links.first.class
=> Link
This should be no different than my working examples:
user.links.class
=> Array
user.links.first.class
=> Link
I thought maybe the error was from me calling search on an array and not a link. But in previous examples I'm also calling it on an array.
I'm using vote_fu to handle the voting thus the vote/voteable.
The search function or scope that you have defined is defined on the Link object and is usable in Link relations, but it is not defined on a simple array, which is what is getting returned from the first collect example. Here is a simple distinction:
class User
scope :search, lambda{ |name| where(name: name) }
end
User.search('Kombo').all # Returns an array of the SQL result run against the DB
User.all.search('Kombo') # NoMethodError: undefined method `search' for #<Array:0x000001079b15b0>
In your first example, Link.search(params[:search]), you are performing the equivalent of User.search.all, and User is a scoped ActiveRecord relation/object, which means it can continue to be combined with other scopes, like where, limit and group. In the second example, #links = current_user.votes.collect {|vote| vote.voteable}, collect is acting on such a relation and is returning a simple array which can no longer be acted upon with these scoped functions. The second example is like doing User.all.search.
It's confusing because both of these examples resolve to an Array eventually, but the difference is what is happening before that resolution to an Array, and when you are actually calling the search function. To get around this you'll have to actually call the search scope or function on an ActiveRecord object, like Link or an ActiveRecord Relation like current_user.links, but you won't be able to call it on a result. Just to clarify:
Link.search(params[:search]) # will work
Link.all.search(params[:search]) # will not work
current_user.links.search(params[:search]) # will work
current_user.links.all.search(params[:search]) # will not work
current_account.links.search(params[:search]) # will work
current_account.links.all.search(params[:search]) # will not work
When you call .collect you are implicitly calling .all, which breaks the scope chain. The following two commands are equivalent in that respect:
#links = current_user.votes.collect {|vote| vote.voteable}
#links = current_user.votes.all.collect {|vote| vote.voteable}

Resources