Rails 5.0.2 - ID in relation belongs_to/has_many - ruby-on-rails

I am new on RAILS, so don't hit me.
I consider such problem:
- author
has_many :books
- book
belongs_to :author
In console I create a new author, per example:
ar = Author.new(fname: "Frank", lname: "Herbert")
ID of this record is not set before save.
Then I create some books from object ar:
ar.books.new(title: "Dune"), ar.books.new(title: "The Green Brain")
No errors. But when I list books:
ar.books.all
got an empty list.
I figured out that first I have to save ar, and then I can add books.
Is there a way to save ar with books, no need saving ar without books before?

Sure you can!
You need to call ar.books to look up for books that you have added. When you call ar.books.all ActiveRecord tries to find something in database (obviously it returns empty array). So just:
author = Author.new(fname: "Frank", lname: "Herbert")
author.books.build(title: "Dune")
author.save
It will save author & books as you expect. By the way use build method instead of new. In this way you show that you are going to create record soon.

Follow below code:
First create Author and then create books with author as foreign key.
ar = Author.new(fname: "Frank", lname: "Herbert")
ar.save
ar.books.create(title: "Dune")
ar.books.create(title: "The Green Brain")
OR
ar = Author.new(fname: "Frank", lname: "Herbert")
ar.books.build(title: "Dune")
ar.books.build(title: "The Green Brain")
ar.save

Related

How do I update one of model having relation each other?

I try to update 2 model with following steps.
Article
id
current_version
status
ArticleHistory
id
article_id
title
content
version
These models have relationship with article_id and current_version = version.
First, we made one record like this.
article.id:1
article.current_version:1
article.status:public
article_history.id:1
article_history.title:"test title"
article_history.content:"test content"
article_history.version:1
And I'm going to update like this. Before that, I'd like to copy existing ArticleHistory record with new id. I mean, it's like renewing ArticleHistory.
article.id:1
article.current_version:2
article.status:public
(copied)article_history.id:2
(copied)article_history.title:"updated test title"
(copied)article_history.content:"updated test content"
(copied)article_history.version:2
But now, I can't figure out how to express by RoR ActiveRecord.
After this modification, Article has got multiple record.
Give me advise, please.
class Article
has_many :article_histories
should do the trick. If you need more, the doco for has_many is here:
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many
If this is not suitable - then please tell us why it doesn't work for you :)
To copy...
# first find the article_history with the highest version for this article
latest_history = article.article_histories.order(:version).last
# if there isn't one, create a new one
if latest_history.blank?
new_history = article.article_histories.new(params[:article_history])
new_history.version = 1
else
# Otherwise... merge params and the old attributes
combined_attributes = latest_history.attributes.merge(params[:article_history])
# and use that to create the newer article_history version
new_history = article.article_histories.build(combined_attributes)
new_history.version = latest_history.version + 1
end
new_history.save!
Note: this code is just to give you an idea of how it could be done.
You will need to bugfix it and make it actually work yourself.

Using Wikipedia-Client Gem to Update Rails Database

My ruby and Rails is a bit rusty. I have a table in my database called institutes which has some of the columns filled. I want to use the Wikipedia-Client gem to fill some of the others. I want to use the name attribute to find the page on Wikipedia then use page.summary for the description attribute in my table and page.image_urls.first for the picture attribute. At the moment, I'm struggling to work out how I would go about this.
My current code is:
require 'Wikipedia'
Institute.each do |institute|
school = institute.pluck(:name)
page = Wikipedia.find(school)
description = page.summary
picture = page.image_urls.first
Institute.update!(description: description, picture: picture)
end
I'm clearly doing something wrong here to do with the selection and use of the name attribute to find the Wikipedia page, but can't quite work it out. I think even if I were to pluck the name correctly, it wouldn't assign anything to the right id.
If there's also a way to drop the "The" at the beginning of the name in the Wikipedia search if it exists in :name, that would also be helpful as it seems some institutes drop this on Wikipedia.
You can try to use something like this:
#use https://github.com/kenpratt/wikipedia-client
require 'wikipedia'
#select all Institutes through AR model
Institute.all.each do |institute|
#'institute' is an object, so we can get its name by dot operator
school = institute.name
#try to find school as is
#then try to find without 'The'
#and go ahead only if page exists
page = Wikipedia.find(school)
page = Wikipedia.find(school[3..-1].strip) if page.content.nil? and school[0..2].downcase == 'the'
next if page.content.nil?
description = page.summary
picture = page.image_urls.first
#update Institute object
institute.update!(description: description, picture: picture)
end

