Rails 3 ActiveRecord Insert Cannot Insert Value Null - ruby-on-rails

I am using:
Rails 3.0.9
MSSQL 2005
I have the table:
CREATE TABLE [dbo].[edocs](
[id] [int] IDENTITY(1,1) NOT NULL,
[id_claim] [int] NOT NULL,
[id_material] [smallint] NOT NULL,
[is_secondary] [bit] NOT NULL CONSTRAINT [DF_edocs_is_secondary] DEFAULT ((0)),
[title] [varchar](100) COLLATE Ukrainian_CI_AS NOT NULL,
[ext] [varchar](4) COLLATE Ukrainian_CI_AS NOT NULL,
[size] [int] NOT NULL,
[code] [varchar](10) COLLATE Ukrainian_CI_AS NULL,
[receive_date] [datetime] NOT NULL CONSTRAINT [DF_edocs_receive_date] DEFAULT (getdate()),
[reg_date] [datetime] NULL,
[reg_numb] [varchar](10) COLLATE Ukrainian_CI_AS NULL,
[idcead] [int] NULL,
[efile] [int] NULL
)
Some of fields has default value (for exapmle receive_date).
In Rails controller I try to create new record:
Edoc.create(
:id_claim => #claim_index,
:id_material => #doc_code,
:title => #file_list.first[:name],
:ext => #file_list.first[:ext],
:size => #file_list.first[:size],
:code => #materials[#doc_code]["code"]
)
But I get error message:
ActiveRecord::StatementInvalid (TinyTds::Error: Cannot insert the value NULL int
o column 'receive_date', table 'eFilling.dbo.edocs'; column does not allow nulls
. INSERT fails.: INSERT INTO [edocs] ([id_claim], [id_material], [is_secondary],
[title], [ext], [size], [code], [receive_date], [reg_date], [reg_numb], [idCEAD
], [eFile]) VALUES (100000, 3, 0, N'text', N'rtf', 80
472, N'al', NULL, NULL, NULL, NULL, NULL)):
But In MSSQL 2005 console I can do that:
insert into edocs ([id_claim], [id_material],[title], [ext], [size]) values(1, 1, 'rrr', 'rtf', 123)
I don't want ActiveRecord auto completes the query by adding fields are not pointed in my create method.
How Can I do that?

I believe that even if you wrote straight SQL queries to insert, and didn't specify values for the "not null" fields, and they didn't have a default value, you would still throw a SQL error. I would suggest either allowing NULL on those fields or giving them a default value (maybe '' or 0?).
This isn't just a Rails thing, this comes down to the SQL queries themselves.
Example, for table with 'id', 'email' and 'name', where 'name' is not null and has no default value, this would fail:
INSERT INTO table (id, email) VALUES ('3', 'test#example.com')
As SQL passes NULL or emptiness as the value to 'name'
Think of it kind of like a 'required field' when it is not null without default value

Related

How to set relation column type in TypeORM when using separated schema definition?

how can I set the type of column for relation when using a separated schema definition?
I'm trying to join on uuid (Postgres) column, but the migration generator generates character varying. Here's how relation is defined in schema:
...
relations: {
tenant: {
type: "many-to-one",
target: Tenant.name,
onDelete: "CASCADE",
onUpdate: "CASCADE",
joinColumn: {
foreignKeyConstraintName: "user_tenant_fk",
},
},
},
...
Here's how schema:log looks:
CREATE TABLE "tenant" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" character varying NOT NULL, CONSTRAINT "tenant_pk" PRIMARY KEY ("id"));
CREATE TABLE "user" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "email" character varying NOT NULL, "passwordHash" character varying NOT NULL, "tenantId" character varying, CONSTRAINT "user_email_key" UNIQUE ("email", "tenantId"), CONSTRAINT "user_pk" PRIMARY KEY ("id"));
...
But this will fail, as user.tenantId and tenant.id have different types. So how can I set manually the type of user.tenantId? Can't find relevant property in EntitySchemaRelationOptions. Adding tenantId as column with uuid type also not helped.

Rails create record with column of type 'Date'

