Creating sqlite dbs a la rails way, without execute() - ruby-on-rails

I have a controller like this:
def download_link
#It starts a background process to handle all these things
temp_file = Tempfile.new 'temp_file'
temp_sqlite_db = SQLite3::Database.new temp_file.path
temp_sqlite_db.execute("CREATE TABLE inspection (id INTEGER NOT NULL,desc VARCHAR(255));")
inspections = Inspection.a_heavy_query_that_doesnt_worths_to_wait_so_much_for_a_reply
# Some code inserting records and creating tables, with execute() too
# more code, compressing the db and sending an email with a download link to the zip file
end
Now, I would like to know if there's a way to replace the execute() function and maybe create the tables and save records like inspection.create(something) . Thanks in advance

If anyone needs something similar, this was my implementation:
# config/initializers/sql_returner.rb
module ActiveRecord
class Base
def sql_insert
if attributes_with_quotes.empty?
connection.empty_insert_statement(self.class.table_name)
else
"INSERT INTO #{self.class.quoted_table_name} " +
"(#{quoted_column_names.join(', ')}) " +
"VALUES(#{attributes_with_quotes.values.join(', ')});"
end
end
def self.sql_create
"CREATE TABLE #{table_name} (" +
" #{ self.columns.collect{ |column|
column_sql = " #{ column.name } #{ sql_type column } "
column_sql << " PRIMARY KEY " if column.primary
column_sql << " NOT NULL " unless column.null
column_sql
}.join(', ') } );"
end
private
def self.sql_type column
case column.type
when 'datetime', 'string'
'TEXT'
else
column.type.to_s
end
end
end
end
Then, if I need to create tables and insert records, taking the same code of the question as example, I must to run:
def download_link
temp_file = Tempfile.new 'temp_file'
temp_sqlite_db = SQLite3::Database.new temp_file.path
temp_sqlite_db.execute(Inspection.sql_create)
inspections = Inspection.a_heavy_query_that_doesnt_worths_to_wait_so_much_for_a_reply
insert = ""
inspections.each{ |insp|
insert << insp.return_insert_sql
}
#.....
end
For the first method sql_insert I took as example the create method code of ActiveRecord. I know that maybe some kittens died coding this implementation, but at least for me it works.

Related

Parsing the text file in ruby

My text file looks like this
VOTE 1168041805 Campaign:ssss_uk_01B Validity:during Choice:Antony CONN:MIG01TU MSISDN:00777778359999 GUID:E6109CA1-7756-45DC-8EE7-677CA7C3D7F3 Shortcode:63334
VOTE 1168041837 Campaign:ssss_uk_01B Validity:during Choice:Leon CONN:MIG00VU MSISDN:00777770939999 GUID:88B52A7B-A182-405C-9AE6-36FCF2E47294 Shortcode:63334
I want to get value of vote campaign validity choice for which I am doing this:
File.foreach('lib/data/file.txt') do |line|
line = line.tidy_bytes
begin
aline = line.match(/^VOTE\s(\d+)\sCampaign:([^ ]+)\sValidity:([^ ]+)\sChoice:([^ ]+)/)
unless aline.nil?
## do something
end
rescue Exception => e
raise " error: " + e.inspect
p line.inspect
next
end
end
Is there any better way for doing this for
aline = line.match(/^VOTE\s(\d+)\sCampaign:([^ ]+)\sValidity:([^ ]+)\sChoice:([^ ]+)/)
and getting aline[1] aline[2] aline[3] and aline[4]
You can use named captures to get a hash of results instead:
# use a freezed contant instead of making a new Regexp object for each line
REGEXP = /^VOTE\s(?<id>\d+)\sCampaign:(?<campaign>[^ ]+)\sValidity:(?<validity>[^ ]+)\sChoice:(?<choice>[^ ]+)/.freeze
File.foreach('lib/data/file.txt') do |line|
begin
matches = line.tidy_bytes.match(REGEXP)
hash = matches.names.zip(matches.captures).to_h
end
rescue Exception => e
raise " error: " + e.inspect
p line.inspect
next
end
end
If the desired result is an array you might want to use .map:
# use a freezed contant instead of making a new Regexp object for each line
REGEXP = /^VOTE\s(?<id>\d+)\sCampaign:(?<campaign>[^ ]+)\sValidity:(?<validity>[^ ]+)\sChoice:(?<choice>[^ ]+)/.freeze
results = File.foreach('lib/data/file.txt').map do |line|
matches = line.tidy_bytes.match(REGEXP)
matches.names.zip(matches.captures).to_h
end

PostgreSQL monkey patching query execution

