Rails scaffold strange undefined_method error for specific table - ruby-on-rails

I'm currently working on an admin tool for an existing database and encountered a strange problem when scaffolding a particular table.
Here is the schema of the table using rake db:schema:dump:
create_table "locality", :force => true do |t|
t.integer "version", :limit => 8, :null => false
t.string "truth_id", :null => false
t.string "truth_record_id", :null => false
t.binary "deleted", :limit => 1, :null => false
t.string "internal_code", :null => false
t.string "iso_code"
t.string "materialized_path", :null => false
t.string "invariant_name", :null => false
t.binary "published", :limit => 1, :null => false
t.float "geo_point_latitude", :default => 0.0
t.float "geo_point_longitude", :default => 0.0
t.string "class", :null => false
t.integer "hut_count", :default => 0
t.integer "hotel_count", :default => 0
t.string "destination_url"
end
add_index "locality", ["truth_record_id"], :name => "truth_record_id", :unique => true
I used the schema_to_scaffold gem to create my scaffold from the dumped schema:
rails g scaffold locality version:integer truth_id:string truth_record_id:string
deleted:binary internal_code:string iso_code:string materialized_path:string
invariant_name:string published:binary geo_point_latitude:float
geo_point_longitude:float class:string hut_count:integer hotel_count:integer
destination_url:string
This workflow worked for a lot of other tables but when accessing /localities or Locality.all in the rails console all i get its:
irb(main):001:0> Locality.all
Locality Load (2.1ms) SELECT `locality`.* FROM `locality`
NoMethodError: undefined method `attribute_method_matcher' for "Country":String
Where does "Country":String come from?
At first I thought the model name 'locality' is somehow reservers by rails for i18n stuff but the same problem happens when naming the model 'Bla'.
I'm using rails 3.2.13 and a MySQL Database.

I believe that your column: class is invalid. How would you have access to that column since the class is already a method of any object in ruby?
I think that this causes the mess. The class column's value of your loaded locality is "Country" right?

So the problem was column named class, which ruby obviously hates.
Solution posted in this StackOverflow question: Legacy table with column named "class" in Rails
or more specifically in this blog post (Accessed 25.03.2013):
http://kconrails.com/2011/01/28/legacy-database-table-column-names-in-ruby-on-rails-3/

Related

gem annotate, error:Unable to annotate app/models/blog_post.rb: undefined method `supports_foreign_keys?'

