Add and edit data to postgresql with ruby on rails - ruby-on-rails

I have a ruby code that should integrate with database. I use this code:
user_id = params[:user_id].to_i
sql = "SELECT * FROM user_stats WHERE user_id = #{user_id}"
user_stats = ActiveRecord::Base.connection.execute(sql)
but adding rows to database like this:
sql = "INSERT INTO user_custom_fields (id, user_id, name, value, created_at, updated_at) VALUES (#{last_id}, #{user_id}, 'user_field_#{user_field_id[0]["id"]}', '#{personality}', '#{formatted}', '#{formatted}')"
res = ActiveRecord::Base.connection.execute(sql)
won't increase the sequence table and I can't edit this table using this way.
How should I add data to these tables that the sequence tables increase automatically.

Related

Custom joined SQL to ActiveRecord

DB - PostgreSQL
Rails - 4
I have next SQL
sql = <<-SQL
LEFT OUTER JOIN (
SELECT SUM(id) AS sum_ids, some_key FROM second_models
WHERE id < 10000
GROUP BY some_key
) AS second_models ON first_models.id = second_models.first_model_id
SQL
record = FModel.joins(sql).last
record.sum_ids # DOESN'T WORK !
and I can see the record as ActiveRecord object, but can I get somehow field sum_ids which was built manually?
The additional field is inside the join section. It is not selected by default and thus can't be read. When executing your statement you get something like the following SQL query:
SELECT first_models.*
FROM first_models
INNER JOIN (
SELECT SUM(id) AS sum_ids, some_key
FROM second_models
WHERE id < 10000
GROUP BY some_key
) AS second_models
ON first_models.id = second_models.first_model_id
The first select statement prevents the sum_ids field from being accessible in your object since it's never returned to Rails. You want to change SELECT first_models.* to SELECT *. This is simply done by specifying the following select:
record = FModel.select(Arel.star).joins(sql).last
record.sum_ids
#=> should now give you your value
You can also add your field specifically using the following method:
f_models = FModel.arel_table
record = FModel.select(f_models[Arel.star]).select('sum_ids').joins(sql).last
This should result in SELECT first_models.*, sum_ids.

Where is the database file created in this code?

I have this code embedded in a .html.erb file:
require 'sqlite3'
# Open a SQLite 3 database file
db = SQLite3::Database.new 'file.db'
# Create a table
result = db.execute <<-SQL
CREATE TABLE numbers (
name VARCHAR(30),
val INT
);
SQL
# Insert some data into it
{ 'one' => 1, 'two' => 2 }.each do |pair|
db.execute 'insert into numbers values (?, ?)', pair
end
# Find some records
db.execute 'SELECT * FROM numbers' do |row|
p row
end
As you can see the code is creating a database, then create a table, etc..
My problem: I don't know where the file "file.db" is created. I have searched for it on the whole Windows, but I cannot find it.
NOTE 1: it seems the file and the table are being created, because if I request for the same .html.erb, I get Error: the table 'numbers' already exists.
NOTE 2: I know this is not the best place to add the ruby code related to a database. I know I should write it on the controller.
Here it is the full code:
<%
require 'sqlite3'
# Open a SQLite 3 database file
db = SQLite3::Database.new 'development.sqlite3'
# Create a table
result = db.execute <<-SQL
CREATE TABLE numbers (
name VARCHAR(30),
val INT
);
SQL
# Insert some data into it
{ 'one' => 1, 'two' => 2 }.each do |pair|
db.execute 'insert into numbers values (?, ?)', pair
end
# Find some records
db.execute 'SELECT * FROM numbers' do |row|
p row
end
%>
<h1>Welcome#index</h1>
<p>Find me in app/views/welcome/index.html.erb</p>
Look for file.db. SQL lite is a truly light database. To view the tables and records read following:
https://www.tutorialspoint.com/sqlite/sqlite_create_database.htm

What's the right way to search a Rails model by multiple IDs in a more advanced query?

I'm using Rails 5 and PostGres 9.5. How do I write a Rails query that returns results based on finding multiple IDs? I have this
criteria = "my_objects.id IN ?"
param = "(#{params[:ids]})"
...
#results = MyObject.joins("LEFT OUTER JOIN addresses ON my_objects.address_id = addresses.id")
.where("#{criteria} AND EXISTS (SELECT * FROM my_object_times WHERE my_object_times.my_object_id = my_objects.id)", param)
.order(order_by)
.paginate(:page => params[:page])
The IDs are passed in via a query string parameter, taht looks something like
ids=9e24abc1-1422-4e51-9d0b-72ea444f8110,dcba2558-9bcc-48a2-b5ba-61b230aa796f
but the above results in the error
PG::SyntaxError: ERROR: syntax error at or near "'(9e24abc1-1422-4e51-9d0b-72ea444f8110,dcba2558-9bcc-48a2-b5ba-61b230aa796f)'"
Just pass an array as a parameterized value to the query:
ids = params[:ids].split(',')
#results = MyObject.joins("LEFT OUTER JOIN addresses ON my_objects.address_id = addresses.id")
.where("my_objects.id IN ? AND EXISTS (SELECT * FROM my_object_times WHERE my_object_times.my_object_id = my_objects.id)", ids)
.order(order_by)
.paginate(:page => params[:page])
Additionally you should be able to replace AND EXISTS by doing a INNER LEFT join:
#results.left_outer_joins(:addresses)
.joins(:my_object_times)
.where(id: ids)
left_outer_joins is new in Rails 5.

