Ruby PostgreSQL tutorials [closed] - ruby

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I am trying to write a ruby script that interacts with a PostgreSQL database. I am trying to piece together how to do this from the documentation, but a nice tutorial or sample code would work wonders to decrease the amount of time to get this working. If anyone has a link, some tips or has some code they could share I would be most grateful.
Edit, made this note more clear:
Note: this isn't to do with rails ActiveRecord, I am writing a Ruby script that will be involved in a program that is completely independent from Rails.

Please be more specific about what postgresql library you're using.
I'm going to assume the 'pg' gem, apart from ActiveRecord.
The project source has an html file that might be helpful.
Go to https://bitbucket.org/ged/ruby-pg/src/b477174160c8/doc/postgres.html
Then click "raw" at the upper right side of the html. Open the file in your web browser.
This sample code helps you connect (copied from the html file):
require "postgres"
conn = PGconn.connect("localhost", 5432, "", "", "test1")
# or: conn = PGconn.open('dbname=test1')
res = conn.exec("select * from a;")
The res object is a PGResult. Scroll down to that section in the html to see what methods you can call.
This link has a PGResult example:
http://rubydoc.info/gems/pg/0.10.0/PGresult
Excerpt:
require 'pg'
conn = PGconn.open(:dbname => 'test')
res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
res.getvalue(0,0) # '1'
res[0]['b'] # '2'
res[0]['c'] # nil

I confirm, "postgres" package is outdated, you need "pg".
It tooks me lot of time just to get a basic select * from films working with ruby and postgres. As I am kind, here is my code:
postgres preparation (database=megatest user=roger pass=123456 table=films)
$ su postgres
psql
CREATE USER roger WITH PASSWORD '123456';
GRANT ALL PRIVILEGES ON DATABASE megatest to roger;
megatest=# GRANT SELECT ON films TO PUBLIC;
PG package preparation
sudo gem install pg
Ruby Code
require 'pg'
conn=PGconn.connect( :hostaddr=>"127.0.0.1", :port=>5432, :dbname=>"megatest", :user=>"roger", :password=>'123456')
# or for a non IP address :host => 'my.host.name.com' instead of hostaddr
# run the query
res = conn.exec("SELECT * FROM films")
# Ran only once in order to get field Name
fieldArray=res.fields()
fieldArray.each do |elem|
print "elem="+elem+"\n"
end
# print data from the query
res.each{ |row|
puts "Code="+row["code"] +" title="+row["title"] +" did="+row["did"] +" date_prod="+row["date_prod"] +" kind="+row["kind"] +" len="+row["len"]
}
Results
root#eblain-VirtualBox:/home/eblain/ruby# ruby postgresTest.rb
Code=UA502 title=Bananas did=105 date_prod=1971-07-13 kind=Comedy len=01:22:00
Code=UA503 title=Cowboy did=105 date_prod=1979-07-13 kind=Horror len=01:32:00
Code=UA544 title=YoBro did=105 date_prod=1981-07-13 kind=Action len=01:42:00

You only need to require the pg gem and establish the connection to the DB:
require 'pg'
# require 'active_record' # uncomment for not Rails environment
ActiveRecord::Base.establish_connection(:adapter => "postgresql",
:username => "username",
:password => "password",
:database => "database")
When you define models to inherit from ActiveRecord::Base they will use this database connection. Everything else should work like it does in Rails.

For parametrized SQL statements, you should use PGconn#exec_params, e.g.
conn = PGconn.new(:dbname => 'test')
conn.exec_params(
'INSERT INTO comedians (first_name, last_name) VALUES ($1, $2)',
['Louis', 'CK'])
conn.close
Source: http://deveiate.org/code/pg/PGconn.html
Look here for a complete list of parameters that can be passed to the PGconn constructor.

Related

ruby, postgres ,compare data from two tables coming from two databases

