Any reason an INSERT in a trigger would do nothing? - advantage-database-server

So I've added the following trigger on a table:
INSERT INTO TNQueue (QueuedDate, Action)
VALUES (CURRENT_TIMESTAMP(), 'ManageLoadOrderTypes');
and it doesn't appear to do anything. I have several other, much more complicated trigger on other tables that all work great. They all do this sort of insert to this same table, but generally after checking for changes, if the record warrants an insert, decided what data to insert, sub query the __new and __old tables, etc.
The same trigger exists for both AFTER INSERT and AFTER UPDATE. I've tried with and without _old/_new tables and memo data.
Any ideas?

When you created the Trigger was the table open by other users (or even your user)?
If I remember correctly, if the table did not have any triggers and was opened, any new triggers do not take effect until ALL users close the table.

If you dont commit, I believe the change will automatically rollback

Related

How to keep track of a table data-change migration on Ruby on Rails

Here is the problem:
I have Ruby on Rails project that has a table that have almost 100k rows and I have a binary column and I want to make changes in the content data on this column.
So I must iterate over those 100k rows, making changes on that row on particular column, saving it back on database.
But I must keep track of changes because these changes could fail and I should have someway to re-start data change from where I stopped.
Here is what I thought of a way of doing it:
Create a Migration to have a table MigrationTrack to track all records that have being migrated
Create a model of the above migration
Create a rake task that grabs all 100k from TableToUpdate and iterate over them, saving data back to row and save its ID on MigrationTrack. Create a logic to have a join on TableToUpdate and MigrationTrack to filter only ids that I haven't updated yet
After above migration finished create another migration to drop MigrationTrack table and remove its model.
Is there any other "Railsh way" to do that? Anyone have done such change?
Thanks
I would do it like this:
Add and deploy a migration adding a new column with the desired data type to the database table.
Add code to your model that save the value from the old column into the new column too.
Run a rake task or a simple one-liner in the console that touches all records to make sure the code introduced in step one ran on each record.
After this step, you can manually verify if all records in the database have both columns set as expected.
Switch using the new attribute instead of the old attribute in the code.
Drop the old column.
For simple cases, try running a simple view to check how it will turn out to be, for example, if your migration is
change_column :table, :boolean_field, 'integer USING CASE boolean_field THEN ...'
then you try do a simple select query with your cast, if you need more safey, you can create 'up' and 'down' methods on your migrations, then you can create a backup table on up, and on down, you can revert the values

Is it possible to delay a validation until after a series of updates have been performed in rails?

One of my models has a position column and I have a draggable UI that allows users to change the model's position by dragging it to a new position. Updating the position will update the position of many other entries in that table.
I would like to be able to update all the affected models at once in a transaction, and then have the validation run that all positions are still unique, and roll back the transaction if the validation does not pass. Is there a way to do this?
Well, I think you want to use active record transactions block to wrap what you want to do with all your update!, if anything failed during all your record update because of the validation, it will rollback everything inside the active record transactions block.
Here is a link for you to read more http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
Also, if you really need to skip validation you can do
#model.save(validate: false)
and check again after you save everything like
#model.valid?
And you will need to manually throw an exception in the active record transaction block to cause everything to be rolled back

Add auto increment with scope to existing column in migration-file rails

