rails test makes Mysql2 complain about default value - ruby-on-rails-3

I'm pretty confused about an error I get trying to unit test a model (User) I have.
I have a fixture for the model in test/fixtures/users.yml
new_user_in_unavailable_country:
first_name: John
last_name: Lennon
email: john.lennon#pop.co.uk
password: YokoOn0
country: UNITED KINGDOM
Now in test/unit/user_test.rb I have
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "status_auto_fill_for_unavailable_country" do
users(:new_user_in_unavailable_country).valid?
assert users(:new_user_in_unavailable_country).status == "SUBSCRIBED"
end
end
So far so good. Now, here is what that generates upon rake:test:units :
Error:
test_status_auto_fill_for_available_country(UserTest):
ActiveRecord::StatementInvalid: Mysql2::Error: Field 'name' doesn't have a default value: INSERT INTO `countries` (`id`) VALUES (980190962)
Okay, if there is an hidden insert somewhere into table countries (which I never asked for!), I should be able to see that upon running the same code in a rails console.
So I tried:
> usr = User.new(:first_name => "John", :last_name => "Lennon", :email => "john.lennon#pop.co.uk", :password => "YokoOn0", :country => "UNITED KINGDOM")
#<User id: nil, first_name: "John", last_name: "Lennon", email: "john.lennon#pop.co.uk", hashed_password: nil, password_salt: nil, created_at: nil, updated_at: nil, organization_id: nil, country: "UNITED KINGDOM", status: nil>
>> usr.valid?
(1.0ms) SELECT COUNT(*) FROM `countries` WHERE `countries`.`available` = 1 AND `countries`.`name` = 'UNITED KINGDOM'
(1.0ms) SELECT COUNT(*) FROM `countries` WHERE `countries`.`available` = 1 AND `countries`.`name` = 'UNITED KINGDOM'
(0.0ms) SELECT COUNT(*) FROM `countries` WHERE `countries`.`available` = 1 AND `countries`.`name` = 'UNITED KINGDOM'
(1.0ms) SELECT COUNT(*) FROM `countries` WHERE `countries`.`available` = 1 AND `countries`.`name` = 'UNITED KINGDOM'
(0.0ms) SELECT COUNT(*) FROM `countries` WHERE `countries`.`available` = 1 AND `countries`.`name` = 'UNITED KINGDOM'
(0.0ms) SELECT COUNT(*) FROM `countries` WHERE `countries`.`available` = 1 AND `countries`.`name` = 'UNITED KINGDOM'
(0.0ms) SELECT COUNT(*) FROM `countries` WHERE `countries`.`available` = 1 AND `countries`.`name` = 'UNITED KINGDOM'
(0.0ms) SELECT COUNT(*) FROM `countries` WHERE `countries`.`available` = 1 AND `countries`.`name` = 'UNITED KINGDOM'
(0.0ms) SELECT COUNT(*) FROM `countries` WHERE `countries`.`available` = 1 AND `countries`.`name` = 'UNITED KINGDOM'
User Exists (1.0ms) SELECT 1 FROM `users` WHERE `users`.`email` = BINARY 'john.lennon#pop.co.uk' LIMIT 1
true
>> usr.status
"SUBSCRIBED"
Okay, no insertion into countries table.
Anyidea of what happens behind the scene that I am missing and that generates this error?
Create Country migration:
class CreateCountries < ActiveRecord::Migration
def change
create_table :countries do |t|
t.string :name , :null => false
t.string :iso_2_letters_code , :null => false
t.string :iso_3_letters_code , :null => false
t.integer :phone_code
end
add_index :countries , :iso_2_letters_code , :unique => true
add_index :countries , :iso_3_letters_code , :unique => true
end
end

Related

How to form a rails query to grab all the discussion posts a particular user has made?

