Get index of database iteration on ruby - ruby

I'm trying to iterate through database file with gdbm, create objects with values I get and assign them to an array. The problem is I can't seem to get index of iteration and I need it for my array. Here is the code:
bots_directory = "../data/bots.db"
bots = Array.new
GDBM.new(bots_directory).each_pair.with_index do |nickname, password, index|
bots[index] = Bot.new(nickname, password)
end
Error I get:
`[]=': no implicit conversion from nil to integer (TypeError)
Also, will database file close after the block is executed?

I would use each_with_index instead of each_pair.with_index:
bots_directory = "../data/bots.db"
bots = []
GDBM.new(bots_directory).each_with_index do |(nickname, password), index|
bots[index] = Bot.new(nickname, password)
end
Or even simpler, since the index starts from 0 and increases by 1 anyway:
bots_directory = "../data/bots.db"
bots = []
GDBM.new(bots_directory).each_pair do |nickname, password|
bots << Bot.new(nickname, password)
end
Perhaps map is also an option?
bots_directory = "../data/bots.db"
bots = GDBM.new(bots_directory).map do |nickname, password|
Bot.new(nickname, password)
end

Related

How should I check passwords in Ruby?

I am using Ruby to manage users in a database.
I am using pass = Digest::MD5.hexdigest() to encrypt passwords before they are being added to the database.
I need to create a function to check that a given password matches that stored in the database but I'm not sure how I should do it.
Do I use pass = Digest::MD5.hexdigest() on the user provided password, and then check that against what is returned from the database?
This is correctpassword?:
def correctpassword?(nick, pass)
user = nick
pass = Digest::MD5.hexdigest(pass)
db = SQLite3::Database.new "database.db"
db.execute("SELECT * FROM t1 WHERE user = ? and pass = ?", user, pass)
!results.empty?
end
This is attempting to use correctpassword?:
if clt.registered?(#nick)
if clt.correctpassword?(#nick, #pass)
sv_send 'NOTICE', #nick, ":Correct password."
else
sv_send 'NOTICE', #nick, ":Incorrect password."
end
end
I don't see either notices. Using correctpassword? seems to break things.
This works though:
if clt.registered?(#nick)
sv_send 'NOTICE', #nick, ":This account is registered."
end
There is no assignment for results var. Do results = db.execute("SELECT * FROM t1 WHERE user = ? and pass = ?", user, pass)
MD5 is a one-way hash encryption algorithm. There is no way to directly decrypt a MD5 hash. The algorithm itself uses modular arithmetic to package the serialized string and there is no way to go backwards from that.
So I think you should convert the password to MD5 which user try to enter and compare that hash with stored encrypted password in db.
Eg:
> stored_password_in_db = Digest::MD5.hexdigest('gagan')
#=> "cc18a19beff0bdf874861a4dae6124b6"
> user_enter_password_for_login = Digest::MD5.hexdigest('gagan')
#=> "cc18a19beff0bdf874861a4dae6124b6"
> stored_password_in_db == user_enter_password_for_login
#=> true
> user_enter_password_for_login = Digest::MD5.hexdigest('Gagan')
#=> "f52bb23033354697e8f55abdaed9d94f"
> stored_password_in_db == user_enter_password_for_login
#=> false

Dynamically check if a field in JSON is nil without using eval

Here's an extract of the code that I am using:
def retrieve(user_token, quote_id, check="quotes")
end_time = Time.now + 15
match = false
until Time.now > end_time || match
#response = http_request.get(quote_get_url(quote_id, user_token))
eval("match = !JSON.parse(#response.body)#{field(check)}.nil?")
end
match.eql?(false) ? nil : #response
end
private
def field (check)
hash = {"quotes" => '["quotes"][0]',
"transaction-items" => '["quotes"][0]["links"]["transactionItems"]'
}
hash[check]
end
I was informed that using eval in this manner is not good practice. Could anyone suggest a better way of dynamically checking the existence of a JSON node (field?). I want this to do:
psudo: match = !JSON.parse(#response.body) + dynamic-path + .nil?
Store paths as arrays of path elements (['quotes', 0]). With a little helper function you'll be able to avoid eval. It is, indeed, completely inappropriate here.
Something along these lines:
class Hash
def deep_get(path)
path.reduce(self) do |memo, path_element|
return unless memo
memo[path_element]
end
end
end
path = ['quotes', 0]
hash = JSON.parse(response.body)
match = !hash.deep_get(path).nil?

cassandra Ruby : multiple values for a block parameter (2 for 1)

I am trying to follow a tutorial on big data, it wants to reads data from a keyspace defined with cqlsh.
I have compiled this piece of code successfully:
require 'rubygems'
require 'cassandra'
db = Cassandra.new('big_data', '127.0.0.1:9160')
# get a specific user's tags
row = db.get(:user_tags,"paul")
###
def tag_counts_from_row(row)
tags = {}
row.each_pair do |pair|
column, tag_count = pair
#tag_name = column.parts.first
tag_name = column
tags[tag_name] = tag_count
end
tags
end
###
# insert a new user
db.add(:user_tags, "todd", 3, "postgres")
db.add(:user_tags, "lili", 4, "win")
tags = tag_counts_from_row(row)
puts "paul - #{tags.inspect}"
but when I write this part to output everyone's tags I get an error.
user_ids = []
db.get_range(:user_tags, :batch_size => 10000) do |id|
# user_ids << id
end
rows_with_ids = db.multi_get(:user_tags, user_ids)
rows_with_ids.each do |row_with_id|
name, row = row_with_id
tags = tag_counts_from_row(row)
puts "#{name} - #{tags.inspect}"
end
the Error is:
line 33: warning: multiple values for a block parameter (2 for 1)
I think the error may have came from incompatible versions of Cassandra and Ruby. How to fix it?
Its a little hard to tell which line is 33, but it looks like the problem is that get_range yields two values, but your block is only taking the first one. If you only care about the row keys and not the columns then you should use get_range_keys.
It looks like you do in fact care about the column values because you fetch them out again using db.multi_get. This is an unnecessary additional query. You can update your code to something like:
db.get_range(:user_tags, :batch_size => 10000) do |id, columns|
tags = tag_counts_from_row(columns)
puts "#{id} - #{tags.inspect}"
end

Ruby array.each Returning Same Value Each Time

I'm designing a REST API with Ruby and Sinatra. Only one problem I'm having:
I'm trying to iterated over an array of posts selected from MySQL.
The format is
[{:post => "Hello, world!", :comments => [{:author => "user1", :content => "Goodbye, world!"}]}, ...]
So, it's an array with a hash with the content post and comments, and the comments key has another array and hash(es) containing the author and content of the comment.
I have the following code pulling an array of posts from MySQL (returned in an array with hashes in it), and then iterating over those hashes. For each hash in the array, it gets the post ID and queries MySQL for any comments associated with that post. It then pushes the post and the comments to a hash, which is the pushed to an array that is returned.
def get_post(id = 'null', profile = 'null', owner = 'null')
r = Array.new
x = Hash.new
p = self.query("SELECT * FROM `posts` WHERE `id` = '#{id}' OR `post_profile` = '#{profile}' OR `post_owner` = '#{owner}'")
p.each do |i|
x[:post] = i
x[:comments] = self.query("SELECT * FROM `comments` WHERE `post` = '#{i["id"]}'")
r.push(x)
end
return r
end
The odd thing is is that I can use a puts statement in the loop, and I'll get the individual posts
Ex:
r.push(x)
puts x
But the array (r) just contains the same data over and over again. Sorry for such a long post, I just wanted to be thorough.
You keep pushing the same Hash instance onto the array, rather than creating new hashes. Try this:
def get_post(id = 'null', profile = 'null', owner = 'null')
p = self.query("SELECT * FROM `posts` WHERE `id` = '#{id}' OR `post_profile` = '#{profile}' OR `post_owner` = '#{owner}'")
p.map do |i|
{
post: i,
comments: self.query("SELECT * FROM `comments` WHERE `post` = '#{i["id"]}'")
}
end
end
What this does is loop through the posts (with map rather than each, as I'll explain in a moment), and for each posts, returns a new hash consisting of your desired data. The map method collects all the return values from the loop into an array, so you don't have to do any manual array management.

`[]': can't convert String into Integer (TypeError) Ruby