we have a database legacy from a SQL SERVER, and now the new database is a postgres, I would like to do some testing to see if the content is the same from both tables, sinnce I still don't have acess to the legacy database (SQL server), I said let play with the new postgres database by polling two table and try to compare the data, in the iteration loop I got confused, any idea will be helpful :
require 'pg'
pg_conn = PGconn.connect("localhost", 5432, '', '', "myDB", "userxx", "Zazzz")
all_children = pg_conn.exec("SELECT * from COMPANY;")
all_children2 = pg_conn.exec("SELECT * from COMPANY2;")
all_children.each do |child|
??????
end
Thanks,
The quick and dirty way would be to do a fast checking on one column, for example the name of the companies and compare the results to see the differences by substracting the resulting arrays :
require 'pg'
pg_conn = PGconn.connect("localhost", 5432, '', '', "myDB", "userxx", "Zazzz")
all_children = pg_conn.exec("SELECT name from COMPANY;")
all_children2 = pg_conn.exec("SELECT name from COMPANY2;")
# first check the count, if it's the same it's probably a good sign
puts all_children.length
puts all_children2.length
# check differences
results = all_children.uniq - all_children2.uniq
results2 = all_children2.uniq - all_children.uniq
For more complex tests you can maybe use the scientist gem from github : https://github.com/github/scientist
Edit:
sql version ?
select * from company left outer join company2 on company.name = company.name2 where company2.name is null;

Ruby : SoftLayer API : getPendingEvents fails to show many relational properties

I'm trying to make a softlayer API call using Ruby to see upcoming maintenance and the machines that may be effected by the maintenance. I have a few questions but I'm running into an issue seeing many of the relational properties documented here:
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Notification_Occurrence_Event
Here is my simple program:
require 'rubygems'
require 'softlayer_api'
require 'pp'
client = SoftLayer::Client.new(:username => user, :api_key => api_key, :timeout => 99999999)
account = client['Account'].object_mask("mask[pendingEventCount]").getObject()
pending_event_count = account["pendingEventCount"]
current_time = Time.now.to_i
for i in 0..(pending_event_count/30.0).ceil - 1
list_of_pending_events = client['Account'].result_limit(i*30,30).object_mask("mask[id, startDate, endDate, recoveryTime, subject, summary]").getPendingEvents
for x in 0..list_of_pending_events.length - 1
start_time = DateTime.parse(list_of_pending_events[x]['startDate']).to_time.to_i
if start_time > current_time
pp list_of_pending_events[x]
end
end
end
The above works, but if I try to add a relational property to the mask, such as "impactedResources" it will fail saying that property does not belong to SoftLayer_Notification_Occurrence_Event. Can someone help explain why this, and many other, relational properties are not valid in the above call?
Also, two quick other questions on this topic:
1) Why do some of the results in getPendingEvents have start AND end times in the past? And why do some have a missing end time altogether? Notice I'm checking if the start time is greater than the current time as there seems to be old maintenance data in the results.
2) Am I taking the right approach for getting upcoming maintenance and figuring out machines that will be impacted? (Using getPendingEvents and then the 'impactedResources' property)
I used your code and I added the "impactedResources" to the object mask and it worked fine. You may be getting the issue, because your API user does not have enough permissions, I recomend you try with the master user.
regarding to your other questions:
1.- When I ran your code I got only 3 events whose startDate is greater than the current time, so it worked fine for me. If you still are getting that issue you can try using objectFilters.
require 'rubygems'
require 'softlayer_api'
require 'pp'
client = SoftLayer::Client.new(:username => user, :api_key => apikey, :timeout => 99999999)
object_filter = SoftLayer::ObjectFilter.new
object_filter.set_criteria_for_key_path('pendingEvents.startDate', 'operation' => 'greaterThanDate',
'options' => [{
'name' => 'date',
'value' => ['9/8/2016']
}])
list_of_pending_events = client['Account'].object_filter(object_filter).object_mask("mask[id, startDate, endDate, recoveryTime, subject, summary]").getPendingEvents
pp list_of_pending_events
2.- Yes, that approach wil work.
Regards

