Ruby (without rails) using activerecord, insert into does not work - ruby

I need to insert a new record into an existing table in a databse. I tried both approaches below:
class UserDetail < ActiveRecord::Base
def self.add_new_user
new_user = UserDetail.new
new_user.first_name = 'Joe'
new_user.last_name = 'Smith'
new_user.user_id = 'TEST'
new_user.save
end
def self.add_new_user_2
UserDetail.create(user_id: 'TEST', first_name: 'Joe',
last_name: 'Smith')
end
However, both approaches give me the error below:
ActiveRecord::StatementInvalid: OCIError: ORA-00926:
missing VALUES keyword: INSERT INTO "USER_DETAIL" DEFAULT VALUES
What am I missing? Please share your solutions.
(Using Ruby 1.9.3, ActiveRecord 4.2.4)

ActiveRecord makes assumptions about primary keys. It is expecting to find a primary key on your UserDetail table called "ID". Should look something like.
class UserDetail < ActiveRecord::Base
self.table_name = :user_detail
self.primary_key = :user_id
def self.add_new_user
new_user = UserDetail.new
new_user.first_name = 'Joe'
new_user.last_name = 'Smith'
new_user.user_id = 1
new_user.save
end
end

Related

Cannot update record with ActiveRecord (no rails)

Hello I have the following table in my PostgreSQL database:
CREATE TABLE user_logins (token VARCHAR(512) NOT NULL, user_id UUID UNIQUE NOT NULL, create_date TIMESTAMPTZ DEFAULT clock_timestamp(), last_visit TIMESTAMPTZ DEFAULT clock_timestamp(), expire TIMESTAMPTZ DEFAULT clock_timestamp() + INTERVAL '30 DAYS');
For which I have the following ActiveRecord class
require "active_record"
class UserLogin < ActiveRecord::Base
end
I want to update the last_visit column, which I try to do like this:
def update_last_visited(user_token)
user_login = UserLogin.find_by(token: user_token)
if user_login == nil
return false
end
user_login.update(last_visit: Time.now.utc)
end
However, I get this error:
2023-02-19 11:55:21 - ActiveRecord::StatementInvalid - PG::SyntaxError: ERROR: zero-length delimited identifier at or near """"
LINE 1: ...logins" SET "last_visit" = $1 WHERE "user_logins"."" IS NULL
As I have understood ActiveRecord if I have the object ActiveRecord should be able to update the record, or have I miss understood something?
Should I instead do an update based on a where?
A minimal reproducible example:
require "active_record"
require "yaml"
require 'securerandom'
db_config_file = File.open("database.yml")
db_config = YAML::load(db_config_file)
ActiveRecord::Base.establish_connection(db_config)
class UserLogin < ActiveRecord::Base
end
def update_last_visited(user_token)
user_login = UserLogin.find_by(token: user_token)
if user_login == nil
return false
end
user_login.update(last_visit: Time.now.utc)
end
user_login = UserLogin.new
user_login.token = "wompas"
user_login.user_id = SecureRandom.uuid
user_login.save
update_last_visited(user_login.token)
The database.yml file:
adapter: 'postgresql',
host: 'localhost',
port: 5432
username: 'user',
password: 'password',
database: 'dbname'
Note: The project does not utilise Rails, we only use ActiveRecord for its ORM capabilities.
Your UserLogin doesn't have a primary key. But ActiveRecord expects tables to have a primary key column named id per default. See Active Record Basics / Schema Conventions in the official Rails Guides.
In your example, it feels like the user_id can be used as a primary key, because is cannot be NULL and it must be unique. You can try to configure user_id to be used by as primary key by ActiveRecord like this.
class UserLogin < ActiveRecord::Base
self.primary_key = :user_id
end
But in general, I suggest not fighting the default conventions and would just add a bigint id column to that table. While it is possible to configure custom primary key columns, it makes everything a bit more complex because you will need to remember those custom setting in other use cases – like, for example, when defining association.

how to get single latest record from a view and test it in console

I kinda have 2 questions. I have following model and method to get the latest record from view. but when i try to test in console i get error undefined method or variable vCustomerDetails why i am getting the error?
Also, how do i select only one column from view?
SELECT TOP 1 HasConditionFlag FROM vCustomerDetails
WHERE vCustomerDetails.UserID = #user_id
ORDER BY EntryDate DESC
Model
module Customer
class CustomerUsage < ActiveRecord::Base
self.table_name = 'vCustomerDetails'
def self.has_condition_flag(user_id)
vCustomerDetails
.where("vCustomerDetails.UserID = #{user_id}")
.order('vCustomerDetails.EntryDate DESC')
.last
end
end
end
this one worked
def self.has_condition_flag(user_id)
CustomerUsage
.select("vCustomerDetails.HasConditionFlag")
.where("vCustomerDetails.UserID = #{user_id}")
.order('vCustomerDetails.EntryDate DESC')
.first
Remove vCustomerDetails
module Customer
class CustomerUsage < ActiveRecord::Base
self.table_name = 'vCustomerDetails'
def self.has_condition_flag(user_id)
where("vCustomerDetails.UserID = #{user_id}")
.order('vCustomerDetails.EntryDate DESC')
.last
end
end
end
to select a limited number of columns use
.select('HasConditionFlag')

ActiveRecord ignores table_name_prefix

I've got situation where I need to define table_name and table_name_prefix within a model and for some reason table_name overrides table_name_prefix.
class ScheduleItem < ActiveRecord::Base
self.table_name = "schedule_item"
self.table_name_prefix = 'ACQ_IBM_T.'
end
The prefix is completely ignored in the queries. But, when I comment out the table_name part then the prefix is added. Anyone has seen strange behavior like this before?
In ActiveRecord::ModelSchema::ClassMethods, the table_name setter puts the value in #table_name:
def table_name=(value)
...
#table_name = value
And the table_name getter just uses the #table_name value if it is defined:
def table_name
reset_table_name unless defined?(#table_name)
#table_name
end
The table_name_prefix is only used to help Rails when it is trying to guess the table name based on the class name (in reset_table_name).
If you have a table name that Rails can't guess, you can do this:
class ScheduleItem < ActiveRecord::Base
self.table_name = "ACQ_IBM_T.schedule_item"
Or if you need to use the prefix somewhere else, you can do this:
class ScheduleItem < ActiveRecord::Base
self.table_name_prefix = 'ACQ_IBM_T.'
self.table_name = "#{table_name_prefix}schedule_item"

How to remove table column in Active Record

I would like to remove column from the table by using Active record. Please find the below snippet
require "active_record"
require 'sqlite3'
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'test_one')
class Account < ActiveRecord::Base
table_name = "AccountBean"
primary_key = "process_id"
remove_column "xxx" // I need this type of method to remove column "xxx" from accounts table
end
Is there any class method in ActiveRecord which satisfy this requirement ?
I guess ActiveRecord presumes that changes to structure shall be done using migrations.
If you really need to, you could use the same methods rails uses in migrations to e.g. remove a column - like here
I don't recommend this :)
ActiveRecord::Base.connection.remove_column("persons", "first_name")
Within a class that would look something like:
class Account < ActiveRecord::Base
table_name = "AccountBean"
primary_key = "process_id"
connection.remove_column(table_name, "xxx")
end

Sequel model over two joined tables

I have a legacy PostgreSQL database, which has a single model split into two tables, with one-to-one mapping between them.
CREATE TABLE auth_user (
id SERIAL,
username VARCHAR(30),
email VARCHAR(75),
password VARCHAR(64),
first_name VARCHAR(75),
last_name VARCHAR(75)
)
CREATE TABLE user_profile (
user_id INTEGER REFERENCES auth_User.id,
phone VARCHAR(32)
)
Unfortunately, I'm unable to change database structure.
I want to use this as a single Sequel model. Retreiving data from database works as expected:
class User < Sequel::Model
end
# Variant 1: using LEFT JOIN
#User.set_dataset DB[:auth_user].left_join(:user_profile, :user_id => :id)
# Variant 2: using two FROM tables
User.set_dataset DB[:auth_user, :user_profile]\
.where(:auth_user__id => :user_profile__user_id)
user = User[:username => "root"] # This works.
However, saving the model fails:
user.set :first_name => "John"
user.save # This fails.
If I use first variant of the dataset (with left_join) I get a "Need multiple FROM tables if updating/deleting a dataset with JOINs" error. If I use second variant, it still fails: "PG::Error: ERROR: column "phone" of relation "auth_user" does not exist LINE 1: ..."email" = 'nobody#example.org', "password" = '!', "phone"..."
Is there a way I could make Sequel seamlessly issue two UPDATE statements? (Same question holds for INSERTs, too).
You can have a Sequel model that uses a joined dataset, but there's no easy way to save such a model.
Personally, I would use a many_to_one relationship, nested attributes, and hooks for what you want:
class UserProfile < Sequel::Model(:user_profile)
end
class User < Sequel::Model(:auth_user)
many_to_one :user_profile, :key=>:id, :primary_key=>:user_id
plugin :nested_attributes
nested_attributes :user_profile
def phone
user_profile.phone
end
def phone=(v)
user_profile.phone = v
end
def user_profile
if s = super
s
else
self.user_profile_attributes = {}
super
end
end
def before_destroy
user_profile.destroy
super
end
def before_create
user_profile
super
end
def after_update
super
user_profile.save
end
end
I haven't tested that, but something like it should work. If you have problems with it, you should probably post on the sequel-talk Google Group.

Resources