Rails if #model.save is throwing an error - ruby

I have a Message model. Whenever I run if #message.save in my controller I get this error:
ERROR: null value in column "conversation_id" violates not-null constraint
I just want to redirect if save fails.
def create
#message = Message.new(message_params)
if #message.save
# redirect
else
# render new
end
end
My schema for messages
create_table "messages", force: true do |t|
t.string "body", null: false
t.integer "conversation_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
end

I believe the reason this is happening is because there is no validation in your actual model, only in the db. Therefore, it is passing the validation to continue saving, but the db has a problem with it. Simply include a validation in your model, and it will return false:
validates :conversation_id, presence: true

Related

For rails, is creating the 'ar_internal_metadata' table with a handwritten migration a good idea?

When I run a migration, the 'ar_internal_metadata' table keeps being stripped out of the schema.
create_table 'ar_internal_metadata', primary_key: 'key', force: :cascade do |t|
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.string 'value'
end
If I were to create the 'ar_internal_metadata' with a manual migration, would it work fine or cause problems?
keeps being stripped out of the schema.
This is expected behaviour:
# activerecord/lib/active_record/schema_dumper.rb
def ignored?(table_name)
[ActiveRecord::Base.schema_migrations_table_name, ActiveRecord::Base.internal_metadata_table_name, ignore_tables].flatten.any? do |ignored|
ignored === remove_prefix_and_suffix(table_name)
end
end

Ancestry gem gives error "The scope body needs to be callable." in rails 4?

models/message.rb
class Message < ActiveRecord::Base
has_ancestry
end
schema.rb
create_table "messages", force: :cascade do |t|
t.text "content"
t.integer "parent_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "ancestry"
end
after adding has_ancestry in model it gives error Argument Error.
"The scope body needs to be callable."
Please help me
Thanks

Add column to schema before created_at column

I'm trying to add a column to my table.
Here is my migration file:
class AddEmail < ActiveRecord::Migration
def change
add_column :apps, :email, :string, after: :website
end
end
However, when I run it, the newly created email column goes all the way to the last column after updated_at:
ActiveRecord::Schema.define(version: 20141217210326) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "apps", force: true do |t|
t.string "name"
t.string "iTunes"
t.string "website"
t.datetime "created_at"
t.datetime "updated_at"
t.string "email"
end
end
What I want is for the new email column to go in between the website and created_at column. How do I do that?
Postgres doesn't support the ordering of columns in tables. If you don't have any code in production, just alter the original migration that creates the apps table.

SQLite3::SQLException: duplicate column name: User_id: ALTER TABLE "comments" ADD "User_id" integer/