I am trying to do something simple. I would like to print the pure sql before its execution and then to print the response when the query finishes. I think that I should monkey patch one of these two methods but the sql queries of the application do not use them.
Any idea how can I do it?
I know that it sounds stupid, but then I will extend this logic.
require 'active_record/connection_adapters/postgresql_adapter'
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
def query(sql, name = nil) #:nodoc:
File.open("file1", "a") { |f| f.write sql + "\n\n" }
log(sql, name) do
result_as_array #connection.async_exec(sql)
File.open("file1", "a") { |f| f.write "RESPONSE \n\n" }
end
end
def execute(sql, name = nil)
File.open("file2", "a") { |f| f.write sql + "\n\n" }
log(sql, name) do
#connection.async_exec(sql)
File.open("file2", "a") { |f| f.write "RESPONSE \n\n" }
end
end
end
My main idea is to handle execution methods at least for MySQL and PostgreSQL. I found that I can do it for MySQL this way:
require 'active_record/connection_adapters/mysql2_adapter'
module ActiveRecord
module ConnectionAdapters
class Mysql2Adapter < AbstractMysqlAdapter
def exec_query(sql, name = 'SQL', binds = [])
File.open("path2", "a") { |f| f.write sql + "\n" }
result = execute(sql, name)
ActiveRecord::Result.new(result.fields, result.to_a)
end
end
end
end
Maybe there is a way to handle this for all DB-s in one place?

Recursion for nested list generation

I need some help at my recursion function to get it run.
I had a database table with following attributes:
id
title
parent_id
Some example entries would be:
1,title1, 0
2,title2, 1
3,title3, 1
4,tilte4, 0
5,title5, 3
with these entries I wants to create the following nested list
title1
title2
tille3
title5
title4
I write the following functions to generate these but there is a failure in there which overfolows my stack always
def topic_nested_list(topics_list)
get_nested_list(topics_list, topics_list.first)
end
def get_nested_list(topics, parent)
ul_contents = ""
ul_contents << "<ul>"
childs = get_topic_childs(topics,parent.id)
if childs.blank?
ul_contents << "<li>" << parent.title << "</li>"
else
for child in topics
ul_contents << get_nested_list(topics, child)
end
end
ul_contents << "</ul>"
end
def get_topic_childs(topic_list, id)
childs = []
topic_list.each do |topic|
if topic.parent_id == id
childs.push(topic)
end
end
return childs
end
I am not too sure everything that your code is doing, but it seems you want something like this
def process_topics topics_list
topics_list.each do |t|
# do something
process_topics children_of_topic(topic_list, t)
# or do something
end
end
def children_of_topic(topic_list, topic)
topic_list.select(|t| t.id == topic.parent_id)
end
It might be good to simplify your example down to something like this then add stuff in as you go.
Your very first call
get_nested_list(topics_list, topics_list.first)
Is not making sense. You want to cycle through each topic in your list and get the children of that topic and then recurse on that.

How to get result of multiples queries in a scope?

I have a dummy_names table which contains random first_names and last_names. In the db, where there is a first_name for an entry, the last_name is NULL and vice versa.
I'm trying to write a scope that returns a random name (a random first_name + a random last_name from that able).
What am I doing wrong here...?
scope :random_name, lambda {
fname = self.where('first_name IS NOT NULL').first
lname = self.where('last_name IS NOT NULL').first
fname.first_name.to_s + " " + lname.last_name.to_s
}
here we go
#in your initializer
module ActiveRecord
class Base
def self.random
if (c = count) != 0
find(:first, :offset =>rand(c))
end
end
end
end
#in your model
def self.random_name
"#{self.where('first_name IS NOT NULL').random.first_name} #{self.where('last_name IS NOT NULL').random.last_name}"
end

How can I identify and process all URLs in a text string?

I would like to enumerate all the URLs in a text string, for example:
text = "fasòls http://george.it sdafsda"
For each URL found, I want to invoke a function method(...) that transforms the string.
Right now I'm using a method like this:
msg = ""
for i in text.split
if (i =~ URI::regexp).nil?
msg += " " + i
else
msg+= " " + method(i)
end
end
text = msg
This works, but it's slow for long strings. How can I speed this up?
I think "gsub" is your friend here:
class UrlParser
attr_accessor :text, :url_counter, :urls
def initialize(text)
#text = parse(text)
end
private
def parse(text)
#counter = 0
#urls = []
text.gsub(%r{(\A|\s+)(http://[^\s]+)}) do
#urls << $2
"#{$1}#{replace_url($2)}"
end
end
def replace_url(url)
#counter += 1
"[#{#counter}]"
end
end
parsed_url = UrlParser.new("one http://x.com/url two")
puts parsed_url.text
puts parsed_url.urls
If you really need extra fast parsing of long strings, you should build a ruby C extension with ragel.

Resources