I have a class named record which have these columns:
'ID' INT,
'RECORD' VARCHAR2(50),
'CREATED_AT' DATE,
'UPDATED_AT' DATE,
'MANUAL_UPDATE' DATE
I want to insert new record with the following code:
Record.new(ID: '1', RECORD: 'Foo', MANUAL_UPDATE: '20150110122356')
New record will be created but inside the MANUAL_UPDATE column, the values become Nil.
I want to create a record with provided string in the format of '%Y%m%d%H%M%S'. How do I do that?
More information on the Database's structure:
CREATE TABLE ZMNS_TEST.SAVED_ITEMS
(
ID INT NOT NULL,
RECORD VARCHAR2(50 CHAR) NOT NULL,
CREATED_AT DATE NOT NULL,
UPDATED_AT DATE NOT NULL,
MANUAL_UPDATE DATE,
)
You are trying to insert a String (timestamp) to a Date column and therefore you're getting nil. You have two options:
1> Update proper date as in:
Record.new(ID: '1', RECORD: 'Foo', MANUAL_UPDATE: Date.today)
2> Convert your timestamp to date and then update:
date = Date.strptime("20150110122356",'%Y%m%d%H%M%S')
#=> Sat, 10 Jan 2015
Record.new(ID: '1', RECORD: 'Foo', MANUAL_UPDATE: date)
Try the method below
Date.strptime('20150110122356', '%Y%m%d%H%M%S')
Record.new(ID: '1', RECORD: 'Foo', MANUAL_UPDATE: Date.strptime('20150110122356', '%Y%m%d%H%M%S'))

How to prevent Ruby on Rails Active record from getting default model values from the database?

