Repopulate an accidentally deleted heroku db from console output - ruby-on-rails

I made a mistake and accidentally delete all records from Attachment model in production.
I could at least get all the records from the console output (I previously did a simple Attachment.all and get all records hash displayed on screen).
This is a sample of actual output:
=> [#<Attachment id: 50, shortcut: "1eo2", attachment_file_name: "tumblr_lbxifqK2LT1qa0qyy.jpg", attachment_content_type: "image/jpeg", attachment_file_size: 80960, attachment_updated_at: "2010-12-22 07:39:01", created_at: "2010-12-22 07:39:02", updated_at: "2011-03-07 02:14:05", post_id: nil, about_me: nil, is_nsfw: nil, attachable_id: nil, attachable_type: nil, is_default: nil, temp_token: nil, user_id: 1, description: nil, visits: nil>,
#<Attachment id: 51, shortcut: "1fp7", attachment_file_name: "tumblr_lbxig3Qzrg1qa0qyy.jpg", attachment_content_type: "image/jpeg", attachment_file_size: 75532, attachment_updated_at: "2010-12-22 08:04:00", created_at: "2010-12-22 08:04:01", updated_at: "2011-03-07 02:14:05", post_id: nil, about_me: nil, is_nsfw: nil, attachable_id: nil, attachable_type: nil, is_default: nil, temp_token: nil, user_id: 1, description: nil, visits: nil>,
#<Attachment id: 52, shortcut: "1ghq", attachment_file_name: "tumblr_lbh5dvOZMf1qa4bk9o1_500.jpg", attachment_content_type: "image/jpeg", attachment_file_size: 68396, attachment_updated_at: "2010-12-22 08:04:32", created_at: "2010-12-22 08:04:33", updated_at: "2011-03-07 02:14:05", post_id: nil, about_me: nil, is_nsfw: nil, attachable_id: nil, attachable_type: nil, is_default: nil, temp_token: nil, user_id: 1, description: nil, visits: nil>,
Question is how can I parse this log an put them again the database and there a way to also keep the original ID and avoid having a new one? (I got other relationships by ID with other models).

A quick and dirty way that you might be able to do it would be something similar to this:
1) Load all the console input into a string. Take off the brackets at the beginning/end (the square ones). Then, use this Regex to get the contents of each Attachment object:
#<Attachment (.*)>,
So, something like
consolestr.scan(/#<(Attachment .*)>,/).each do |attachment|
which should give you an array consisting of each Attachment object.
2) Split the properties of each Attachment object on comma to get the full property, then on colon to get the key value pair. Something like:
properties = {}
attachment.split(",").each do |property|
s = property.split(":")
key = s[0]
value = s[1]
properties[key] = value
end
3) Re-create the record:
Attachment.create(properties)
Unfortunately I'm not at a place where I can fully test this right now, but I think it should work in theory. You may have to do some additional tinkering with the value that you capture, such as removing the quotes on string values, as well. Hopefully this is at least one way that can get you started recovering that data. I'm sure you are very nerve racked right now!

If you're trying to get the database back to exactly where it was before you nuked it, your best option is to take the console output and transform it into raw SQL INSERT statements.
Creating the objects through a Rails console will re-assign the ID field, which will then break any existing object associations you've got.

Related

Update or save records from instance