I ran the command
rails g migration AddUser_idToComments User_id:string
and then I figured out that User_id should be an integer and so I ran
rails g migration AddUser_idToComments User_id:integer --force thinking that it would overwrite the initial command.
But now, I'm getting this error:
```
louismorin$ rake db:migrate
== 20140910155248 AddIndexToComments: migrating ===============================
-- add_column(:comments, :Index, :string)
-> 0.0069s
== 20140910155248 AddIndexToComments: migrated (0.0070s) ======================
== 20140910181022 AddUserIdToComments: migrating ==============================
-- add_column(:comments, :User_id, :integer)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: duplicate column name: User_id: ALTER TABLE "comments" ADD "User_id" integer/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:in change'
ActiveRecord::StatementInvalid: SQLite3::SQLException: duplicate column name: User_id: ALTER TABLE "comments" ADD "User_id" integer
/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:inchange'
SQLite3::SQLException: duplicate column name: User_id
/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:in `change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
```
Here's my schema.rb file
```
ActiveRecord::Schema.define(version: 20140910155210) do
create_table "comments", force: true do |t|
t.text "body"
t.integer "post_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "User_Id"
end
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
create_table "posts", force: true do |t|
t.string "title"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.integer "topic_id"
end
add_index "posts", ["topic_id"], name: "index_posts_on_topic_id"
add_index "posts", ["user_id"], name: "index_posts_on_user_id"
create_table "topics", force: true do |t|
t.string "name"
t.boolean "public", default: true
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", 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, null: false
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.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.string "role"
t.string "avatar"
t.string "Image"
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
```
Because of the error, your second migration -- changing the column type -- didn't run. If that migration was only intended to change that one column, we could then delete the file it generated and try again.
If you don't yet have any data in that column that you care about, that's pretty easy:
rails g migration ChangeTypeOfUserIdOnComments
This migration name isn't special. Might as well have been DoWhateverIWant
Then, edit the created migration's change method to something like this:
def change
remove_column :comments, :user_id
add_column :comments, :user_id, :integer
add_index :comments, :user_id
end
When you then run your un-run migrations rake db:migrate, it shouldn't trip up on the one which errored (because we deleted it), and then it should run this one, which removes the column and adds it back with the correct type.
If you DO have data you want to save, the procedure is more complicated. Your change method would have to grab the current user_id's for each comment, and then assign them to the new comments when we create the new column. The below should hopefully work:
def change
user_ids = {}
Comment.find_each{ |c| user_ids[c.id] = c.user_id.to_i }
remove_column :comments, :user_id
add_column :comments, :user_id, :integer
add_index :comments, :user_id
Comment.each{ |c| c.update_attribute(:user_id, user_ids[c.id])
end
Also note that the names of the migration in the command are generally all CamelCase or all snake_case. So: AddColumnUserIdToComments or add_column_user_id_to_comments. Naming as you did might cause problems.
** EDIT **
Modify a Column's Type in sqlite3
It appears that SQLite has NO good way to modify/drop a column. I'd suggest either:
Dropping and restarting a SQLITe table
Drop the table, drop the original user_id migration and the line in the new one about removing the old user_id column, and then create a new table with the new migrations. Should work fine if you don't care about your data
Switching to Postgres, which is the database Heroku uses.
It's probably a good idea (because you want your production and local databases to behave identically), but can be bug-prone to switch to.
Look here for guidance -- Change from SQLite to PostgreSQL in a fresh Rails project

Authlogic - how to check if a user is logged out

This is my setup:
user.rb
acts_as_authentic do |c|
c.logged_in_timeout(1.minutes)
end
user_session.rb
def to_key
new_record? ? nil : [ self.send(self.class.primary_key) ]
end
self.logout_on_timeout = true
application_controller.rb
helper_method :current_user_session, :current_user
private
def current_user_session
logger.debug "ApplicationController::current_user_session"
return #current_user_session if defined?(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
logger.debug "ApplicationController::current_user"
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.user
end
def require_user
logger.debug "ApplicationController::require_user"
unless current_user
#store_location
flash[:warning] = "You must be logged in to access this page"
#redirect_to new_user_session_url
redirect_to root_url
return false
end
end
def require_no_user
logger.debug "ApplicationController::require_no_user"
if current_user
#store_location
flash[:warning] = "You must be logged out to access this page"
redirect_to account_url
return false
end
end
But when I load my page, I will get the error
undefined method `logged_out?' for #<User:0x00000103ee8348>
I try to read the official GitHub page of Authlogic, but I still don't know, what I miss... Could anyone give me a tip for fix it?
Many thanks in advance!
I was having the exact same problem, and it boiled down to the fact I didn't have all of the necessary columns in my User model.
My original User model (from db/schema.rb) was pretty minimalistic:
create_table "users", :force => true do |t|
t.string "username"
t.string "name"
t.string "crypted_password"
t.string "password_salt"
t.string "persistence_token"
t.string "perm", :default => "employee"
end
However, I added the column t.datetime :last_requested_at to my model, as well as a few others that may or may not be needed. My final User model looks like:
create_table "users", :force => true do |t|
t.string "username"
t.string "name"
t.string "crypted_password"
t.string "password_salt"
t.string "persistence_token"
t.string "perm", :default => "employee"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "login_count", :default => 0, :null => false
t.integer "failed_login_count", :default => 0, :null => false
t.datetime "last_request_at"
t.datetime "current_login_at"
t.datetime "last_login_at"
t.string "current_login_ip"
t.string "last_login_ip"
end
After adding in the other columns, I no longer get the undefined method 'logged_out?'... error.
Good luck!
(reference/more info: http://www.michaelhamrah.com/blog/2009/05/authlogic-and-openid-on-rails/ -- search in the page for logged_out?, the explanation was about 3/4 of the way down the post.)
If you want to know if a user is logged out, you can do:
if current_user_session
...
This condition will return true if the user is logged in (there is a session), and false if they are logged out (the session is nil).
As for the error message, undefined method 'logged_out?' for #<User:0x00000103ee8348> means that you haven't defined a method called logged_out?, so it doesn't know what you mean.
Authlogic doesn't define a logged_out? method for the User model, and neither have you, so there's nothing to call. The reason is that the state of either being "logged in" or being "logged out" doesn't have anything to do with the User model, but instead is a property of whether or not a given user has an active UserSession record.

Resources