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
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
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?
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.
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
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.