I have posts and organisations in my database. Posts belongs_to organisation and organisation has_many posts.
I have an existing post_id column in my post table which I by now increment manually when I create a new post.
How can I add auto increment to that column scoped to the organisation_id?
Currently I use mysql as my database, but I plan to switch to PostgreSQL, so the solution should work for both if possible :)
Thanks a lot!
#richard-huxton has the correct answer and is thread safe.
Use a transaction block and use SELECT FOR UPDATE inside that transaction block. Here is my rails implementation. Use 'transaction' on a ruby class to start a transaction block. Use 'lock' on the row you want to lock, essentially blocking all other concurrent access to that row, which is what you want for ensuring unique sequence number.
class OrderFactory
def self.create_with_seq(order_attributes)
order_attributes.symbolize_keys!
raise "merchant_id required" unless order_attributes.has_key?(:merchant_id)
merchant_id = order_attributes[:merchant_id]
SequentialNumber.transaction do
seq = SequentialNumber.lock.where(merchant_id: merchant_id, type: 'SequentialNumberOrder').first
seq.number += 1
seq.save!
order_attributes[:sb_order_seq] = seq.number
Order.create(order_attributes)
end
end
end
We run sidekiq for background jobs, so I tested this method by creating 1000 background jobs to create orders using 8 workers with 8 threads each. Without the lock or the transaction block, duplicate sequence number occur as expected. With the lock and the transaction block, all sequence numbers appear to be unique.
OK - I'll be blunt. I can't see the value in this. If you really want it though, this is what you'll have to do.
Firstly, create a table org_max_post (org_id, post_id). Populate it when you add a new organisation (I'd use a database trigger).
Then, when adding a new post you will need to:
BEGIN a transaction
SELECT FOR UPDATE that organisation's row to lock it
Increment the post_id by one, update the row.
Use that value to create your post.
COMMIT the transaction to complete your updates and release locks.
You want all of this to happen within a single transaction of course, and with a lock on the relevant row in org_max_post. You want to make sure that a new post_id gets allocated to one and only one post and also that if the post fails to commit that you don't waste post_id's.
If you want to get clever and reduce the SQL in your application code you can do one of:
Wrap the hole lot above in a custom insert_post() function.
Insert via a view that lacks the post_id and provides it via a rule/trigger.
Add a trigger that overwrites whatever is provided in the post_id column with a correctly updated value.
Deleting a post obviously doesn't affect your org_max_post table, so won't break your numbering.
Prevent any updates to the posts at the database level with a trigger. Check for any changes in the OLD vs NEW post_id and throw an exception if there is one.
Then delete your existing redundant id column in your posts table and use (org_id,post_id) as your primary key. If you're going to this trouble you might as well use it as your pkey.
Oh - and post_num or post_index is probably better than post_id since it's not an identifier.
I've no idea how much of this will play nicely with rails I'm afraid - the last time I looked at it, the database handling was ridiculously primitive.
Its good to know how to implement it. I would prefer to use a gem myself.
https://github.com/austinylin/sequential (based on sequenced)
https://github.com/djreimer/sequenced
https://github.com/felipediesel/auto_increment
First, I must say this is not a good practice, but I will only focus on a solution for your problem:
You can always get the organisation's posts count by doing on your PostsController:
def create
post = Post.new(...)
...
post.post_id = Organization.find(organization_id).posts.count + 1
post.save
...
end
You should not alter the database yourself. Let ActiveRecord take care of it.

Initialize database values in rails

In my project, i have a situation like when user runs the application.
The system should insert some values in a table which is used allover the application.
(These value should be inserted only once when the project is executed at first time)
I am trying to find out if there is any initialization function like Constructors in Rails.
I tried to use the config/application.rb, but i am not sure its the right way to do this.
Please suggest.
Thanks
If you looking for inserting some default dictionary data like month names etc you should look into seed.rb file or even better consider using seed_fu gem (https://github.com/mbleigh/seed-fu)
Yes you can insert/edit/delete records into table with migration :
1) Create the migration .
2) Run db query inside the execute. like :
execute "insert into users (name, role) values ('vik', 'admin')"
3) After all the insertion operation run the migration.
How if you update have boolean field or any kind of integer field to maintain status in your application. And for the very first time, user runs the application, your code will insert necessary values for that user in db and update boolean/status field and will be cached(for better performance only rather than fetching value from db every time). However after every time cache is cleared, it will send the query to db; but fetching boolean value(checking user status) is more faster than checking all inserted values for that user.

ActiveRecord, Postgres and partitioned tables

I've set up a trigger-based partitioning scheme on one of our pg 8.3 databases according to the pg docs here:. Basically, I have a parent table, along with several child tables. An insert trigger on the parent redirects any inserts on the parent into the appropriate child table -- this works well.
The ActiveRecord pg adapter, however, seems to rely on the postgres INSERT ... RETURNING "id" extension to get the id of the returned row after the initial insert. But the trigger seems to break the RETURNING clause -- no id is returned, although the row is created correctly.
While I suppose this behavior makes sense -- after all, nothing is being inserted in the main table, I really need to find some kind of work-around, as other child records will be inserted that require the row id of the just-inserted row.
I suppose I could add some kind of unique id to row prior to insert and then re-read it using this key after insert, but this seems pretty kludgy. Does anyone have a better work-around?
Since Rails v.2.2.1, you can turn off 'returning id' behavior just by overriding #supports_insert_with_returning method in PostgreSQLAdapter.
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
def supports_insert_with_returning?
false
end
end
Currently it looks like my best option is to just change the table prefix in a before_create event so that the insert happens on the underlying partition table directly, bypassing the insert trigger altogether. This is not a perfect solution, however, but seems to be the most performant and the simplest.
The only other solution I can come up with is to add a guid column to each table, and re-read the row from the parition table by guid immediately after insert to get the id.
Any other suggestions are welcome. Thanx -- m

Resources