ruby 2.0.0p247
Rails 3.2.22
mysql
I added gem 'annotate'
after bundle install. gem was installed
Next step: rails g annotate:install
next step: run rake db:migrate
Display error:
Unable to annotate app/models/blog_post.rb: undefined method `supports_foreign_keys?' for ActiveRecord::ConnectionAdapters::Mysql2Adapter:0x0000000346aae8
Similarly for other models
What wrong? How solve this issue. Thank you.
EDIT
shema.rb
.........................
create_table "blog_posts", :force => true do |t|
t.integer "user_id", :null => false
t.string "subject"
t.text "body", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "comments_count", :default => 0, :null => false
t.boolean "delta", :default => true, :null => false
t.string "tags_line"
t.string "commentable_by", :default => "all", :null => false
t.string "visible_by", :default => "all", :null => false
t.integer "article_id"
t.boolean "draft", :default => false, :null => false
t.datetime "published_at"
t.datetime "last_comment_at"
end
add_index "blog_posts", ["delta"], :name => "index_blog_posts_on_delta"
add_index "blog_posts", ["user_id"], :name => "index_blog_posts_on_user_id"
........................................................................
Probably the versions of your annotate-gem and your mysql2-gem are not compatible. You are still using Rails 3.2. Maybe it is because your mysql2-gem is quite old.
When looking at the release notes of the annotate-gem, you can see that it had added foreign_key support in 2.6.9. So it can help to downgrade it to 2.6.8

What should I do when I need a new field in a table in rails?

I am a newbie in rails; my problem is:
I have a table for users, and I need to add more fields...
Where do I put that?
I tried to put it in the migration file, but the schema doesn't change when I run rake db:migrate.
This is in my migration file:
def self.up
create_table :users do |t|
t.string :username, :null => false # if you use another field as a username, for example email, you can safely remove this field.
t.string :email, :default => nil # if you use this field as a username, you might want to make it :null => false.
t.string :crypted_password, :default => nil
t.string :salt, :default => nil
t.string :nombres, :default => nil
t.string :apellidos, :default => nil
t.string :codigo, :default => nil
t.string :fecha, :default => nil
t.string :zona, :default => nil
t.string :institucion, :default => nil
t.string :frecuencia, :default => nil
t.string :pregunta, :default => nil
t.string :respuesta, :default => nil
t.timestamps
end
And the schema is still without new fields
create_table "users", :force => true do |t|
t.string "username", :null => false
t.string "email"
t.string "crypted_password"
t.string "salt"
t.string "nombres"
t.string "apellidos"
t.string "codigo"
t.string "fecha"
t.string "zona"
t.string "institucion"
t.string "frecuencia"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "remember_me_token"
t.datetime "remember_me_token_expires_at"
end
What should I do?
Simple migration
You can use a migration generator:
$> rails g migration add_position_to_users position:integer
then run
$> rake db:migrate
More complex migration
or more complex migration which rails also provide:
$> rails g migration add_body_and_pid_to_users body:string:index pid:integer:uniq:index
$> rake db:migrate
More information about migrations can be found at railsguides
http://guides.rubyonrails.org/migrations.html
I think something we're not mentioning here is adding the code into the migration file.
My steps to add a column go something like this:
# rails generate migration AddFieldName blah:string
Inside the migration file generated:
(btw, this typically looks like: db/migrations/20130330115915_add_field_name.rb)
class AddFieldName < ActiveRecord::Migration
def change
add_column :table_name, :blah, :string
end
end
After making this change, I then run db:migrate. Then, the column is added to the database.

rails: table already exists on new git branch

I'm trying to play around with different messaging gems that all use devise. Therefore, after installing Devise on master branch of git, I checked out a new branch to try one gem "rails messaging" https://github.com/frodefi/rails-messaging, and when I couldn't get it to work, I committed the changes to that branch, and then I went back to master and checked out a new branch to try another gem "mailboxer" https://github.com/ging/mailboxer/tree/master/lib. In the gemfile of this new branch there was no trace of the gems from the first branch, however when I tried rake db:migrate for this second branch after installing the gems, I got this error message, which seemed to suggest that a table from the first branch was interfering with the rake of the second branch, unless by doing
rails g mailboxer:install
It automatically runs the rake db:migrate. However, the README says that I have to run rake db:migrate, so I'm not sure...
rake aborted!
An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: table "conversations" already exists: CREATE TABLE "conversations" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "subject" varchar(255) DEFAULT '', "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL
)
Can anyone suggest how I can work around this? I don't really know what commands to run to figure this out.
This is the scheme.rb file. Based on the index "messaging users" i'm guessing it's the setup created by the rails messaging gem (on the first branch) but I'm not totally sure. I looked at the source code on git but got kinda lost because I'm not very experienced.
ActiveRecord::Schema.define(:version => 20120302041333) do
create_table "conversations", :force => true do |t|
t.string "subject", :default => ""
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "messaging_users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "messaging_users", ["email"], :name => "index_messaging_users_on_email", :unique => true
add_index "messaging_users", ["reset_password_token"], :name => "index_messaging_users_on_reset_password_token", :unique => true
create_table "notifications", :force => true do |t|
t.string "type"
t.text "body"
t.string "subject", :default => ""
t.integer "sender_id"
t.string "sender_type"
t.integer "conversation_id"
t.boolean "draft", :default => false
t.datetime "updated_at", :null => false
t.datetime "created_at", :null => false
t.integer "notified_object_id"
t.string "notified_object_type"
t.string "notification_code"
end
add_index "notifications", ["conversation_id"], :name => "index_notifications_on_conversation_id"
create_table "receipts", :force => true do |t|
t.integer "receiver_id"
t.string "receiver_type"
t.integer "notification_id", :null => false
t.boolean "read", :default => false
t.boolean "trashed", :default => false
t.boolean "deleted", :default => false
t.string "mailbox_type", :limit => 25
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "receipts", ["notification_id"], :name => "index_receipts_on_notification_id"
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
end
The issue here is that while your code, schemas, gems, and migrations are stored in git, the database itself is not. So when you switch between branches, the database still retains its state.
These solutions will all work:
drop and re-seed your database
rake db:reset
migrate down (while on the old branch) to undo the migration. I'm not sure if the gem installed a migration in db/migrate or ran a migration directly from the gem, so this isn't as easy, but is better for data integrity if you don't want to wipe your data.
reload the schema you have stored in git (this has the same effects as the first one)
rake db:schema:load
use an sqlite database for now - while not appropriate for production, if you check in the database to git, it will behave as you're wishing your current database behaved. I should warn you though that large files like this will be a pain. Better to use one of the other approaches.
Yeah switching branches with different migration levels is a mess. There is no 'one-liner' to do this properly. There are four things that can be out of sync. You'll need to:
1) Determine what migrations your branch has:
(look at the contents of db/migrations)
2) Determine what your app thinks your database looks like:
(look at db/schema.rb)
3) Determine what migrations your database thinks it has by looking at the schema_migrations table:
~> rails db console
(opens up your db console, in my case mysql...)
mysql> SELECT * FROM schema_migrations; # don't forget the ';' at the end!
(outputs big huge list of migration timestamps)
4) Look at the actual tables to see if the migrations have been applied.
mysql> describe table_name;
(outputs the column names, see if they have been updated per the migration)
5) Now the part that requires thinking. There are a couple possible scenarios. I can only speak to the one I ran into:
Your migration files (1), your schema.rb(2) and your actual tables (4) match, but your schema_migrations table (3) is missing the migration timestamp. This was my issue.
If you don't care about the data: rake db:reset. It will trash your whole database and recreate the structure from scratch
Please suggest other scenarios with solutions..

Heroku ActiveRecord Error: PgSQL put null in id field

I just deployed a simple Ruby on Rails (3.0.10) application to Heroku. There is a line of code create a new User object like this.
User.create(:name => "[name here]", :email => "[email here]")
It can run well in my local machine, which is using MySQL. After I deployed it to Heroku, I got an error.
ActiveRecord::StatementInvalid: PGError: ERROR: null value in column "id" violates not-null constraint : INSERT INTO "users" ("id", "name", "email", "created_at", "updated_at") VALUES (NULL, '[name here]', '[email here]', '2011-09-28 03:59:12.908593', '2011-09-28 03:59:12.908593') RETURNING "id"
I have no idea what's wrong with my code. Did i miss anything?
Thanks all.
UPDATE
Migration
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :email
t.string :name
t.timestamps
end
end
def self.down
drop_table :users
end
end
Schema
ActiveRecord::Schema.define(:version => 20110922071106) do
create_table "users", :force => true do |t|
t.string "email"
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
end
Did you do this:
(Taken from http://railsapps.github.com/rails-heroku-tutorial.html)
Replace SQLite with PostgreSQL If you are developing locally using
SQLite, you will need to switch to PostgreSQL for deployment to
Heroku. If you don’t want to develop using PostgreSQL locally, you
can set up your Gemfile to use SQLite for development and PostgreSQL
for production.
To switch from SQLite to PostgreSQL for deployment to Heroku, edit
your Gemfile and change this line:
gem 'sqlite3'
To this:
group :production do
gem 'pg'
end
group :development, :test do
gem 'sqlite3'
end
For anyone else looking, I had this same problem. Worked fine in dev, but failed in production with Postgres. The problem I had I tracked back to the CanCan plugin, specifically code I had that was creating a guest user the ability.rb file, if no user object existed. The guest account was suggested in a Railscast. I removed the User.new guest creation command and the problem resolved.
I just re-create the whole RoR application, and copy all the controllers, models, and views that I built to the new app. It is now running well.
I tried to compare 2 versions and didn't have any result. Will let you guys know if I find out the cause of this.
Thanks all. :)
I had a similar problem. if you try to reload the schema (on local, dont do it on production obviously), you should see a difference in what you think you have and what the database actually thinks.
rake db:schema:dump
rake db:schema:load
THIS WILL ERASE YOUR DATA. But you should see a difference in the schema for 'users'. This was my difference:
The fresh dump showed:
create_table "posts", :id => :false, :force => true do |t|
t.integer "id", :null => false, :limit=> 8
t.integer "object_id", :limit => 8
t.string "post_type"
t.string "from_id"
t.text "picture_url"
t.text "video_source"
t.integer "shares"
t.integer "likes"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "image_size", :limit => 8
t.integer "vid_size", :limit => 8
end
But i know that id is handled by rails and this should be:
create_table "posts", :force => true do |t|
t.integer "object_id", :limit => 8
t.string "post_type"
t.string "from_id"
t.text "picture_url"
t.text "video_source"
t.integer "shares"
t.integer "likes"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "image_size", :limit => 8
t.integer "vid_size", :limit => 8
end
If this is also the case for you, simply add to your user model:
set_primary_key :id
That reset it and it works now. I still don't know the cause of the problem but this fixed it for me.

Unable to Seed Data for Authlogic

When I run rake db:seed in my Rails 3 application I get the error:
rake aborted!
undefined method 'find_or_create_by_first_name_and_last_name_and_role_and_email_and_password_and_password_confirmation'
Below are my create_users.rb and seeds.rb files respectively. Why isn't the find_or_create_by_* method being dynamically created?
def self.up
create_table :users do |t|
t.string :first_name, :null => false
t.string :last_name, :null => false
t.string :role, :null => false
t.string :email, :null => false
t.string :crypted_password, :null => false
t.string :password_salt, :null => false
t.string :persistence_token, :null => false
t.string :current_login_ip
t.string :last_login_ip
t.datetime :current_login_at
t.datetime :last_login_at
t.timestamps
end
end
User.find_or_create_by_first_name_and_last_name_and_role_and_email_and_password_and_password_confirmation(...)
According to the docs:
This dynamic finder is called with find_or_create_by_ and will return the object if it already exists and otherwise creates it, then returns it. Protected attributes won’t be set unless they are given in a block. (emphasis mine)
I'm guessing password and password_confirmation are protected attributes.
You are missing "and" between role and email
User.find_or_create_by_first_name_and_last_name_and_role_and_email_and_password_and_password_confirmation(...)

Resources