I'm developing a RoR app, with Firebird with its SQL engine but i cant understand why ActiveRecord (AR) keeps querying the database for default values!
Here is the tables DDL:
CREATE TABLE GLOBAL_SETTINGS
(
SKEY varchar(64) NOT NULL,
SVALUE varchar(256) NOT NULL,
OBS blob sub_type 1,
IS_SYSTEM "BOOLEAN" DEFAULT 1 NOT NULL,
CREATED_AT timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
UPDATED_AT timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT PK_GLOBAL_SETTINGS_SKEY PRIMARY KEY (SKEY)
);
Here is the migration that created this table: (create_global_settings.rb)
class CreateGlobalSettings < ActiveRecord::Migration
def up
create_table :global_settings, :id => false do |t|
t.string :skey, :null => false, :limit => 64
t.string :svalue, :null => false, :limit => 256
t.text :obs
t.boolean :is_system, :null => false, :default => true
t.timestamps :null => false
end
# defaults on timestamp columns
execute("alter table GLOBAL_SETTINGS alter column CREATED_AT set default CURRENT_TIMESTAMP;")
execute("alter table GLOBAL_SETTINGS alter column UPDATED_AT set default CURRENT_TIMESTAMP;")
# our custom PK naming
execute("alter table GLOBAL_SETTINGS add constraint PK_GLOBAL_SETTINGS_SKEY primary key (SKEY)")
end
def down
drop_table :global_settings
end
end
Here is my model: (global_Settings.rb)
class GlobalSettings < ActiveRecord::Base
#model validations!
validates :skey, presence: true
validates :skey, uniqueness: { case_sensitive: false, message: 'Global setting key allready exists!'}
validates :svalue, presence: true
end
No views or tests or helper are defined!
In rails console if i do:
gs = GlobalSettings.new(skey: 'testKey', svalue: 'testValue')
D, [2014-11-21T13:11:18.547669 #7215] DEBUG -- : (192.2ms) SELECT CAST(1 AS SMALLINT) FROM RDB$DATABASE
D, [2014-11-21T13:11:18.564272 #7215] DEBUG -- : (16.3ms) SELECT CAST(CURRENT_TIMESTAMP AS TIMESTAMP) FROM RDB$DATABASE
D, [2014-11-21T13:11:18.580900 #7215] DEBUG -- : (16.4ms) SELECT CAST(CURRENT_TIMESTAMP AS TIMESTAMP) FROM RDB$DATABASE
#<GlobalSettings skey: "testKey", svalue: "testValue", obs: nil, is_system: true, created_at: nil, updated_at: nil>
gs.save
D, [2014-11-21T13:11:24.403986 #7215] DEBUG -- : GlobalSettings Exists (13.2ms) SELECT 1 AS one FROM "GLOBAL_SETTINGS" WHERE LOWER("GLOBAL_SETTINGS"."SKEY") = LOWER(?) ROWS 1, testKey
D, [2014-11-21T13:11:24.543674 #7215] DEBUG -- : SQL (89.4ms) INSERT INTO "GLOBAL_SETTINGS" ("CREATED_AT", "SKEY", "SVALUE", "UPDATED_AT") VALUES (?, ?, ?, ?), 2014- 11-21 13:11:24, testKey, testValue, 2014-11-21 13:11:24
true
As you can see it seems that AR is trying to get the default values for my model/table, and in this case that is not needed because it's querying the database 3 times, and it should only be doing an insert, and letting the SQL engine take care of the rest.
How do i prevent this kind of situation to happen?
Is there any way to prevent AR to fetch defaults for columns?
And another question, in the new method of the GlobalSetting model i am just using columns sKey: and sValue:, why is active record putting all others columns in the insert?
AFAIK: new only creates a model object which accepts a hash as a parameter in which keys are your table attributes. It does not query database at this point of time. Once you call the save method, it first calls valid? method to check if your object passes the validations you have defined. It is independent of database schema except for the uniqueness validation you have defined here. Uniqueness validation queries the database to check if such a value already exists. Once your object passes all the validations, it then calls the query to insert the data into your database. If the data violates some conditions at database level, exception is raised. So when the query is run at the database level, you have no control over it from rails. If there are default values in the database, they'll be assigned. The only way to bypass them is to explicitly passing some other values to the corresponding attribute.
And as per the behaviour of t.timestamps, yes, rails will automatically update the updated_at column each time you modify that record and created_at column when you create a new record.

Restore primary key in active record schema

Somehow, my schema ended up with this id column:
create_table "tables", :id => false, :force => true do |t|
t.integer "id", :null => false
# other fieds
end
This is the info on the column (note that primary is false):
[4] pry(main)> Table.columns.first
=> #<ActiveRecord::ConnectionAdapters::PostgreSQLColumn:0x007f98d06cc0f8
#coder=nil,
#default=nil,
#limit=nil,
#name="id",
#null=false,
#precision=nil,
#primary=false,
#scale=nil,
#sql_type="integer",
#type=:integer>
So I get this error whenever I try to save a new record:
ActiveRecord::StatementInvalid: PG::Error: ERROR: null value in column "id" violates not-null constraint
What's the best way to restore my primary key?
Rails migrations can't handle this natively - you'll need to use execute with the SQL that sets the primary key, creates the missing sequence, moves the sequence to the latest 'id' value (if any are present), and assigns the sequence nextval as the default:
execute("ALTER TABLE tables ADD PRIMARY KEY (id);")
execute("CREATE sequence tables_id_seq;")
# skip this next line if you know that no rows exist yet
execute("SELECT setval('tables_id_seq', (SELECT MAX(id) FROM tables));")
execute("ALTER TABLE tables ALTER id SET DEFAULT nextval('tables_id_seq');")

How to set a default value for a text input in ActiveScaffold?

How does one set a default value for a text input using ActiveScaffold 1.2RC1?
For later versions, it looks like this (from http://activescaffold.com/2010/7/21/changes-in-naming-schema-for-overrides) should work:
module PlayersHelper
def player_name_form_column(record, options)
text_field :record, :name, options.merge(:value => record.name || 'new player')
end
end
But it appears in 1.2RC1, the column form override method takes the input name as the second argument. I tried this:
module PlayersHelper
def player_name_form_column(record, _)
text_field :record, :name, {:value => record.name || 'new player'}
end
end
But it had no effect.
Update
My second try actually did work. In fact, both of these work:
text_field :record, :name, {:value => record.name || 'new player'}
text_field :record, :name, :value => (record.name || 'new player')
The interesting thing is that ActiveScaffold will actually propagate the default value for a column in the database to the input form! My players table looks like this:
mysql> show create table players\G
*************************** 1. row ***************************
Table: players
Create Table: CREATE TABLE `players` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) DEFAULT 'Manny Ramirez',
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=119 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
So record.name was actually set to 'Manny Ramirez', meaning I never saw my default. So the correct thing to do here seems to be to modify the default in the database, since blindly setting the value will break edits (i.e. if the player's name is 'David Ortiz', clicking Edit would pop up a player with all David's attributes, but with the name set to 'Manny Ramirez'.
Try maybe :value => "Something"

Resources