Rails activeadmin cannot detect auto increment field existing table - ruby-on-rails

I have existing rails app that have some tables with some data. I did the CRUD operation directly from postgresql client before using activeadmin.
I don't know whether I missed the documentation or this is a bug: activeadmin cannot detect my existing autoincrement id for table.
If I refresh the submitted form until the auto increment id surpass the existing id in my table, it works.

First think which I could think of would be that you have passed the id parameter in permit params.
Please check that and if is present then remove it.
Secondly,as mentioned in the post that there are already data in the database so there is a problem with the sequences generated, since they can be only used once.
The solution is to set the sequence for your song_artists.id column to the highest value in the table with a query like this:
SELECT setval('song_artist_id_seq', (SELECT max(id) FROM song_artists));
I am assuming that your sequence name "song_artist_id_seq", table name "song_artist", and column name "id".
To get the sequence name run the below mentioned command:
SELECT pg_get_serial_sequence('tablename', 'columname');
For Resetting the postgres sequences from rails console:
ActiveRecord::Base.connection.tables.each do |t|
ActiveRecord::Base.connection.reset_pk_sequence!(t)
end
Another solution would be to override the save() method in your song_artist class to manually set the song_artist id for new records but is not advisable.

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

Rails and Active Record: is possible to mass assign ID?

I'm migrating a Bulletin Board from PHP (mysql) to Rails (PG) and for SEO I must keep the same IDs for topics.
My migration script use the standard class methods, so I create a new topic with mass assignment. Using this solution postgres give me an incremental ID for my topic that is different from my original ID.
Is there any way to force the ID? I know that id are unique (they come from my mysql db) but I need to keep identity for SEO and for url rewrite. I found a solution searching here but now is deprecated.
Create your migration like this:
create_table :table_name, {id: false} do |t|
t.int :your_custom_id
# .. other columns ...
end
execute "ALTER TABLE `table_name` ADD PRIMARY KEY (your_custom_id);"
Finally, to let Rails view this non-standard id field as your primary ID, add the following code in your model:
set_primary_key :your_custom_id # for Rails 3
self.primary_key = :your_custom_id # for Rails 4
Now, set this field to be free from mass-protection, and use it like a normal field.
However, I will really advise you to simply setup a new table column (i.e. field), something like old_id and not to mess with default Rails id field. Once you do that, use that field in your routes.

rails model validation in the database

I have a table and have the validation for uniqueness setup in the table. eg.
create table posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY UNIQUE,
title varchar(255) unique,
content text
);
Here title is unique. Do also need to inform the model class about this uniqueness? If not when i insert a duplicate title, it gives me error. How do I catch that. Currently rails shows me the backtrace and i could not put my own error messages
def create
#f = Post.new(params[:post])
if #f.save
redirect_to posts_path
else
#flash['message'] = "Duplicated title"
render :action=>'new'
end
end
I am not being redirected to the new and instead show a big backtrace.
Use the validates_uniqueness_of validation. "When the record is created, a check is performed to make sure that no record exists in the database with the given value for the specified attribute (that maps to a column)"
You will have to add all of the validations to your models. There is a gem called schema_validations, which will inspect your db for validations and create them in your models for you. https://github.com/lomba/schema_validations
Yes you do as noted in other answers, the answer is validate_uniqueness_of - http://ar.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000086. Note, even though you have a validation in your model a race condition does exist where Rails may try and do two inserts unaware of there being a unique record already in the table
When the record is created, a check is performed to make sure that no
record exists in the database with the given value for the specified
attribute (that maps to a column). When the record is updated, the
same check is made but disregarding the record itself.
Because this check is performed outside the database there is still a
chance that duplicate values will be inserted in two parallel
transactions. To guarantee against this you should create a unique
index on the field. See add_index for more information.
So what you have done, by creating a unique index on the database is right, though you may get database driver exceptions in your exception log. There are workarounds for this, such as detecting when inserts happen (through a double click).
The Michael Hartl Rails Tutorial covers uniqueness validation (re. the "email" field) here. It appears the full uniqueness solution is:
Add the :uniqueness validation to the model.
Use a migration to add the unique index to the DB.
Trap the DB error in the controller. Michael's example is the Insoshi people_controller--search for the rescue ActiveRecord::StatementInvalid statement.
Re. #3, it looks like Michael just redirects to the home page on any DB statement exception, so it's not as complex (nor as accurate) as the parsing suggested by #Ransom Briggs, but maybe it's good enough if, as #Omar Qureshi says, the uniqueness constraint covers 99% of the cases.

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

Adding id column and populating it to an existing table in Rails?

I have an existing table that I'd like to use for a Rails application.
It's a simple table with only 4 columns. However it does not yet have id column. And also new data will be added periodically.
I am trying to find a way to add the id column and populate it.
I guess I have two options, but being a noob I am sure there are better ways.
Option 1: I can add the id column and populate it when I parse raw data into CSV files, and then import it to the Rails database. In this case, when I parse the data into CSV files, I need to figure out how to find the last used unique id is.
Option 2: Parse raw data into CSV files, then import to the Rails database. Then my rails application will populate the id column for the new data entries.
If Rails has a built in method or GEM that can populate the id fields for the new entries, that would be great. In that case I will go with the Option 2.
If not, I think it's easier to go with the Option 1.
So I guess the question becomes this: Can Rails automatically populate the id column of entries with blank id field?
Thanks!
Either option should work because the underlying database will automatically handle the id column since it's the primary key. So create the table using a migration, then parse, import, and add the CSV data to your database via which ever method sits best.

Resources