Create Postgresql database in Heroku with Ruby (without Rails)

I'm currently hosting a simple Ruby script that stores URLs and Scores and saving them to YAML. However, I'd like to save to a Postgresql database instead since the yaml file is deleted every time I restart the app. Here's the error I'm getting in Heroku:
could not connect to server: No such file or directory (PG::ConnectionBad)
Here's an example script that works locally, but throws me the above error in Heroku:
require 'pg'
conn = PG.connect( dbname: 'template1' )
res1 = conn.exec('SELECT * from pg_database where datname = $1', ['words'])
if res1.ntuples == 1 # db exists
# do nothing
else
conn.exec('CREATE DATABASE words')
words_conn = PGconn.connect( :dbname => 'words')
words_conn.exec("create table top (url varchar, score integer);")
words_conn.exec("INSERT INTO top (url, score) VALUES ('http://apple.com', 1);")
end
Thanks in advance for any help or suggestions!
Assuming you have created a Postgres database using the Heroku toolchain via heroku addons:add heroku-postgresql:dev (or the plan of your choice) you should have a DATABASE_URL environmental variable that contains your connection string. You can check that locally through heroku pg:config.
Using the pg gem (docs: http://deveiate.org/code/pg/PG/Connection.html) - and modifying the example from there to suit -
require 'pg'
# source the connection string from the DATABASE_URL environmental variable
conn = PG::Connection.new(ENV['DATABASE_URL'])
res = conn.exec_params('create table top (url varchar, score integer;")
Update: A slightly more complete example for the purposes of error handling:
conn = PG::Connection.new(ENV['TEST_DATABASE_URL'])
begin
# Ensures the table is created if it doesn't exist
res = conn.exec("CREATE TABLE IF NOT EXISTS top (url varchar, score integer);")
res.result_status
rescue PG::Error => pg_error
puts "Table creation failed: #{pg_error.message}"
end

Using prepared statement with MySQL2 gem?

How do I create prepared statements for insert and select queries in MySQL? I am using the MySQL2 gem, and my connection object looks like this:
con = Mysql2::Client.new(:host => "#{ENV['DB_HOST']}", :port => '3306', :username => "#{ENV['DB_UNAME']}", :password => "#{ENV['DB_PWD']}", :database => 'dbname')
Unfortunately, mysql2 gem does not have prepared statement support yet. The contributors are planning to add such a feature in a near future, as we can see by this Pull Request discussion:
https://github.com/brianmario/mysql2/pull/289
If you must have prepared statements in your application, I would recommend you to read about Sequel, which has a very nice support for prepared statements and bound variables:
https://github.com/jeremyevans/sequel
http://sequel.jeremyevans.net/rdoc/files/doc/prepared_statements_rdoc.html
UPDATE
As mentioned by #lulalala starting on version 0.4.0 MySQL2 gem supports prepared statements:
statement = #client.prepare("SELECT * FROM users WHERE login_count = ?")
result1 = statement.execute(1) # Binds the value 1 to the placeholder
result2 = statement.execute(2) # Binds the value 2 to the placeholder
statement = #client.prepare("SELECT * FROM users WHERE last_login >= ? AND location LIKE ?")
result = statement.execute(1, "CA") # Binds 1 and 'CA' to the placeholders, respectively
I hope that helps.
You may also use mysql2-cs-bind gem, a thin wrapper of mysql2 which adds prepared statement feature:
https://github.com/tagomoris/mysql2-cs-bind
It provides xquery method that accepts arguments for the statement:
require 'mysql2-cs-bind'
client = Mysql2::Client.new(...)
client.xquery('SELECT x,y,z FROM tbl WHERE x=? AND y=?', val1, val2) #=> Mysql2::Result

Enumerating settable parameters

I successfully setup a connection to my Rally project, but am not able to programatically set the "Submitted By" field when opening defects. I am misnaming the parameter, or it is not settable via the REST API. Any help on querying modifiable parameters, link to attribute names, or code to set the "Submitted By" parameter would be greatly appreciated.
My goal is to have a webpage where folks submit defects or stories, along with their email, and use that to populate their username in the "Submitted By" field. My current setup can open Stories and Defects but only anonymously since the second to last line has no effect.
I am using the Ruby API and the following is the ruby code that gets invoked when a user clicks on a button on the main page, which redirects them to localhost:4567/rally_defect where Sinatra is listening.
require 'rubygems'
require 'rally_rest_api'
require 'sinatra'
custom_headers = CustomHttpHeader.new
custom_headers.name = 'Mail 2 Rally'
custom_headers.version = '0.1'
custom_headers.vendor = 'Rally Software'
rally_server = 'https://rally1.rallydev.com/slm'
rally_username = <insert rally username>
rally_pwd = <insert rally password>
rally = RallyRestAPI.new(:base_url => rally_server,
:username => rally_username,
:password => rally_pwd,
:http_headers => custom_headers)
get '/rally_defect' do
rally.create(:defect, :name => "Test Defect",
:description => "This is a test",
:SubmittedBy => "test")
end
If you're getting started building this integration, I'd strongly recommend using rally_api instead of rally_rest_api.
rally_rest_api is in the process of being deprecated for a number of issues around performance and stability. There won't be any further development on rally_rest_api moving forward.
You can find documentation on rally_api here:
https://developer.help.rallydev.com/ruby-toolkit-rally-rest-api-json
rally_api does require Ruby 1.9.2 or higher.
rally_api's syntax is quite similar to rally_rest_api. The rally_api version of what you're attempting above would look something like the code sample below. Note that any "set-able" parameter can be set simply by including its name in the object hash and setting that to a value.
The best place to look for the Rally Webservices API object model, including Artifact attributes, allowed values, and whether they are write-able is the Webservices API documentation:
https://rally1.rallydev.com/slm/doc/webservice
When an attribute of a Rally Artifact is itself a Rally Object like a User, for example, either lookup the Object in Rally first (the example below does this), or, set the value to the REST URL reference to the object in Rally. For instance, if you know that user#company.com has ObjectID 12345678910 in Rally, then you can do:
user_ref = "/user/12345678910"
new_defect["SubmittedBy"] = user_ref
The code below shows the way to do a lookup into Rally to get the User object, given an email-formatted UserID, since I'm assuming you'll probably need to accomodate multiple different users.
require 'rubygems'
require 'rally_api'
require 'sinatra'
#Setting custom headers
headers = RallyAPI::CustomHttpHeader.new()
headers.name = 'Mail 2 Rally'
headers.vendor = "My Company"
headers.version = "0.1"
# Rally credentials
rally_username = <insert rally username>
rally_pwd = <insert rally password>
rally_server = 'https://rally1.rallydev.com/slm'
# Rally REST API config
config = {:base_url => rally_server}
config[:username] = rally_username
config[:password] = rally_pwd
config[:workspace] = "Workspace Name"
config[:project] = "Project Name"
config[:headers] = headers #from RallyAPI::CustomHttpHeader.new()
# New up rally connection config
#rally = RallyAPI::RallyRestJson.new(config)
# Lookup UserID for SubmittedBY
submitted_by_user_id = "user#company.com"
user_query = RallyAPI::RallyQuery.new()
user_query.type = :user
user_query.fetch = "ObjectID,UserName,DisplayName"
user_query.order = "UserName Asc"
user_query.query_string = "(UserName = \"#{submitted_by_user_id}\")"
# Query for user
user_query_results = #rally.find(user_query)
submitted_by_user = user_query_results.first
# Create the Defect
new_defect = {}
new_defect["Name"] = "Test Defect"
new_defect["Description"] = "This is a test"
new_defect["SubmittedBy"] = submitted_by_user
new_defect_create_result = #rally.create(:defect, new_defect)
puts "New Defect created FormattedID: #{new_defect_create_result.FormattedID}"

Resources