how to store facebook friends to DB (newbie) - ruby-on-rails

i'm creating a facebook-app for university project and i'm trying to store all my friends in the DB.
By using the API-syntax "me/friends" i get a facebook-respond looking like this:
{"data"=>[{"name"=>"Albert Einstein", "id"=>"11111111"}, {"name"=>"Max Mustermann", "id"=>"222222222"}, {"name"=>"Just Another Name", "id"=>"333333333"}]}
I believe its a json-object, but i'm not sure.
Question: How can i save the data, i need a DB with all the User-IDs of my friends.
Thx!
Edit:
Hey, this is what i have searched for. But i still get an error and don't know why.
My code:
def insert_1
fb_friends = rest_graph.get('me/friends')
fb_friends[:data].each do |f|
#friend = Model.new(:name => f["name"] )
#friend.save
end
end
I get an Heroku error (We're sorry, but something went wrong.)

You have two options -
Option 1-
You can create a friends table which will belong to users table. If a user has 200 friends, it will create 200 entries in friends table all belonging to the user via has_many-belongs_to relationship. For storing data, you just have to iterate over facebook friends hash and then save each of them separately
Pros : You can search for any friend separately.
Cons : There will be so many of friend entries. Saving them will take time, if somebody has many friends(say 500-700). Repeating entries will be created for mutual friends.
Options 2
You can add a friends column in your users table and declare this in your user.rb
serialize :friends
This way, you just have to pass a hash object to friends attribute of user table, and rails will save that in yaml format for you. When you will do #user.friends, rails will again convert that yaml formatted data to hash object and return it.
Pros : There will be only one query to save all users. You can iterate through this hash to show list of all friends.
Cons : You can't update them separately, you will update all together. Not good if you want to store some other information in relation to user's friends.
Update
as per your code example above
fb_friends = #your logic to get data as shown above.
fb_friends[:data].each do |f|
#friend = Friend.new(:name => f["name"],:fb_user_id => f["id"] )#creating Friend model obj.
#friend.save
end

Related

How to get only one db record from couple of same?

I have records in the db table that can differ only by ids and creation/update time. How can I get only the unique records?
I tried this way, but it didn't work:
msg_to_user = user.messages.new_messages.uniq
I'll explain. User can follow post manually but also same post can be followed by user automatically. So I want to send only one message if post have been commented by someone.
1747 test message TamadaTours 12 new 2016-01-29 06:14:04.736869 2016-01-29 06:48:55.948529 32964382
1748 test message TamadaTours 12 new 2016-01-29 06:14:04.741184 2016-01-29 06:48:55.951371 32964382
All records in the database are uniq (at least because of ID column, which by default has a uniq constraint).
You would want to use DISTINCT:
Model.select('DISTINCT column_name1, column_name2')
Your question is flawed...
The point of having an id... otherwise known as primary_key... in a relational database is so that you can actively identify the unique records you want:
A primary key uniquely specifies a tuple within a table. In order for an attribute to be a good primary key it must not repeat
When you write... "How can I get only the unique records" ... the answer is to pull only the records based on their id.
If you refine your question to what you really want...
I want to send only one message if post have been commented by someone
--
In other words, you want to pull a collection of unique user_ids (no duplicates), to which you can send new messages?
To do this, you can use...
#recipients = Message.select(:user_id).distinct #-> all unique user_ids
If you're trying to pull the "new" messages for a user, but only show the first (if they're the same), you'll want to use something like the following:
#msg_to_user = user.messages.new_messages.uniq(:title)
Ref
A better pattern to implement would be to validate the uniqueness of new messages:
#app/models/message.rb
class Message < ActiveRecord::Base
validates :user_id, uniqueness: { scope: :message_id } #-> replace message_id with other unique identifier
end
This would ensure only one new message is present for a user.
you can also use group by in your query like this
Model.all.group("column_name")
One way to extract the data but get rid of the ORM context.
# maps every record to hash, remove the ID entry and then removes duplicates
msg_to_user = user.messages.new_messages.attributes.map { |e| e.except('ID') }.uniq

Creating a user from an array of emails

