Rails Article.find 1 raises ActiveRecord::StatementInvalid on legacy database - ruby-on-rails-3

I'm creating a rails app over a legacy database table. Everything works fine locally, but on the server I hit this error whenever I do Article.find(1)
Could not log "sql.active_record" event. NoMethodError: undefined method `name' for nil:NilClass
ActiveRecord::StatementInvalid: PG::Error: ERROR: zero-length delimited identifier at or near """"
LINE 1: SELECT "articles".* FROM "articles" WHERE "articles"."" = $1 LIMIT 1
The legacy database has an id field, however the schema describes the id with
create_table "articles", :id => false, :force => true do |t|
t.decimal "id", :precision => 10, :scale => 0, :null => false
...
Note that Article.find_by_id(1) returns the record without any problem.
Any ideas how to fix this?

UPDATED - See below
It turns out, adding the following to the model fixes this:
class Article < ActiveRecord::Base
set_primary_key :id
...
Presumably, because rails didn't create the table, it doesn't know what field the primary key is. It seems a little odd though, an educated guess with a warning - or even a more friendly error message - would be appreciated.
UPDATE:
Rails 3.2+ the above method is deprecated. The new method is as follows:
class Article < ActiveRecord::Base
self.primary_key = :id
...
Thanks to #lboix for pointing this out!

Seems that this option has been updated guys : set_primary_key error in Rails
Hope it will help :)
Take care

Related

Rails removing a column from activerecord not working

I want to remove container:references from my table, I have tried:
rails generate migration RemoveContainerfromCreateTasks container:references
followed by rails db:migrate, but it my reference field is still not removed.
Below is my ActiveRecord
class CreateTasks < ActiveRecord::Migration[6.1]
def change
create_table :tasks do |t|
t.string :title
t.text :body
t.references :container, null: false, foreign_key: true
t.text :tag
t.datetime :due
t.integer :priority
t.timestamps
end
end
end
class RemoveContainerfromCreateTasks < ActiveRecod::Migration[6.1]
def change
end
end
The issue here is really a sneaky capitalization error. Running:
rails generate migration RemoveContainerfromCreateTasks container:references
Will generate a migration with an empty change block which will do absolutely nothing when you migrate it except modify the migrations meta table (a table that AR uses to keep track of which migrations have been run). But if you properly capitalize From:
rails generate migration RemoveContainerFromCreateTasks container:references
It will generate:
class RemoveContainerFromCreateTasks < ActiveRecord::Migration[6.0]
def change
remove_reference :create_tasks, :container, null: false, foreign_key: true
end
end
Rails isn't actually intelligent. It just casts the name argument into snake case and compares it to a set of patterns like:
remove_something_from_tablename foo:string bar:integer
create_tablename foo:string bar:integer
create_foo_bar_join_table foo bar
And it then uses a template to generate the according type of migration. If you don't properly pluralize it will be cast into:
remove_containerfrom_create_tasks
Which Rails does not know what to do with as it does not match a known pattern.
Also note despite popular belief migrations are just a DSL to create SQL transformations which is completely unaware about your tables or models. In this case the resulting migration will just blow up when you attempt to run it since you don't have a create_tasks table.
I would roll the missnamed migration back. Delete it then run:
rails g migration RemoveContainerFromTasks container:references
rails db:migrate
Your issue here is that "CreateTasks" is not table in your database. "Tasks" is, however.
rails g migration RemoveContainerFromTasks container:references
will provide you
class RemoveContainerFromTasks < ActiveRecord::Migration[6.1]
def change
remove_reference :tasks, :container, null: false, foreign_key: true
end
end
A migration of this will successfully remove container from your schema.rb file, and subsequently the database system you're using.
Here's some console output, because why not:
unclecid#home:~/Desktop/sample_app$ rails db:migrate
== 20201227150512 CreateTasks: migrating ======================================
-- create_table(:tasks)
-> 0.0022s
== 20201227150512 CreateTasks: migrated (0.0023s) =============================
== 20201227151021 RemoveContainerFromTasks: migrating =========================
-- remove_reference(:tasks, :container, {:null=>false, :foreign_key=>true})
-> 0.0330s
== 20201227151021 RemoveContainerFromTasks: migrated (0.0331s) ================

Error in all unit and functional tests after altering column names of a table

I renamed 3 columns of a table and suddenly ALL of my unit and functional tests throw the same error, that they cannot find the table with the old column names. Even the tests for the models that have nothing to do with the table I modified throw that same error:
Example:
54) Error:
test_should_show_user(UsersControllerTest):
ActiveRecord::StatementInvalid: SQLite3::SQLException: table answers has no column named id_user: INSERT INTO "a
nswers" ("id_user", "id_survey", "id_question", "answer", "created_at", "updated_at", "id") VALUES ('MyString',
1, 1, 'MyText', '2012-06-16 17:45:56', '2012-06-16 17:45:56', 980190962)
this is what I did in my migration to alter the table:
class EditAnswersTable < ActiveRecord::Migration
def self.up
rename_column :answers, :id_user, :user_id
rename_column :answers, :id_survey, :survey_id
rename_column :answers, :id_question, :question_id
end
def self.down
rename_column :answers, :user_id, :id_user
rename_column :answers, :survey_id, :id_survey
rename_column :answers, :question_id, :id_question
end
end
I restarted the console and also eclipse, but nothing changed.
The app itself is working fine in the server, so why is the testing throwing those errors for every test?
What should I do? Thanks in advance.
Check your fixtures file! Whenever I'd rename columns, I'd usually forget to tweak my fixtures to match. This causes an error on every single test, just like you're seeing.
Hope that helps!

Rails 3 HABTM join table migration

I have a HABTM association between Users and Groups in my Rails 3 app. The book I'm following to learn Rails recommends running the following command line to create the join migration:
rails generate migration create_groups_users
However in the documentation it looks like I should've run:
rails generate migration create_groups_users_join_table
So that the following would be in my _create_groups_users.rb migration:
class CreateGroupsUsersJoinTable < ActiveRecord::Migration
Is adding join_table required?
Adding join_table at the end is not explicitly required. Your first command 'create_groups_users' is fine. I've done this in rails 3.0.9 and it works.
You can double check by opening up the migration file and checking that it looks like:
create_table :groups_users, :id => false do |t|
t.integer :group_id
t.integer :user_id
end
The :id => false is needed for a join table as it shouldn't have its own id field.
The last argument in your call to rails generate migration create_groups_users just denotes the class name and a part of the file name of the migration. So it does help to find the migration you have created, the migration file itself is (inside the class body) empty. So both versions are ok.

Why am I getting an error during a migration coupled with default data?

rails g migration CreateStates
Then add the following code to the migration:
===========================
class CreateStates < ActiveRecord::Migration
def self.up
create_table :states do |t|
t.column :name, :string
t.column :abbreviation, :string
end
State.create :name => 'Alabama', :abbreviation => 'AL'
State.create :name => 'Alaska', :abbreviation => 'AK'
State.create :name => 'Arizona', :abbreviation => 'AZ'
end
def self.down
drop_table :states
end
end
============================
I get an error:
** Invoke db:migrate (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:migrate
== CreateStates: migrating ===================================================
-- create_table(:states)
-> 0.0010s
rake aborted!
An error has occurred, this and all later migrations canceled:
uninitialized constant CreateStates::State
/Users/jondoe/.rvm/rubies/ruby-1.8.7-p330/lib/ruby/gems/1.8/gems/rspec-core-2.5.1/lib/rspec/core/backward_compatibility.rb:20:in `const_missing'
========
It seems like this should be able to do this:
http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
I have also tried to create a model instead of a just a migration file. Still same error. I have also tried creating 2 migrations (one to create table, then one to add data) and that didn't work either. Any ideas?
Try doing:
State.reset_column_information
before your State.create.
documentation
Your code would work perfectly, except that you don't actually have a State class. The only way Rails would know about this class is if you defined it in app/models/state.rb as Class State < ActiveRecord::Base...
Rather than running a custom migration, I'd recommend running this line of code:
rails g model State name:string abbreviation:string
This will:
Create your model (and unit test files)
Create a migration named something like 20110508223913_create_states.rb, which will look nearly identical to your attempted migration above.
Then all you need to do is add your State.create... lines and you should be good to go.

Rails 3 validates_uniqueness_of with :scope generates invalid SQL?

Have two models that record some monthly statistics and I'm trying to enforce a composite key constraint within the model using:
validates_uniqueness_of :entity_id, :scope => [:year, :month]
When trying to run a .valid? method on a record, I continually get an error as apparently ActiveRecord is generating improper SQL.
SQLite3::SQLException: near "FROM": syntax error: SELECT FROM "table" WHERE ("table"."entity_id" = 1) AND ("table"."year" = 2007) AND ("table"."month" = 6) LIMIT 1
Notice above that Rails isn't adding a * in the select statement and so SQLite correctly throws an error.
Any ideas if I've done something wrong here?
Try this
validates :entity_id, :uniqueness => {:scope => [:year, :month]}
you probably want
:presence => true