Rails ActiveRecord hash condition

I really don't understand some tutorial code despite running the equivalents of it on a console (which don't work) and there's no explanation.
This comes from the Rails guides and I really like to understand everything that I read
Article.where(author: author)
Author.joins(:articles).where(articles: { author: author })
The (author: author) part is where I get lost. I mean does it do a self join? If that's the case I can't do it on my console with the same syntax.
And if author: author means articles.author and Author.author (which would be weird because ambiguity.
Thanks, sorry if this has been posted before.
Article.where(author: author)
^- Select Article records by the given author.
Select Article records where the author_id (probably) column equals the "id of author". Now author (after the :) could be a local variable or it could be a method call returning an 'author' object. Either way, it's probably an instance of an Author model class that responds to an id method call.
Author.joins(:articles).where(articles: { author: author })
^- Select Author records for authors that have an Article. Again the author here (after the :) is a local variable or a method call. The articles: { author: author } is just a convenient way to put some criteria on the join.
Once you get the correct author variable sorted, add a .to_sql to the end of the method call chain in your console to see what SQL is being generated. That should help you understand what's going on.

saving and updating on serialized column

Apologies in advance for the ugly code (in addition to it not working).
I have a Rails app that has many users who play different quiz games, which were created by various users. There is no rails-style association between user and quizes except that each quiz has been made by a particular user. There's actually not even a 'quiz' model in the application (quizes are made of question and answer models).
For obvious reasons, users are only allowed to try each quiz once; therefore, I have to record which users' quizers a particular user has tried. Therefore, I created a 'quiz' attribute on the user model, and serialized it, so that I would hopefully have a database column like this ['2','4','10'] if I had played the quizes that were made by users with ids 2,4 and 10.
In the user model, after creating :quiz as a 'string', I did this to turn the string into an array in the db
attr_accessible :quiz
serialize :quiz
However, I'm having a lot of trouble writing code that does all of the following
a) checks if that column's not empty (maybe the player hasn't played a quiz yet): I did player.quiz? to test that.
b) checking whether the array includes a particular user.id (i.e. if the player has already played that quiz) I do player.quiz.include?(user.id.to_s) to test that
c) creating the first entry if a user hasn't played any quizzes yet. I did quiz = user.id.to_s
d) adding to the array of game's once a user's played a second user's game (i.e. player's quiz column is ['2'] and now they play quiz by user.id 4.
With various combinations of the code below, I keep erasing/resetting the quiz column when I try to update, or I'm creating strings like '68' when I want ['6','8'] instead.
I'd be grateful if you could give me some tips to fix this up.
code not working
if player && player.quiz? && player.quiz.include?(user.id.to_s) #checks if signed in (if player), if the player.quiz column isn't empty, and if it includes a user id
alreadyplayedthisquiz = true
else
if player.quiz? #it might be that no quizzes are registered on db
quiz = player.quiz #this is a string
quiz.push(user.id.to_s) #can't push onto a string
quiz += user.id.to_s #this is wrong, because if I've played quiz 6 and 8, it'll be '68' in the db
else
quiz = user.id.to_s #if no quiz on player's db, create first one
end
alreadyplayedthisquiz = false
end
player.update_attributes({quiz: quiz})
First, I would store the values in the database as "2","4","6" rather than as ["2","4","6"]. The [ and ] are not necessary.
I would use the String#split to convert the string in the database to an array that can be used in the code. I would use Array#join to convert the array used in the code back into a string for storage in the database.
quiz = player.quiz? ? player.quiz.split(",") : []
alreadyplayedthisquiz = quiz.include? user.id.to_s
if (!alreadyplayedthisquiz)
quiz.push user.id.to_s
player.update_attributes({:quiz => quiz.join(",")})
end

how to store facebook friends to DB (newbie)

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

Resources