Why does Rails produce this SQL error, when similar code works elsewhere?

I have this rake task to import a csv file that I'm trying to debug, with a similar pattern to create records in 8 different tables from each row in the file. Records in the independent tables get created, then I need to find those records' id numbers to use as foreign keys to create records in the dependent tables.
The error says:
rake aborted!
ActiveRecord::StatementInvalid: Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'BLANCO) LIMIT 1' at line 1: SELECT `fields`.* FROM `fields` WHERE (IGNACIO BLANCO) LIMIT 1
which I verified in the MySQL console. But in the previous five tables, this similar code works fine to obtain the foreign keys:
require 'csv'
CSV.foreach('public/partial.csv', :headers => true) do |row|
# create the Company object
this_company_name = row['name'].strip!
this_operator_num = row['operator_num']
if !(Companies.exists?(:company_name => this_company_name))
Companies.create(company_name: this_company_name, operator_num: this_operator_num)
end
thecompany = Companies.find_by(company_name: this_company_name)
company_id = thecompany.id
# create the County object
this_county_name = row['county'].strip!
if !(Counties.exists?(county_name: this_county_name))
Counties.create(county_name: this_county_name)
end
thecounty = Counties.find_by(county_name: this_county_name)
county_id = thecounty.id
# create the Gastype object
this_gastype_name = row['gas_type'].strip!
if !(Gastypes.exists?(gas_type: this_gastype_name))
Gastypes.create(gas_type: this_gastype_name)
end
thegastype = Gastypes.find_by(gas_type: this_gastype_name)
gastype_id = thegastype.id
# create the Field object
this_field_name = row['field_name'].strip!
this_field_code = row['field_code'].strip!
if !(Fields.exists?(field_name: this_field_name))
Fields.create(field_name: this_field_name, field_code: this_field_code)
end
thisfield = Fields.find_by(this_field_name)
field_id = thisfield.id
...
The SQL statement that Rails created which produces the error is:
SELECT `fields`.* FROM `fields` WHERE (IGNACIO BLANCO) LIMIT 1;
which has an obviously incorrect WHERE clause. My question is why did Rails not produce the correct statement, like:
SELECT fields.* FROM fields WHERE (field_name ='IGNACIO BLANCO') LIMIT 1;
Should I change how the .find_by statement is written? Or is there a better way of obtaining the requisite foreign key?
Because of this line:
thisfield = Fields.find_by(this_field_name)
You're simply passing a string to find_by, and Rails will consider it to be raw SQL.
You need to use either of these two solutions:
thisfield = Fields.find_by_field_name(this_field_name)
thisfield = Fields.find_by(field_name: this_field_name)

How does rails know if a string in postgres is a string or a serialized hash

In rails, I have a hash that I "sanitized" and then inserted into the database with a direct sql call.
To read the record out, though I need to use the active record. It however is reading the field as a string, though I have the serialize value set for that field.
Here's how I insert the data
def self.update_records(iFileName, iHashArray)
return false if(rows.size == 0)
return false if(killed?)
p "Pushing hash.size = #{rows.size}"
next_id = adjust_sequence( rows.size) #this reserves the record ids. explicit out paces the autosequence
records = iHashArray.each_with_index.map { |hash, index| "\r\n(#{next_id + index}, #{sanitize(hash)})" }
sql = wrapWithSQL(UPLOAD_ID, sanitize(iFileName), records.join(", "));
connection.execute(sql);
adjust_sequence(1);
return true
end
def self.wrapWithSQL(iUploadId, iFileName, iSql)
sql = "WITH new_values (id, hash_value) as ( values #{iSql} )"+
"\r\nINSERT INTO upload_stages (id, hash_value, upload_id, status,file_name, created_at, updated_at)"+
"\r\nSELECT id, hash_value, #{iUploadId}, 1, #{iFileName}, current_timestamp, current_timestamp FROM new_values returning id";
end
My active record class for reading the values
class UploadStage < ActiveRecord::Base
serialize :hash_value, Hash
#...
end
Now on my windows box it works fine. And for the last several months I've seen the hash come out without issue.
On heroku it comes out of the database as a string, and my code can't figure out what to do with a string when it was expecting a hash.
Has anyone any idea how to confront this?
Note... my pushing to the database with raw sql is because I'm pushing 5000 records in one go. I can alter the sql, but I have to be able to push with sql, because active record just doesn't support the speed I need.

Resources