Search hash results for similar matches rails 3 - ruby-on-rails

I'm using the Facebook API to pull a list of all of my friends. However, I don't want to store the results in the database. I just want to take the hash of results that I get back and perform selects on the results.
However, I'm having a hard time doing that...
I get results like this...
[{"name"=>"John Smith", "id"=>"12345"}, {"name"=>"Jane Doe", "id"=>"23456"}, {"name"=>"Samuel Jackson", "id"=>"34567"}, {"name"=>"Kate Upton", "id"=>"45678"}]
They're stored in #friends
My select is:
#friends.select{|key, hash| hash["name"] == "John Smith" }
but I keep getting an error "undefined method `[]' for nil:NilClass"
Two questions:
1. How can I get the search of the hash to return John Smith (without storing in a database, and without modifying the initial Facebook API query)
2. Is it possible to use "Like" rather than "==" so that it returns results containing the word?
Thank you!

You are getting "undefined method [] for nil:NilClass" because you are using the method select wrongly. Try doing this:
#friends.select{ |hash| hash["name"] == "John Smith" }
So I believe this answers your first question. You don't need to store anything in the database, but in the instance variable #friends, and use select correctly.
Regarding the second question, I believe you should look into regular expressions, as it really depends on what do you mean by "like", but if you say that you want:
it returns results containing the word?
Well, if you want to check for a specific word (let's say Smith), you would do the select as:
#friends.select{ |hash| hash["name"].include? "Smith" }
Which would give you all the elements on the array which name includes the word Smith.

Related

Dynamic Method Calls on Rails Association

Given an array like this:
%w{ field_one, field_two, some_association.field_one }
I need to iterate over this and dynamically call these methods on a given object, exactly as described here: Ruby send method with rails associations
So far I have this, which does fetch the values correctly:
field.include?('.') ? field.split('.').inject(some_object, :send) : some_object.send(field)
Additionally though, I need to call :human_attribute_name on the correct class to generate labels. What is a clean way to accomplish this?
It's not clear what you're trying to accomplish but if I had to guess I'd say you're trying to make some kind of CMS or reporting system in which the definition of what data to display can be altered through a user interface. There are gems for this kind of thing but seeing as you're on this track...
By :human_attribute_name I assume you mean the friendly name to be displayed on the page as a label. First of all it would be more appropriate to use a string rather than symbol as you can then use spaces and more characters. Assuming you never intend to have duplicate label names on the same webpage you could try using a hash instead of an array.
fields = {
"Field One" => "field_one" ,
"Field Two" => "field_two" ,
"Field One Of Some Association" => "some_association.field_one"
}
and then fetch the data in a similar way to that shown in the answer you referenced.
data = {}
fields.each_pair do | friendly_name, attribute |
data[friendly_name] = if attribute.include?('.')
attribute.split('.').inject(some_object, :send)
else
some_object.send(attribute)
end
end
That should leave you with a hash you can loop over in your view like this
{
"Field One" => "Mr" ,
"Field Two" => "Data",
"Field One Of Some Association" => "A Friend Of Mr Data"
}

How do you access an object's (ActiveRecord::Relation) value by key in Ruby on Rails?

tl;dr How do I get the corresponding value with the key of an object?
I'm confused why
Atag.where(tag:'brand') gives me what I would call an object for lack of a better term: #<ActiveRecord::Relation [#<Atag id: 1, tag: "brand", created_at: "2015-01-31 04:29:20", updated_at: "2015-01-31 04:29:20">]>
But I'm having the basic difficult of accessing the corresponding value for the key :id.
Atag.where(tag:'brand').id and Atag.where(tag:'brand')[:id] and Atag.where(tag:'brand')(:id) all throw errors, while in this case I'm just trying to have the integer 1 returned.
I seem to be unable to ruby, nor find a succinct answer to this basic question with my google searching skills (or lack there of).
Thanks
From great documentation at the Odin Project.
The key thing to note is that #find returns the actual record while #where returns an ActiveRecord::Relation which basically acts like an array.
So if you're using #where to find a single record, you still need to remember to go into that "array" and grab the first record, e.g. User.where(:email => "foo#bar.com")[0] or User.where(:email => "foo#bar.com").first.
This gets me all the time...
Get the id of your tag = 'brand' with following query:
Atag.find_by(tag:'brand').id
Check following variations:
Atag.find(1)
#gives you the object with the Atag id = 1
Atag.find(100) #let's say this record does not exist then you will
get ActiveRecord::RecordNotFound exception.
Better option :
Atag.where(id: 1)
#this returns you a relation and it's true you are trying to access
only a single object.
Hence, you just need to modify it to :
Atag.where(id: 1).first
#Above one will give you an object of Atag not an association result.
# to verfiy you can execute, Atag.where(id: 1).first.class
Atag.where(id: 999).first
# In this case if there is no record found with id = 999, then it'll
return nil which can be easily handled than an exception found
while using find method.
Get the same flavor using the dynamic finders.
Atag.find_by(id: 1) #gives the Atag with id 1
Atag.find_by_id(1). # same as above.
Atag.find_by(id: 999) #if not found then simply returns nil.
Atag.find_by(name: 'ruby') #return Atag object with name: 'ruby'
Atag.find_by_name('ruby') #same as above.
Yep, looks like you figured it out. For reference, you can use Atag.where(tag:'brand').first to get the first result, and Atag.where(tag:'brand').to_a to get an array of all the matching results.
where return instance of ActiveRecord::Relation which can be treated like an array with records as its members. Even if the result is single it should be accessed like a member of array with single element
Atag.where(tag: 'brand')
returns the array of results and to access id we should get the record from the array first i.e.
Atag.where(tag: 'brand')[0].id
In order to get id of all the matching records we need to use pluck with where. pluck returns an array of attribute that is plucked.
Atag.where(tag: 'brand').pluck(:id)
This would return an array of id from the collection returned by where only.
The find_by method finds the first record matching some conditions. Since find_by returns the record (not an array) , we can do:
Atag.find_by(tag: 'brand').id
PS: No one had mentioned pluck that's why I wrote this answer. Hope its helpful.

Returning a hash instead of array with ActiveRecord::Base.connection

I have to use a query like this :
query = Enc.joins(:rec).group("enc.bottle").
select("enc.bottle as mode, count(rec.id) as numrec, sum(enc.value) as sumvalue")
That I use with :
#enc = ActiveRecord::Base.connection.select_all(query)
To get the data, I've to do #enc.rows.first[0] (it works)
But #enc.rows.first["mode"] doesn't work ! Because each row of #enc.rows contains array.. not a map with the name of each field.
Maybe select_all is a wrong method.
Does it exist another method to get the data with the name of field ?
Thank you
EDIT
If you can associate a model with the query, then there's no need for the generic select_all method. You can use find_by_sql like this:
Enc.find_by_sql(query).first.mode
# => testing
Note that you will no be able to see the aliases when inspecting the results, but they are there. Also, the convention is to use plural names for the tables. You might find it easier to just sticks with the defaults.

Rails select from model

in some video i saw next string:
User.select(:email).map(&:email)
tell me plz what does it means
i know that string
User.select(:email)
is selecting only the email column from the db, but i don't understand what means
.map(&:email)
and can we change User.select(:email) to User.pluck(:email)
because from tutorial i understand thats the same methods. is this true?
The map(&:email) maps your array of Users to a map of string containing only the users' emails.
The Array.map iterates over your current array, and creates a new one, by calling the parameter block, and storing the result in the new array. It is equivalent with this:
new_array = []
Users.select(:email).each do |user|
new_array << user.email
end
User.select(:email)
is returning an array of User objects. The expression
User.select(:email).map(&:email)
selects the email attribute of that objects only. So you end up with an array of email strings. That's at the end the same as
User.pluck(:email)
But it's is different from User.select(:email) for that reason.
See the documentation of pluck als well.
I suppose you already know what map(&:email) gives you, I assume you are asking how and why because it was the same thing that struck me when I first saw this.
So this is one of the more advanced ruby magic that voodoo's results back to you :)
Basically lets look at the map function, in itself the most basic usage is to accept a block level command. And after iterating through, takes the default return value and chuck it into an array for you usage. For example, lets see this
list = User.all
so we get a list of user objects [User model,User model] etc.
list.map do |user|
user.email
end
if u run this block in IRB or Rails Console, you get ["some#email.here, another#email.here"] etc.
so lets catch this result and assign it into a variable
email_list = list.map do |user|
user.email
end
now email_list should equal to ["some#email.here, another#email.here"]
Now that you get the background to the map function, lets delve into the various ways it can accept a parameter
list.map {|user| user.email }
this is the same as the above, but using curly braces to enclose the block logic
list.map(&:email)
this is the shorthand for the above, by defining the block for you, you just supply what child function you wish to run on the block item.
Hope this has given you alittle insight into short hand methods and its block level equivalents.

Mongoid OR query syntax

This must be asked alot but it is very poorly documented. There is no mention at http://mongoid.org/en/mongoid/docs/querying.html
I'm trying to check whether a user exists (below is an AND query), how can I change it to an OR type query
Username.where(:username=>#username, :email=>#email)
(Either the email or the username must match).
I have found some pretty complicated ways online including sending a direct javascript (from): http://omarqureshi.net/articles/2010-6-17-using-or-in-mongoid
Surely there must be a simple clear syntax to do this correctly?
For the sake of others who end up on this page, the updated syntax is now
Username.or({username: #username}, {email: #email})
Please refer to the updated docs or relevant impl.
Yeah, this used to be documented better. Try this:
Username.any_of({:username => #username},
{:email => #email})
There is a typo in #miguel-savignano's response. According to Stackoverflow the "edit queue is full", which is why I didn't submit an edit.
Proper syntax:
Username.or({username: #username}).or({email: #email})
A more concise solution:
Username.or({username: #username}, {email: #email})
The Mongo selector will resolve to:
{"$or"=>[{"username"=>#username}, {"email"=>#email}]}
I found this question as I was trying to solve for creating "or" queries.
If you are looking to match a string or any one of an array of elements, then you will need to write a Mongoid query with the Mongo '$in' selector.
For example, you have a specific username and an array of emails. You would like to return all results where at least one of the fields matches either the username or one of the emails within the array.
#username = "jess"
#emails = ["hi#mail.com", "test#mail.com", "foo#mail.com"]
User.or({username: ""}, {email: {'$in': #emails}})
The Mongo selector will resolve to:
{"$or"=>[{"first_name"=>""}, {"email"=>{:$in=>["hi#mail.com", "test#mail.com", "foo#mail.com"]}}]}
If you have Users with 2 of the 3 emails in your database, then the selector will return a count of 2.
If you have a User with the username "jess" and 3 additional Users each with one of the given emails, then the selector will return a count of 4.
Also, in Mongoid 5.0, if you still want to use the where method, use the following
Username.where('$or' => [ { username: #username }, { email: #email } ])
this is very useful when you are building a kind of query hash in a dynamic way and you need to keep the where method
In Mongoid 5.0, this works for me
Username.or({username: #username}).or({email: #email})

Resources