Im creating an api to create a new userS(plural) from an array of emails.
We are assuming that there are no validations other than user requires an email. So all i need is an email to create a user.
Reason i'm doing this is because i'm creating an API.
How do i create users from an array of emails?
Here is the array. I actually have real emails but for this example i will make them up.
# => [
# [0] "email1#example.com.au",
# [1] "email2#example.com.au",
# [2] "email3#example.com",
# [3] "email4#example.com.au",
# [4] "email5#example.com.au"
# ]
To create a user it's just the typical way
User.new(email: 123#example.com)
Thanks in advance for any help.
To save records based on your array, you will want to store that array in a variable (remember that in Ruby, everything is an object). Let's say you have:
emails = ["email1#example.com.au",
"email2#example.com.au",
"email3#example.com",
"email4#example.com.au",
"email5#example.com.au"]
From there you can write a loop that iterates over your lovely array and creates a User for each array item you declared:
emails.each do |e|
User.create(email: e)
end
User.new will not save the records, so please use User.create.
If you just want to save records basing on the emails list(which is an array basing on your description), you just need to do everything like #l0010o0001l said(I love this nickname! :) ).
But in my opinion, you could do something more if this api will be provided to others.
The first thing is that you should format the email address with all words in lower-case before you save them. This may do great help whenever save new records or maintain old records. Just like:
emails.each do |email|
User.create(email: email.downcase)
end
Then you need to present result to the one who calls the api. just like: if all the email list was created successfully you can respond with the records amount created successfully. And if some records can not be created(format error, record has existed .etc) you should respond with the error info (you may need to use user.errors.full_messages to get error messages).
The way to do this is somethign like
user_emails.each do |user_email|
User.create(email: user_emails )
end

Rails Controller Variables and Complex Relationships

Let's say we have the following scenario in a Rails application:
Users have many Websites, and Websites have many Simulations (likewise, Websites belong to Users, and Simulations belong to Websites).
Now the problem is, how do I display a list of all of a User's Simulations on the User Show page?
My first gut attempt was to define the following in the Users Controller:
def show
#user = User.find(params[:id])
#websites = #user.websites
#simulations = #user.websites.simulations
end
And then use <%= render #simulations %> in the Users Show Page, but that gives a NoMethodError: undefined methodsimulations' for []:Array` when I visit localhost:3000.
So how can I create a variable in my User Controller that holds all the Simulations that belong to the Websites that belong to a particular User?
Any and all help is greatly appreciated!
class User < ActiveRecord::Base
has_many :websites
has_many :simulations, :through => :websites
end
now you can use #simulations = #user.simulations and get all the user's simulations
In your user model add this method. This will produce 2 queries but still better then joining simulations in ruby code.
def websites_simulations
Simulation.where(website_id: website_ids)
end
Use Erez's answer
You asked for it - I don't know about ruby, but each website in #websites should already contain a field that has a simulation.
This is what you're doing.
1 - You take user, a single object, and get its websites. Cool. User looks something like this (in pseudocode):
Object #user
{
Array[] websites = [(Website)site1, (Website)site2];
}
Alright, that's cool. So user.websites should return an array of websites.
2 - You try to get the simulations from a website. A website probably looks like this:
Object #website
{
Array[] simulations = [(Simulation)sim1, (Simulation)sim2];
}
Hm, why doesn't it work? Well lets break down what you're doing:
#user.websites.simulations
You're taking websites, which is an array, and trying to reference a variable that belongs to a website type and not an array type. #user.websites is an array object that holds websites, not a website itself. What you want is to get #website.simulations, not websites.simulations.
So the first step is getting a website. That's easy - one way would be to try to fetch a website from your website array in the user.
#User.websites[0] <-- may not be syntactically correct; I don't know ruby.
Now if you want to get all of the websites, iterate through them using a loop and push them to a new array. Again in pseudocode:
#all_simulations = new Array();
for(#i=0;#i<count(#user.websites);#i++) //first loop through the websites
{
for(#q=0;#q<count(#user.websites[#i].simulations);#q++) //then loop through the simulations
{
#all_simulations.push(#user.websites[#i].simulations[#q]); //push the simulation into #all_websites
}
}
What we do here is we go into each website in the user.websites array and then grab each simulation from that website and throw that into our #all_simulations variable. If you understand the concept, you should be able to convert this logic into valid ruby.

Rails: Get relationship on array of objects

I don't know if there's a good answer for this. Let's say I have:
users = User.where(:location => "Utopia") #=> Returns [user1,user2,user3,user4]
I would like do something like:
users.photos #=> Returns all photos this group of users has
And simply get all the photos back without iterating over them. I ask because each iteration is a DB call. Is there any good way that does a single DB call?
The most straightforward way to do this is to use the eager loader:
users = User.where(:location => 'Utopia').includes(:photos)
That will fetch the users in one pass, then the relationships and their associated photos in another. You can wrap it all up into one call if you either use a JOIN or a subselect, it's your call, but it'll look something like this:
photos = Photo.includes(:user).where('users.location' => 'Utopia')
There's more information available in the Active Record Query Interface documentation in section 12.

Rails using a variable find condition

I am using Braintree for managing subscriptions in my Rails app.
I have a Subscription model that stores the braintree customer ID and subscription ID.
I want to filter active subscriptions in my Subscription model. So far I have
def find_active_subscriptions
#active_subscriptions = Braintree::Subscription.search do |search|
search.status.is "Active"
end
But now I want to use the subscription IDs in #active_subscriptions to find all of the objects in my local Subscription model with the same subscription IDs and put that into a variable such as #local_active_subscriptions.
The reason I have to do this is to use the local info to access Braintree::Address and only pull active addresses.
Thanks for the help.
One you have the #active_subscriptions you can collect all of the ids into an array and pass them right into the find method of your local Subscription model. I don't know what attributes you are using here, so I'm just making some guesses:
#active_subscription_ids = #active_subscriptions.collect(&:subscription_id)
#local_active_subscriptions = LocalSubscriptionModel.find(#active_subscription_ids)
I'm not sure what Braintree::Subscription.search returns, but if it's something akin to ActiveRecords, could you use something like:
#local_active_subscriptions = Subscription.where("id IN(?)", #active_subscriptions.map{ |act_subs| act_subs.id })
The .map function should put all the IDs into an array, and then ActiveRecord query would look for all the Subscriptions in your subscriptions table whose ID is in that array.
I'm not certain about mapping on Braintree::Subscriptions; I've never used that.
Edit
Like ctcherry said, you can also do the search with find. And I guess collect is good for mapping the ids into an array too. You could also maybe use #active_subscriptions.map(&:id)

Resources