I am trying to iterate over a JSON parsed hash table (that has nested Array's of hashes) and insert into a Text Table . The JSON parsed code that I am trying to iterate over is:
{"server"=>{"security_groups"=>[{"name"=>"default"}], "adminPass"=>"LhXEPMkYmqF7", "id"=>"82b7e32b-f62b-4106-b499-e0046250229f", "links"=>[{"href"=>"http://10.30.1.49:8774/v2/89fc0b9d984d49fba5328766e923958f/servers/82b7e32b-f62b-4106-b499-e0046250229f", "rel"=>"self"}, {"href"=>"http://10.30.1.49:8774/89fc0b9d984d49fba5328766e923958f/servers/82b7e32b-f62b-4106-b499-e0046250229f", "rel"=>"bookmark"}], "OS-DCF:diskConfig"=>"MANUAL"}}
The code I am using to iterate over the top is:
server_table = Text::Table.new do | t |
t.head = ['Server ID', 'Server URL', 'Admin Password']
end
response = JSON.parse(r)
response['server'].each do | serv_info |
server_table.rows << [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]
end
puts server_table
I am getting the error:
/lib/get_token.rb:166:in `[]': can't convert String into Integer (TypeError)
from ./lib/get_token.rb:166:in `create_server'
from ./lib/get_token.rb:165:in `each'
from ./lib/get_token.rb:165:in `create_server'
If I individually use puts to print out each command they work fine, but the iteration does not. The commands that pull the correct info are:
puts response['server']['links'][0]['href']
puts response['server']['id']
puts response['server']['adminPass']
All 3 of those work, but if I try and iterate over them I get the string error. I know it has something to do with .each returning an Array of hashes but I do not fully understand why the PUTS command is working without issue in the script and also in IRB.
Any thoughts?
Each serv_info is a pair of a map represented as an array of 2 elements. Therefore everything after << in your code is just wrong.
The secret to avoid such mistakes is to stop trying to obfuscate your own code.
server_table.rows should contain all possible triples of server ID, link and a password.
response = # { "server" => ...}
server = response['server']
server_id = server['id']
link_infos = server['links']
admin_pass = server['adminPass']
link_infos.each do |link_info|
link = link_info['href']
server_table.rows << [server_id, link, admin_pass]
end
Update
We can easily use this code to process multiple servers
response = # [ {"server" => ...}, ...]
response.each do |server|
... # above code snippet goes here
# or you may extract it into a method and call it here
end
Also I want to mention that irb is really great for dealing with this kind of problems. It is a command line Ruby interpreter and it's great for prototyping. It prints out result of each statement you type and has an autocompletion to help you find required classes/methods. Instead of waiting several hours to get an SO answer to simple question you will get it using irb in a couple of minutes.
Perhaps you mean just
serv_info = response['server']
server_table.rows << [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]
Since response['server'] is a hash not an array.
Instead of using:
server_table.rows << [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]
Try:
server_table.rows += [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]
Or:
server_table.rows << ["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]

Resources