Using Rails 4 with GraphQL API.
I'm getting some inputs via an object, based on which I'm finding or initializing new ActiveRecord objects that I want to save later.
Sample input is:
[
{:id=>"192", :internalId=>128, :title=>"Editing"},
{:internalId=>130, :title=>"New"}
]
As you can notice, some of the records already exist and have an ID, we need to update those. And the rest we need to save as new records.
Then I have a method that goes through those post values:
def posts=(value)
#posts = value.map do |post|
init_post(post)
end
end
def init_post(post)
Post.find_or_initialize_by(
id: post[:id],
title: post[:title],
internal_id: post[:internalId],
)
end
That will return two instances of the Post model:
[#<Post id: 192, title: "Editing", internal_id: 128, created_at: nil, updated_at: nil>, #<Post id: nil, title: "New", internal_id: 130, created_at: nil, updated_at: nil>]
Finally, I want to save both records:
def save_posts
posts.each(&:save)
end
Which will return:
"#<ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry '192' for key 'PRIMARY': INSERT INTO `posts` ..."
So how do I make sure the instances with ID just update the existing record, and the rest just save as new ones?
You can find, change/create and save it at once
Post.find_or_initialize_by(id: post[:id]).tap do |record|
record.title = post[:title]
record.internal_id = post[:internalId]
record.save
end

In minitest, how do I lookup an item from the database (as opposed to the fixtures definition)?

I'm using Rails 5 and minitest. In minitest, how do I lookup an object from the database by one of its attributes (e.g. not the fixtures designation for the object). In my test I have
item = items(:one)
,,, do some db manipulation to this object ...
Item.all.each do |i|
puts "#{i.inspect}"
end
updated_item = Item.find(id: item.id)
But the line
updated_Item = Item.find(id: item.id)
dies with the error
ActiveRecord::RecordNotFound: Couldn't find Item with 'id'={:id=>980190962}
What is odd is taht in the lines above, where I print out the records in my database, I can see the object in question with the ID that Rails claims not to find ...
#<Item id: 298486374, name: "MyString", rating: 0, score: 0, created_at: "2018-01-19 20:25:05", updated_at: "2018-01-19 20:25:05">
#<Item id: 980190962, name: "Item1", rating: 1, score: 5, created_at: "2018-01-19 20:25:05", updated_at: "2018-01-19 20:25:05">
What am I doing wrong? How do I lookup the updated object?
find() looks by id , no need to tell, so:
updated_Item = Item.find(item.id)

carrier wave uploaded image should not exist but does in rails

I have a model called "Profile" and one of the attributes is called "pic". In the console, when I do:
User.first.profile
The following is returned.
=> #<Profile id: 64, created_at: "2014-06-19 15:59:41",
updated_at: "2014-06-19 15:59:41", user_id: 24,
description: "fds aslkjd aslkfjhas dlkjashdf lajkdshf al...",
rate: nil, pic: nil >
As you can see, the "pic" attribute is nil because I never uploaded a picture. I am trying to write several "if statements" to distinguish whether or not the picture exists. For example:
#profile = User.find(24).profile.first
if #profile.pic
I've also tried:
#profile = User.find(24).profile.first
if #profile.pic.exists?
All of these evaluate to true, which should not happen since a picture has never been uploaded.
I've also tried:
#profile = User.find(24).profile.first
if #profile.pic.nil?
and for some reason that evaluates to false.
When I run in the console:
=> #<PicUploader:0x007ff8abeb8560 #model=#<Profile id: 64,
created_at: "2014-06-19 15:59:41", updated_at: "2014-06-19 15:59:41",
user_id: 24, description: "fds aslkjd aslkfjhas dlkjashdf lajkdshf al...",
rate: nil, pic: nil>, #mounted_as=:pic>
I don't know where that is coming from. How do I write an "if statement" for whether or not the image exists that will actually return false like it should?
Thanks.
With carrierwave, you should use either the question-method of your attribute, pic?, or you can use blank?/present?:
#profile.pic.present?
# => false
#profile.pic?
# => false
#profile.pic.blank?
# => true

How get array item correctly?

I have this request to database
#show = Question.where(:question_status => params[:id])
Then in #show variable I have this: [#<Question id: 38, user_id: 1, question: "hi", question_status: 1, created_at: "2013-06-04 18:32:28", updated_at: "2013-06-04 18:32:28">, #<Question id: 40, user_id: 1, question: "urll", question_status: 1, created_at: "2013-06-04 18:34:57", updated_at: "2013-06-04 18:34:57">, #<Question id: 41, user_id: 1, question: "urll", question_status: 1, created_at: "2013-06-04 18:35:31", updated_at: "2013-06-04 18:35:31">]
How get , for example, question field ?
I trying #show.question but have error no defined method question.
#show = Question.find_by_question_status(params[:id])
and #show.question
If you us where statement then use:
#show.each do |show|
show.question
end
#show is an ActiveRecord::Relation object(Array). It does not belong to Question class.
#show = Question.where(:question_status => params([:id]).first
if you are expecting only one result. Otherwise you have to iterate the array for each element
You want to take an array of all question fields?
questions = Question.where(:question_status => params[:id]).map(&:question)
Then you can simply go like
questions.each{|question| puts question }
Try this code at your rails console
#show = Question.where(:question_status => params[:id])
#show.each_with_index do |ques, index|
p "#{index+1} :: #{ques.question}"
end
With the help of index, you will get the sequence number of rows.
Use #show.map(&:question) . This will give you all the questions in array.
#show.question gives you error no defined method question because you are trying to operate question on array #show.
If you do #show.first.question it will give you question of first object.
And
If you do #show.map(&:question) it will give you array of question.
To get all the information.
#show.each do |show|
puts show.question
puts show.question_status
puts show.user_id
end
You can optimize it as per you requirement.

rails Model.create(:attr=>"value") returns model with uninitialized fields

This is really stumping me. The process works fine if I go about it with #new and then #save, but #create returns a model instance with all the fields set to nil.
e.g:
Unexpected behavior:
ruby-1.9.2-p0 > EmailDefault.create(:description=>"hi")
=> #<EmailDefault id: nil, description: nil, created_at: nil, updated_at: nil>
Expected behaviour:
ruby-1.9.2-p0 > e = EmailDefault.new
=> #<EmailDefault id: nil, description: nil, created_at: nil, updated_at: nil>
ruby-1.9.2-p0 > e.description = "hi"
=> "hi"
ruby-1.9.2-p0 > e.save
=> true
ruby-1.9.2-p0 > EmailDefault.last
=> #<EmailDefault id: 4, description: "hi", created_at: "2011-02-27 22:25:33", updated_at: "2011-02-27 22:25:33">
What am I doing wrong?
--update--
Turns out I was mis-using attr_accessor. I wanted to add some non-database attributes, so I did it with:
attr_accessible :example_to, :cc_comments
which is wrong, and caused the situation #Heikki mentioned. What I need to do is:
attr_accessor :example_to, :cc_comments
You need to white list those properties with attr_accessible to enable mass-assignment.
http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html#method-i-attr_accessible
--edit
By default all attributes are available for mass-assignment. If attr_accessible is used then mass-assignment will work only for those attributes. Attr_protected works the opposite way ie. those attributes will be protected from mass-assignment. Only one should be used at a time. I prefer the white listing with attr_accessible.

Resources