I am using rails 5.0.0
I want to make a query that will let me display all the posts the current user has made. The two relevant tables I have are:
create_table "discussions", force: :cascade do |t|
t.string "title"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "channel_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
....
t.string "unconfirmed_email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "username"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["username"], name: "index_users_on_username", unique: true
end
create_table "replies", force: :cascade do |t|
t.text "reply"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "discussion_id"
t.integer "user_id"
end
and the relationships are as follows:
class Discussion < ApplicationRecord
belongs_to :channel
belongs_to :user
has_many :replies, dependent: :destroy
has_many :users, through: :replies
class Reply < ApplicationRecord
belongs_to :discussion
belongs_to :user
class User < ApplicationRecord
rolify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable
has_many :notifications, foreign_key: :recipient_id
has_many :discussions, dependent: :destroy
has_many :channels, through: :discussions
in my discussions_controller.rb file i have the following line
#discussions = Discussion.includes(:users).where('users.id' => current_user).order('discussions.created_at desc')
and in my view file I have
<% #discussions.each do |discussion| %>
...
<% end %>
I expect there to be a few entries since I have created them, however no entries are displayed at all. This is what is printed in the terminal window
Processing by DiscussionsController#index as HTML
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendering discussions/index.html.erb within layouts/application
SQL (0.5ms) SELECT "discussions"."id" AS t0_r0, "discussions"."title" AS t0_r1, "discussions"."content" AS t0_r2, "discussions"."created_at" AS t0_r3, "discussions"."updated_at" AS t0_r4, "discussions"."user_id" AS t0_r5, "discussions"."channel_id" AS t0_r6, "users"."id" AS t1_r0, "users"."email" AS t1_r1, "users"."encrypted_password" AS t1_r2, "users"."reset_password_token" AS t1_r3, "users"."reset_password_sent_at" AS t1_r4, "users"."remember_created_at" AS t1_r5, "users"."sign_in_count" AS t1_r6, "users"."current_sign_in_at" AS t1_r7, "users"."last_sign_in_at" AS t1_r8, "users"."current_sign_in_ip" AS t1_r9, "users"."last_sign_in_ip" AS t1_r10, "users"."confirmation_token" AS t1_r11, "users"."confirmed_at" AS t1_r12, "users"."confirmation_sent_at" AS t1_r13, "users"."unconfirmed_email" AS t1_r14, "users"."created_at" AS t1_r15, "users"."updated_at" AS t1_r16, "users"."username" AS t1_r17 FROM "discussions" LEFT OUTER JOIN "replies" ON "replies"."discussion_id" = "discussions"."id" LEFT OUTER JOIN "users" ON "users"."id" = "replies"."user_id" WHERE "users"."id" = 1 ORDER BY discussions.created_at desc
Rendered shared/_discussions.html.erb (8.5ms)
Channel Load (0.3ms) SELECT "channels".* FROM "channels" ORDER BY created_at desc
Role Load (0.3ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = ? AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1]]
Rendered discussions/_sidebar.html.erb (34.1ms)
Rendered discussions/index.html.erb within layouts/application (46.1ms)
Completed 200 OK in 245ms (Views: 165.7ms | ActiveRecord: 6.7ms)
If I use
#discussions = Discussion.includes(:users).order('discussions.created_at desc')
Then all the discussion posts display as they normally would as if the .includes statement was not there.
So, how can I change my query to list out the discussions made by the current user?
Update As per Shiko's comment, here is the output given with his input in the rails console
2.3.0 :001 > User.find(1).discussions
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Discussion Load (0.5ms) SELECT "discussions".* FROM "discussions" WHERE "discussions"."user_id" = ? [["user_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Discussion id: 1, title: "Test", content: "alkjdflk slkfj ", created_at: "2018-04-08 22:40:06", updated_at: "2018-04-08 22:40:06", user_id: 1, channel_id: nil>, #<Discussion id: 2, title: "Fake Bakesale", content: "Come buy cookies", created_at: "2018-04-08 23:29:17", updated_at: "2018-04-08 23:29:17", user_id: 1, channel_id: 1>, #<Discussion id: 3, title: "Fake Bakesale", content: "Come buy cookies", created_at: "2018-04-08 23:30:18", updated_at: "2018-04-08 23:30:18", user_id: 1, channel_id: 1>, #<Discussion id: 4, title: "Meeting today", content: "Come to the meeting", created_at: "2018-04-08 23:35:59", updated_at: "2018-04-08 23:35:59", user_id: 1, channel_id: 1>, #<Discussion id: 5, title: "New post", content: "asdf ", created_at: "2018-04-15 21:50:20", updated_at: "2018-04-15 21:50:20", user_id: 1, channel_id: 2>]>
2.3.0 :002 >
First thing, if you run below command in rails console, you should get an below expected error :
#discussions = Discussion.includes(:users).where('users.id' => current_user).order('discussions.created_at desc')
Expected error:
ActiveRecord::ConfigurationError: Can't join 'Discussion' to
association named 'users'; perhaps you misspelled it?
To fix this issue, you have to use :user instead of :users as below, simply because each discussion belongs to one user and not many :
#discussions = Discussion.includes(:user).where('users.id' => current_user).order('discussions.created_at desc')
There is a more a clean one way to get the current user discussions, using below:
Controller:
#user = User.find(curren_user_id)
ERB file:
<% #user.discussions.each do |discussion| %>
.....
<% end %>
You can do this:
#discussions = Discussion.includes(:user).
where(users: { id: current_user.id }).
order("discussions.created_at desc")
If you don't need to reference the user attributes in your view, you can also do this, which avoids the join altogether:
#discussions = Discussion.
where(user_id: current_user.id).order(created_at: :desc)

Can't create a user in Rails 4.2 using AuthLogic

This is what I've tried, and I'm not sure where the problem is. . .
My model:
class User < ActiveRecord::Base
acts_as_authentic
has_many :assignments
end
Migration:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :login, :null => false
t.string :crypted_password, :null => false
t.string :password_salt, :null => false
t.string :persistence_token, :null => false
t.timestamps null: false
end
end
end
This is what I'm getting in Rails console when trying to create a user:
`<main>'2.2.0 :004 > User.create(login:'whatever', password:'1', password_confirmation:'1')
(0.1ms) begin transaction
User Exists (1.1ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."login") = LOWER('whatever') LIMIT 1
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE "users"."persistence_token" = '4886c517de2414c730b7ed5cc296b0e19c3e56ee398fb0aeed0531c55cbb04fd2a8ce577a4d5bd7dbb52e46cf9ab5e27e287af0993a708d07ded12553460d11c' LIMIT 1
(0.1ms) rollback transaction
=> #<User id: nil, login: "whatever", crypted_password: "400$8$45$c054050d7ce04047$335b3dec54f141e7ab030e1f...", password_salt: "CQlMGatvdGngFXiogDcW", persistence_token: "4886c517de2414c730b7ed5cc296b0e19c3e56ee398fb0aeed...", created_at: nil, updated_at: nil>
No users are created after it:
2.2.0 :005 > User.all
User Load (61.5ms) SELECT "users".* FROM "users"
=> #<ActiveRecord::Relation []>
No errors and some weird SQL. What could be the problem?
EDIT: Just tried u = User.create(login:'whatever', password:'123', password_confirmation:'123'); u.errors.to_json
And I got:
=> "{\"password\":[\"is too short (minimum is 4 characters)\"],\"password_confirmation\":[\"is too short (minimum is 4 characters)\"]}"
So that was my problem, password was too short. Too bad Rails didn't print it by default when I was seeding db. Thanks all!

Rails Active record association by instance methods

I am trying to have (devise) users.rb be placed within a ClassInstruction.rb based on their userRole.rb (teacher or student). The models and schema are below, along with the error. It errors on the final .where statement, I have tried singular, pluralized, and other variations. I am basing this on my original post here, but am unable to get the example answer working.
Schema.rb :
ActiveRecord::Schema.define(:version => 20130523111519) do
create_table "class_instructions", :force => true do |t|
t.string "name"
t.datetime "time"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "class_instructions", ["user_id"], :name => "index_class_instructions_on_user_id"
create_table "roles", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "songs", :force => true do |t|
t.string "title"
t.string "content"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "user_id"
t.string "fractionRepresentation"
t.string "measureRepresentation"
end
create_table "user_roles", :force => true do |t|
t.integer "user_id"
t.integer "role_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "user_roles", ["role_id"], :name => "index_user_roles_on_role_id"
add_index "user_roles", ["user_id"], :name => "index_user_roles_on_user_id"
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
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
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
User.rb model :
class User < ActiveRecord::Base
#DEVISE STUFF
#== Associations
has_many :user_roles, :dependent => :destroy
has_many :roles, :through => :user_roles
has_many :songs
#== Instance Methods
def thisUsersID
self.id
end
def student_classes(class_instruction_name)
member_classes(class_instruction_name, 'Student')
end
def teacher_classes(class_instruction_name)
member_classes(class_instruction_name, Role::TEACHER)
end
private
def member_classes(class_instruction_name, type)
ClassInstruction \
.joins(:user_role) \
.where(["user_role.user_id = ?", id]) \
.joins("INNER JOIN roles ON roles.id = user_roles.role_id") \
.where("roles.name = ?", type) \
.where("class_instruction.name = ?", class_instruction_name)
end
end
user_role.rb model:
class UserRole < ActiveRecord::Base
belongs_to :user
belongs_to :role
has_many :class_instructions, :dependent => :destroy
end
role.rb model
class Role < ActiveRecord::Base
has_many :user_roles, :dependent => :destroy
end
class_instruction.rb model (names are 'ss' and'math-101')
class ClassInstruction < ActiveRecord::Base
belongs_to :user_role
end
Error Stack (from the ruby console after getting the first student and trying to find its classInstruction):
Loading development environment (Rails 3.2.2)
1.9.3-p429 :001 > U = User.find(3)
User Load (3.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 3]]
=> #<User id: 3, email: "stu#test.org", encrypted_password: "$2a$10$2DxWWV34BRFJoLboYyWCIeXEtCPYOSe8JqpTmFU6W2i1...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil>
1.9.3-p429 :002 > U.student_classes('math-101').all
ClassInstruction Load (0.2ms) SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
SQLite3::SQLException: no such column: user_role.user_id: SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: user_role.user_id: SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/sqlite3-1.3.7/lib/sqlite3/database.rb:91:in `initialize'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/sqlite3-1.3.7/lib/sqlite3/database.rb:91:in `new'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/sqlite3-1.3.7/lib/sqlite3/database.rb:91:in `prepare'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/sqlite_adapter.rb:246:in `block in exec_query'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activesupport-3.2.2/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/sqlite_adapter.rb:242:in `exec_query'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/sqlite_adapter.rb:460:in `select'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/database_statements.rb:18:in `select_all'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/querying.rb:38:in `block in find_by_sql'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/explain.rb:40:in `logging_query_plan'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/querying.rb:37:in `find_by_sql'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/relation.rb:171:in `exec_queries'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/relation.rb:160:in `block in to_a'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/explain.rb:33:in `logging_query_plan'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/relation.rb:159:in `to_a'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/activerecord-3.2.2/lib/active_record/relation/finder_methods.rb:159:in `all'
from (irb):2
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/railties-3.2.2/lib/rails/commands/console.rb:47:in `start'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/railties-3.2.2/lib/rails/commands/console.rb:8:in `start'
from /Users/phycom06/.rvm/gems/ruby-1.9.3-p429/gems/railties-3.2.2/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'1.9.3-p429 :003 >
erm,
in this piece of error code.
SQLite3::SQLException: no such column: user_role.user_id: SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: user_role.user_id: SELECT "class_instructions".* FROM "class_instructions" INNER JOIN "user_roles" ON "user_roles"."id" = "class_instructions"."user_role_id" INNER JOIN roles ON roles.id = user_roles.role_id WHERE (user_role.user_id = 3) AND (roles.name = 'Student') AND (class_instruction.name = 'math-101')
do you have "class_instructions"."user_role_id" and "class_instructions"."user_role_id" ?
i think in your schema don't have it, am i right ?
Not sure if this is all there is to it, but in this line:
.where(["user_role.user_id = ?", id]) \
You use user_role singular, when the table name is user_roles plural.

belongs_to / has_many not behaving as expected in Rails console

models:
class Person < ActiveRecord::Base
attr_accessible :email, :first, :last, :uuid, :books
has_many :books
end
class Book < ActiveRecord::Base
belongs_to :person
attr_accessor :blurb, :published, :title, :person
attr_accessible :person
end
I created a Person using the Rails 3.2.8 console like this:
person = Person.create!( {:first => "John", :last => "Doe"} )
and then created a Book
book = Book.create!( {:title => "Ruby for Dummies"} )
I then try to associate them like this:
person.books << book
When I query the person for books, I get an array with the book I created, but when I query the book for the person it belongs to, I get nil. I expected to get the person, given that all information was persisted (I see the SQL commands and I checked the database and the data is correct, i.e. the row in the book table points back to the person id it should.)
What am I missing?
thanks
Edit- Schema:
CREATE TABLE `persons` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`first` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`last` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`uuid` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`email` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2;
CREATE TABLE `books` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
`blurb` TEXT NULL COLLATE 'utf8_unicode_ci',
`published` TINYINT(1) NULL DEFAULT NULL,
`person_id` INT(11) NULL DEFAULT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=3;
Assuming your migrations are correct, there is nothing wrong with your code which should produce the following results:
1.9.3p194 :001 > person = Person.create!( {:first => "John", :last => "Doe"} )
(0.1ms) begin transaction
SQL (145.9ms) INSERT INTO "people" ("book_id", "created_at", "email", "first", "last", "updated_at", "uuid") VALUES (?, ?, ?, ?, ?, ?, ?) [["book_id", nil], ["created_at", Mon, 03 Sep 2012 21:35:53 UTC +00:00], ["email", nil], ["first", "John"], ["last", "Doe"], ["updated_at", Mon, 03 Sep 2012 21:35:53 UTC +00:00], ["uuid", nil]]
(43.5ms) commit transaction
=> #<Person id: 1, email: nil, first: "John", last: "Doe", uuid: nil, book_id: nil, created_at: "2012-09-03 21:35:53", updated_at: "2012-09-03 21:35:53">
1.9.3p194 :005 > book = Book.create!( {:title => "Ruby for Dummies"} )
(0.1ms) begin transaction
SQL (1.4ms) INSERT INTO "books" ("blurb", "created_at", "person_id", "published", "title", "updated_at") VALUES (?, ?, ?, ?, ?, ?) [["blurb", nil], ["created_at", Mon, 03 Sep 2012 21:36:25 UTC +00:00], ["person_id", nil], ["published", nil], ["title", nil], ["updated_at", Mon, 03 Sep 2012 21:36:25 UTC +00:00]]
(4.4ms) commit transaction
=> #<Book id: 1, blurb: nil, published: nil, title: nil, person_id: nil, created_at: "2012-09-03 21:36:25", updated_at: "2012-09-03 21:36:25">
1.9.3p194 :006 > person.books << book
(0.1ms) begin transaction
(0.3ms) UPDATE "books" SET "person_id" = 1, "updated_at" = '2012-09-03 21:36:39.566387' WHERE "books"."id" = 1
(4.4ms) commit transaction
Book Load (0.3ms) SELECT "books".* FROM "books" WHERE "books"."person_id" = 1
=> [#<Book id: 1, blurb: nil, published: nil, title: nil, person_id: 1, created_at: "2012-09-03 21:36:25", updated_at: "2012-09-03 21:36:39">]
1.9.3p194 :007 > Book.all
Book Load (0.5ms) SELECT "books".* FROM "books"
=> [#<Book id: 1, blurb: nil, published: nil, title: nil, person_id: 1, created_at: "2012-09-03 21:36:25", updated_at: "2012-09-03 21:36:39">]
The problem is with your Book model, try the following:
class Book < ActiveRecord::Base
attr_accessible :person, :title, :person
belongs_to :person
end
Before:
1.9.3p194 :002 > Book.last
Book Load (0.1ms) SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT 1
=> #<Book id: 4, blurb: nil, published: nil, title: nil, person_id: 1, created_at: "2012-09-03 21:55:33", updated_at: "2012-09-03 21:55:33">
1.9.3p194 :003 > Book.last.person
Book Load (0.2ms) SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT 1
=> nil
After:
1.9.3p194 :001 > Book.last
Book Load (0.4ms) SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT 1
=> #<Book id: 4, blurb: nil, published: nil, title: nil, person_id: 1, created_at: "2012-09-03 21:55:33", updated_at: "2012-09-03 21:55:33">
1.9.3p194 :002 > Book.last.person
Book Load (1.0ms) SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT 1
Person Load (0.1ms) SELECT "people".* FROM "people" WHERE "people"."id" = 1 LIMIT 1
=> #<Person id: 1, email: nil, first: "John", last: "Doe", uuid: nil, created_at: "2012-09-03 21:48:02", updated_at: "2012-09-03 21:48:02">
Have you tried doing something like the following? If so, what does book.person give you?
person = Person.create!( {:first => "John", :last => "Doe"} )
book = Book.create!( {:title => "Ruby for Dummies"} )
book.person_id = person.id
person.books
book.person

Rails 3: Database column won't update through active record

I haven't an issue where I can't seem to update or modify a database column in rails 3. I've never seen anything like this before and as such am sure it's something small that I'm overlooking. Please help!
IRB Output:
ruby-1.9.2-p318 :002 > User.all
User Load (0.1ms) SELECT "users".* FROM "users"
=> []
ruby-1.9.2-p318 :003 > User.create( :login => "dummy", :password => "foobar", :password_
confirmation => "foobar", :role => "user", :email => "dummy#email.com" )
(0.1ms) begin transaction
User Exists (0.1ms) SELECT 1 FROM "users" WHERE "users"."login" = 'dummy' LIMIT 1
User Exists (0.0ms) SELECT 1 FROM "users" WHERE "users"."email" = 'dummy#email.com' L
IMIT 1
SQL (0.8ms) INSERT INTO "users" ("created_at", "email", "hashed_password", "login", "
role", "salt", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["created_at", Thu, 05 Apr 2
012 02:21:00 UTC +00:00], ["email", "dummy#email.com"], ["hashed_password", "6416111c47f
a52ddfbde9e539ee6e369807bdeab"], ["login", "dummy"], ["role", nil], ["salt", "1LTzevgRHt
"], ["updated_at", Thu, 05 Apr 2012 02:21:00 UTC +00:00]]
(61.5ms) commit transaction
=> #<User id: 3, login: "dummy", role: nil, hashed_password: "6416111c47fa52ddfbde9e539
ee6e369807bdeab", email: "dummy#email.com", salt: "1LTzevgRHt", created_at: "2012-04-05
02:21:00", updated_at: "2012-04-05 02:21:00">
ruby-1.9.2-p318 :004 > u = User.first
User Load (0.2ms) SELECT "users".* FROM "users" LIMIT 1
=> #<User id: 3, login: "dummy", role: nil, hashed_password: "6416111c47fa52ddfbde9e539
ee6e369807bdeab", email: "dummy#email.com", salt: "1LTzevgRHt", created_at: "2012-04-05
02:21:00", updated_at: "2012-04-05 02:21:00">
ruby-1.9.2-p318 :005 > u.role
=> nil
ruby-1.9.2-p318 :006 > u.role = "foo"
=> "foo"
ruby-1.9.2-p318 :007 > u.role
=> "foo"
ruby-1.9.2-p318 :008 > u
=> #<User id: 3, login: "dummy", role: nil, hashed_password: "6416111c47fa52ddfbde9e539
ee6e369807bdeab", email: "dummy#email.com", salt: "1LTzevgRHt", created_at: "2012-04-05
02:21:00", updated_at: "2012-04-05 02:21:00">
Migration:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.column :login, :string
t.column :role, :string
t.column :hashed_password, :string
t.column :email, :string
t.column :salt, :string
t.timestamps
end
end
end
Schema:
ActiveRecord::Schema.define(:version => 20120318205424) do
create_table "users", :force => true do |t|
t.string "login"
t.string "role"
t.string "hashed_password"
t.string "email"
t.string "salt"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
Model:
require 'digest/sha1'
class User < ActiveRecord::Base
validates_length_of :login, :within => 3..40
validates_length_of :password, :within => 4..40
validates_presence_of :login, :email, :password, :password_confirmation, :salt
validates_uniqueness_of :login, :email
validates_confirmation_of :password
validates_format_of :email, :with => /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i, :message => "Invalid email"
attr_accessor :password, :password_confirmation, :role
attr_protected :id, :salt
def self.random_string(len)
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
newpass = ""
1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
return newpass
end
def password=(pass)
#password=pass
self.salt = User.random_string(10) if !self.salt?
self.hashed_password = User.encrypt(#password, self.salt)
end
def self.encrypt(pass, salt)
Digest::SHA1.hexdigest("#{pass}#{salt}")
end
def self.authenticate(login, pass)
u=find(:first, :conditions=>["login = ?", login])
return nil if u.nil?
if User.encrypt(pass, u.salt)==u.hashed_password
# edits wont save without this
u.password=u.password_confirmation=pass
return u
end
nil
end
def send_new_password
new_pass = User.random_string(10)
self.password = self.password_confirmation = new_pass
self.save
Notification.deliver_forgot_password(self.email, self.login, new_pass)
end
def admin?
(self.role == "admin")
end
end
SQLite Update, to show it works:
sqlite> select * from users;
3|dummy||6416111c47fa52ddfbde9e539ee6e369807bdeab|dummy#email.com|1LTzevgRHt|2012-04-05 02:21:00.752890|2012-04-05 02:21:00.752890
sqlite> select role from users;
sqlite> select role from users where login = "dummy";
sqlite> update users set role = "user" where login = "dummy";
sqlite> select role from users where login = "dummy";
user
sqlite> select * from users;
3|dummy|user|6416111c47fa52ddfbde9e539ee6e369807bdeab|dummy#email.com|1LTzevgRHt|2012-04-05 02:21:00.752890|2012-04-05 02:21:00.752890
I've been messing with this for a while... thanks for any help you can give.
EDIT on request:
ruby-1.9.2-p318 :011 > User.last.update_attributes!(:role => "foo")
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
(0.1ms) begin transaction
User Exists (0.1ms) SELECT 1 FROM "users" WHERE ("users"."login" = 'dummy' AND "users"."id" != 3) LIMIT 1
User Exists (0.1ms) SELECT 1 FROM "users" WHERE ("users"."email" = 'dummy#email.com' AND "users"."id" != 3) LIMIT 1
(0.1ms) rollback transaction
ActiveRecord::RecordInvalid: Validation failed: Password is too short (minimum is 4 characters), Password can't be blank, Password confirmation can't be blank
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/validations.rb:56:in `save!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/attribute_methods/dirty.rb:33:in `save!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:246:in `block in save!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:295:in `block in with_transaction_returning_status'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:208:in `transaction'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:293:in `with_transaction_returning_status'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:246:in `save!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/persistence.rb:224:in `block in update_attributes!'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:295:in `block in with_transaction_returning_status'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:208:in `transaction'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/transactions.rb:293:in `with_transaction_returning_status'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/persistence.rb:222:in `update_attributes!'
from (irb):11
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/railties-3.2.2/lib/rails/commands/console.rb:47:in `start'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/railties-3.2.2/lib/rails/commands/console.rb:8:in `start'
from /home/jmervine/Development/personal/blog/vendor/bundle/ruby/1.9.1/gems/railties-3.2.2/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'ruby-1.9.2-p318 :012 > User.last.update_attributes!(:role => "foo")
remove :role from this line attr_accessor :password, :password_confirmation, :role