Rails 3.2: Trying to pass User field through nested form - ruby-on-rails

So based on Ryan Bates rails cast (http://railscasts.com/episodes/196-nested-model-form-revised) I am creating a nested form. The part of the rails application that I am trying to get to work ideally does the following:
Let a current user ask a question
Then provide an answer for that question afterwards
I managed to get everything working, except that when I try to submit the form once everything is filled out, I keep getting the following error:
undefined method `meter_id' for nil:NilClass
app/models/answer.rb:13:in `associate_with_meter_id'
app/controllers/questions_controller.rb:13:in `create'
I believe I know what is wrong, but I am not sure how to fix it. The meter_id is returning an undefined value, because it is not being passed the correct value. Here is the method that associates the meter_id (of answers) with the meter_id (of users):
def associate_with_meter_id
self.meter_id = user.meter_id
end
Here is a partial of my user model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,
:home_size_sf, :meter_id, :avg_monthly_kwh, :discovery_score,
:questions_attributes, :answers_attributes
has_many :data_records, :foreign_key => :meter_id, :primary_key => :meter_id, :class_name => "DataRecord"
has_many :questions
has_many :answers
accepts_nested_attributes_for :questions, :answers
Here is the questions model
class Question < ActiveRecord::Base
attr_accessible :description, :taxonomy, :user_id, :answers_attributes
belongs_to :user
has_many :answers
accepts_nested_attributes_for :answers
validates :description, presence: { :on => :create }
validates :taxonomy, presence: { :on => :create }
def relevance_score
rand
end
end
Here is the questions controller
class QuestionsController < ApplicationController
respond_to :html, :json
def index
#question = current_user.questions.new
#questions = current_user.questions.all
end
def create
#question = current_user.questions.new(params[:question])
if !params[:update_button]
if #question.valid?
if params[:next_button] || !#question.save
render 'index'
elsif !params[:next_button] && params[:submit_button] && #question.save
flash[:success] = "Your question and answer have been saved."
respond_with #question, :location => questions_path
end
else
render 'index'
end
else
render 'index'
end
end
def next
#question = current_user.unanswered.first
#answer = Answer.new(:question => #question, :user => current_user)
respond_to do |format|
format.js
end
end
end
answers model
class Answer < ActiveRecord::Base
attr_accessible :value, :user_id, :meter_id, :question_id
belongs_to :user
belongs_to :question
validates :value, presence: true, :numericality => true
before_save :associate_with_meter_id
def associate_with_meter_id
self.meter_id = user.meter_id **(<-- line 13 from the error message)**
end
end
answers controller
class AnswersController < ApplicationController
respond_to :html, :json
def index
#answers = current_user.answers
end
def create
#answer = current_user.answers.create(params[:answer])
if #answer.save
flash[:notice] = "Thanks for for answer. Please continue with your input...."
respond_with #answer, :location => root_url
end
end
end
database schema
ActiveRecord::Schema.define(:version => 20120210184340) do
create_table "answers", :force => true do |t|
t.integer "meter_id"
t.integer "user_id"
t.integer "question_id"
t.float "value"
t.float "what_if_value"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "data_records", :force => true do |t|
t.datetime "timestamp"
t.float "value"
t.integer "meter_id"
t.string "status_code"
end
create_table "questions", :force => true do |t|
t.string "description"
t.string "taxonomy"
t.string "coeff"
t.float "rsquare", :default => 0.0
t.string "rank"
t.string "responses"
t.string "skips"
t.string "avganswer"
t.float "pval", :default => 0.0
t.float "quality", :default => 0.0
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "setup_constants", :force => true do |t|
t.float "exp_model", :default => 0.0
t.float "exp_pval_const", :default => 0.0
end
create_table "users", :force => true do |t|
t.integer "meter_id"
t.float "home_size_sf", :default => 1000.0
t.text "notifications"
t.float "avg_monthly_kwh"
t.float "ee_score"
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"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
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
Note:
In the answers model (above), the line:
self.meter_id = user.meter_id
Associates the meter_id of the answer model with the meter_id of the user model. I believe this is where the issue is. I tried changing the above line to:
self.meter_id = 2
And then everything worked fine, so it's obvious that the user.meter_id is undefined, so I'm not sure how to pass that value through the nested form? I tried using a hidden field but with no luck (the following is a nested fields_for :answers, within a form_for #questions):
<fieldset>
<%= f.label "Yes" %>
<%= f.radio_button :value, 1 %>
<%= f.label "No" %>
<%= f.radio_button :value, 0 %>
<%= f.hidden_field :user_id %>
<%= f.hidden_field :question_id %>
<%= f.hidden_field :meter_id %>
</fieldset>

First of all, you don't want to pass the current user in the view for security reasons. Instead, you want to do it from the controller.
A starting point (assuming you have current_user):
#answer = current_user.answers.create(params[:answer].merge(:user => current_user))
From there, it's up to you how to pass the user to the answer model. You could, however, use this:
self.meter_id = question.user.meter_id
Assuming that's appropriate.

Related

How can I display the name instead of an ID in rails

I am trying to have a drop down from the other model and display its name in the index page
I have a 3 tables "students", "classrooms", and "classroom_students"
what I am trying is when a student is created he should be able to add the classroom from a dropdown which is populated from classroom table, at the moment the drop down is working however it is getting the id from the dropdown
How to get the classroom name to display in index page
classroom model
class Classroom < ApplicationRecord
belongs_to :user
has_many :classroom_students
has_many :students, through: :classroom_students
end
student model
class Student < ApplicationRecord
has_many :classroom_students
has_many :classrooms, through: :classroom_students
validates :student_fname, presence: true, length: { minimum: 3, maximum: 50 }
end
classroom_student model
class ClassroomStudent < ApplicationRecord
belongs_to :classroom
belongs_to :student
end
students controller
def student_params
params.require(:student).permit(:student_fname, :student_lname, :gender, :dob, :aboriginal, :esl, :special_provisions, :user_id, :classroom_id, :group_id, :active)
end
classrooms controller
def classroom_params
params.require(:classroom).permit(:classroom_name, :classroom_year, :classroom_student)
end
students views form
<%= form.select :classroom_id, Classroom.where(:user_id => current_user.id).map {|r| [r.classroom_name, r.id]} %>
student index
at the moment it is id but I want it to be classroom name
<td><%= student.classroom_id %>
Schema file
create_table "classroom_students", force: :cascade do |t|
t.integer "classroom_id"
t.integer "student_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "classrooms", force: :cascade do |t|
t.string "classroom_name"
t.date "year"
t.string "classroom_student"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "users_id"
t.integer "user_id"
t.string "classroom_year"
t.index ["users_id"], name: "index_classrooms_on_users_id"
end
create_table "students", force: :cascade do |t|
t.string "student_fname"
t.string "student_lname"
t.boolean "gender"
t.string "dob"
t.boolean "aboriginal"
t.boolean "esl"
t.text "special_provisions"
t.integer "user_id"
t.integer "classroom_id"
t.integer "group_id"
t.boolean "active"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "classroom_name"
end
Your association says that student has many classrooms but your database schema says you have a clasroom_id too in the students table. Remove that classroom_id first if you need to associate a student to multiple classrooms. Then your select says:
<%= form.select :classroom_id, Classroom.where(:user_id => current_user.id).map {|r| [r.classroom_name, r.id]} %>
Now as you have multiple classrooms associated to one student so this will not work because classroom_id is not valid. Instead it should be like this:
<%= f.select :classroom_ids, Classroom.where(user_id: current_user.id).map { |r| [r.classroom_name, r.id] }, {}, multiple: true %>
This will associate multiple classrooms with the student.
And donot forget to add classroom_ids in strong params:
def student_params
params.require(:student).permit(:student_fname, :student_lname, :gender, :dob, :aboriginal, :esl, :special_provisions, :user_id, :classroom_id, :group_id, :active, :classroom_ids => [])
end
Hope this helps.
First of all, you have an association User has_many :classrooms, so you can't think that you only have 1 classroom.
You can get all the classes associated to an user with something like this:
<%= f.form_for #student do |f| %>
<%= f.collection_select(:classrrom_id, Classroom.all, :id, :classroom_name,
{:prompt => "Select your classrooms"}, {:multiple => true}) %>
<% end %>
And at your students_controller.rb you should add classroom_ids to your params
def student_params
params.require(:student).permit(:student_fname, :student_lname, :gender,
:dob, :aboriginal, :esl, :special_provisions, :user_id, :classroom_id,
:group_id, :active, :classroom_ids => [])
end

Ruby on Rails Params set recipient and sender with users_id

Have a recipient and sender, both of the same class(Message) for a messaging system in rails. Want to set the params for both i.e. if user creates a message sender by default is the user_id and recipient will be the contact selected from the users contact list.
Currently the database is only receiving a user_id to the recipient_id column which is wrong and should be to sender_id column. Sender_id receives nothing.
After reading, some say not to amend the params as this is bad practice. So set a hidden field in the message view (like the body and title) yet this isn't pushing in to the database.
Two questions, is this process an appropriate rails practice? (ask this as new to rails) If not: can you advise another path or direction? If so: any ideas/thoughts why this isn't saving in to the database?
user model
class User < ActiveRecord::Base
has_many :messages, class_name: "Message", foreign_key: "recipient_id"
has_many :sent_messages, class_name: "Message", foreign_key: "sender_id"
has_many :contacts, dependent: :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_presence_of :firstname, allow_blank: false
validates_presence_of :surname, allow_blank: false
end
message model
class Message < ActiveRecord::Base
belongs_to :sender, class_name: "User", foreign_key: "sender_id"
belongs_to :recipient, class_name: "User", foreign_key: "recipient_id"
validates_presence_of :body, :title
end
Messages controller
class MessagesController < ApplicationController
before_action :message, only: [:show]
before_action :authenticate_user!
def index
#messages = current_user.messages
end
def new
#message = Message.new
end
def create
current_user.messages.create(message_params)
redirect_to '/messages'
end
def show
end
private
def message_params
params.require(:message).permit(:title, :body, :sender_id, :recipient_id)
end
def message
#message = Message.find(params[:id])
end
end
message/new view
<%= form_for #message do |f| %>
<%= hidden_field_tag :sender_id, current_user.id %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
schema
ActiveRecord::Schema.define(version: 20160517131719) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "contacts", force: :cascade do |t|
t.string "firstname"
t.string "surname"
t.string "email"
t.integer "phone"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "user_id"
end
add_index "contacts", ["user_id"], name: "index_contacts_on_user_id", using: :btree
create_table "messages", force: :cascade do |t|
t.string "title"
t.text "body"
t.integer "sender_id"
t.integer "recipient_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: :cascade 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.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "firstname"
t.string "surname"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
add_foreign_key "contacts", "users"
end
Try changing your form to this:
<%= form_for #message do |f| %>
<%= f.hidden_field :sender_id, value: current_user.id %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
Currently the database is only receiving a user_id to the recipient_id
column which is wrong and should be to sender_id column.
In your create action, you have current_user.messages.create(message_params). This creates a message record in the DB with the foreign key's(i.e, recipient_id in your case) value with the parent's(user) id. This is the reason, the recipient_id gets the value of user's id.
Sender_id receives nothing.
This is because the hidden_field set for sender_id is not wrapped with the form builder instance. You need to change
<%= hidden_field_tag :sender_id, current_user.id %>
to
<%= f.hidden_field :sender_id, current_user.id %>

undefined method `sender_id=' for nil:NilClass

currently I am creating a snapchat like application by using Rails. I get the error:
undefined method `sender_id=' for nil:NilClass
while I am trying to submit the new message form, I don't really know where I make the mistake. Moreover, I am not sure about the logic of the create action in my messages_controller, basically I just want the sender sends a message to the people in their friendlist by choosing one or more recipients at the same time(of course, the recipients must be in their friendlist, and I have already accomplished this feature). However, because I still haven't figured out how can I pass the the params recipient_id to the form(I am using simple form gem and devise gem by the way), so I hardcoded the recipient_id in my create action. So,all of suggestions/advices are welcome.
Here are my files:
messages_controller.rb:
class MessagesController < ApplicationController
def new
#message = Message.new
end
def create
#message.sender_id = current_user
#message.recipient_id = current_user.friendships.friend_id
#message = Message.new(message_params)
if #message.save?
flash[:success] = 'Message sent successfully'
redirect_to welcome_profile_path
else
render 'new'
end
end
private
def message_params
params.require(:message).permit(:body, :sender_id, :recipient_id, :user_id)
end
end
messages/new.html.erb:
<h1>Create New Message</h1>
<%= simple_form_for #message do |f| %>
<%= f.input :body %>
<%#= f.association :user, :as => :hidden, :input_html => { :value => current_user.id }, :include_blank => false %>
<%= f.button :submit, "Send Message", class: "btn btn-secondary" %>
<% end %>
message.rb:
class Message < ActiveRecord::Base
belongs_to :user, foreign_key: :recipient_id
belongs_to :sender, :foreign_key => :sender_id, class_name: 'User'
belongs_to :recipient, :foreign_key => :recipient_id, class_name: 'User'
validates_presence_of :body
end
user.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :username,
:presence => true,
:uniqueness => {
:case_sensitive => false
}
validate :validate_username
def validate_username
if User.where(email: username).exists?
errors.add(:username, :invalid)
end
end
has_many :friendships
has_many :friends, :through => :friendships
has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
has_many :inverse_friends, :through => :inverse_friendships, :source => :user
has_many :messages, dependent: :destroy
end
schema.rb:
ActiveRecord::Schema.define(version: 20160316170009) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "friendships", force: :cascade do |t|
t.integer "user_id"
t.integer "friend_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "messages", force: :cascade do |t|
t.text "body"
t.boolean "read"
t.integer "sender_id"
t.integer "recipient_id"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "messages", ["user_id"], name: "index_messages_on_user_id", using: :btree
create_table "users", force: :cascade 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.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "username"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
add_index "users", ["username"], name: "index_users_on_username", unique: true, using: :btree
add_foreign_key "messages", "users"
end
That error is because you don't have #message defined before setting #message.sender_id in your create action. Move #message = Message.new(message_params) to the top of the create action before setting #message.sender_id as follows:
class MessagesController < ApplicationController
...
def create
#message = Message.new(message_params)
#message.sender_id = current_user
#message.recipient_id = current_user.friendships.friend_id
if #message.save?
flash[:success] = 'Message sent successfully'
redirect_to welcome_profile_path
else
render 'new'
end
end
private
def message_params
params.require(:message).permit(:body, :sender_id, :recipient_id, :user_id)
end
end
The second part of the question - current_user is available in your controllers, so you don't need a hidden field for that. You can call #message.sender_id = current_user.id in your create action as you currently have. Next, to set #message.recipient_id, you could update your new.html.erb as follows:
# new.html.erb
<h1>Create New Message</h1>
<%= simple_form_for #message do |f| %>
<%= f.input :body %>
<%# Updated the following line. You could chose to create a hidden field here, or however you wish to implement this in your view as long as you specify `recipient` as the association or `recipient_id` as the field. %>
<%= f.association :recipient, :include_blank => false %>
<%= f.button :submit, "Send Message", class: "btn btn-secondary" %>
<% end %>
With the above setup your create action could be updated to:
# app/controllers/messages_controller.rb
def create
#message = Message.new(message_params)
#message.sender_id = current_user
if #message.save?
flash[:success] = 'Message sent successfully'
redirect_to welcome_profile_path
else
render 'new'
end
end

Unable to insert data in table using form to submit data

I am unable to insert data in user_preferences table where as I am getting all the attributes in params. I tried inserting value from console by following way since association between User has_one user_preference and UserPreference belongs_to User:
user = User.find(1)
user.user_preferences.title = "MyTitle"
I am getting undefined method "title"
user_preference.rb
class UserPreference < ActiveRecord::Base
belongs_to :user
def self.bgcolor_options
[["Orange", "#FF3300"], ["Green", "#00FF00"], ["Blue", "#0000FF"], ["Pink", "#FF0066"], ["Yellow", "#FFFF00"], ["White", "#FFFFFF"]]
end
def self.font_options
[["Times New Roman", "Times New Roman"], ["Verdana", "Verdana"],["Arial", "Arial"],["sans-serif", "sans-serif"]]
end
end
user_preferences_controller.rb
class UserPreferencesController < ApplicationController
def new
#user_preference = UserPreference.new
end
def create
#user_preference = UserPreference.new(user_pref_params)
#user_preference.save unless user_signed_in?
render 'user_preferences/new'
end
def edit
end
def update
end
private
def user_pref_params
params.require(:user_preference).permit(:title, :bgcolor, :font, :description)
end
end
routes.rb
Rails.application.routes.draw do
resources :user_preferences
post "/user_preferences/new"
devise_for :users
devise_scope :user do
authenticated :user do
root :to => 'user_preferences#new', as: :authenticated_root
end
unauthenticated :user do
root :to => 'devise/registrations#new', as: :unauthenticated_root
end
end
user_preferences/new.html.erb
<%= form_for #user_preference, :url => { :action => "create" } do |u|%>
<div style="background-color:#{current_user.user_preference.bgcolor.nil? ? '#FFFFFF' : current_user.user_preference.bgcolor}">
<p>
<%= u.label :title %><br>
<%= u.text_field :title %>
</p>
<p>
<%= u.label :description %><br>
<%= u.text_field :description %>
</p>
<p> <%= u.label :back_ground_color %><br>
<%= u.select :bgcolor, options_for_select(UserPreference.bgcolor_options) %>
</p>
<p>
<%= u.label :font %><br>
<%= u.select :font, options_for_select(UserPreference.font_options) %>
</p>
<br >
<p>
<%= u.submit %>
</p>
<hr >
<div style="background: #{current_user.user_preferences.bgcolor};"></div>
<div style="background-color:#{current_user.user_preferences.font.nil? ? 'Arial' : current_user.font}">
This is the changes made in background
</div>
</div>
<% end %>
schema.rb
ActiveRecord::Schema.define(version: 20150422034042) do
create_table "user_preferences", force: :cascade do |t|
t.text "title"
t.string "font"
t.text "description"
t.string "bgcolor"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "users", force: :cascade 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.datetime "created_at"
t.datetime "updated_at"
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
Adding User.rb code
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
has_one :user_preference
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
You're accessing the wrong association on user:
user.user_preferences.title = "MyTitle"
user_preferences is a has_many association, and returns multiple objects. The error itself also mentions this (something like ActiveRecord_Associations_CollectionProxy).
Simply access the has_one association and it will work:
user.user_preference.title = "MyTitle"
for the console part its not a javascript if you want to set to relation you have to use a variabel to assign, and not to use user_preference(s) note the s and its has_one relation and it should be user_preference and in your User Model it should be
# User Model
has_one :user_preference
# Console
user = User.first
preferences = user.user_preference
preferences.title = "MyTitle"
preferences.save
user.reload.preferences.title # should be "MyTitle"

adding a foreign key in the table

I keep getting this exception: "SQLite3::SQLException: no such column: books.user_id: SELECT "books".* FROM "books" WHERE ("books".user_id = 4)". Which sounds like there is no user_id in the books table.
So I just installed the Foreigner plugin and added "t.integer :user_id, :null => false" and "add_foreign_key(:books, :users)" in the book migration file. I ran "rake db:migrate", but still it is giving me the same exception.
I am using Rails 3 in Windows and Devise to authenticate user.
HOME VIEW
<p><%= link_to "Add new Book",:controller =>"book", :action => 'new' %></p>
<% #books.each do |b| %>
<p><%= b.author%></p>
<p><%= b.title%></p>
<%end%>
HOME CONTROLLER
class HomeController < ApplicationController
def index
#user = current_user
#user.books||=Book.new
#books=#user.books
end
end
BOOK CONTROLLER
class BookController < ApplicationController
def new
#books = Book.new
# redirect_to :controller=>"home" ,:action=>"index"
end
def create
#books = Book.new(params[:book])
if #books.save
render "home/index"
#redirect_to :controller=>"home" ,:action=>"index"
else
render :action => 'new'
end
end
CREATE TABLE/BOOK MIGRATION
class CreateBooks < ActiveRecord::Migration
def self.up
create_table :books do |t|
t.text :title
t.text :author
t.integer :user_id, :null => false
t.timestamps
end
add_foreign_key(:books, :users)
end
BOOK VIEW
<h1>Book#new</h1>
<%= form_for(:book) do |f| %>
<p><%= f.text_field :title %></p>
<p><%= f.text_field :author %></p>
<p><%= f.submit "Add book"%>
BOOK MODEL
class Book < ActiveRecord::Base
belongs_to :user
end
USER MODEL
class User < ActiveRecord::Base
has_many :books
# Include default devise modules. Others available are:
# :token_authenticatable, :lockable, :timeoutable and :activatable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation,:firstname,:lastname,:school,:major,:sex,:zipcode
end
ROUTE
Campus::Application.routes.draw do
get "book/index"
get "book/edit"
get "book/new"
get "home/edit"
devise_for :users
resources :book
root :to=> "home#index"
match '/book/new' =>"home#index"
end
DATABASE SCHEMA
ActiveRecord::Schema.define(:version => 20110609055608) do
create_table "books", :force => true do |t|
t.text "title"
t.text "author"
t.integer "user_id", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "courses", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "strong_ins", :force => true do |t|
t.string "subject"
t.string "topic"
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", :limit => 128, :default => "", :null => false
t.string "password_salt", :default => "", :null => false
t.string "reset_password_token"
t.string "remember_token"
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 "firstname"
t.string "lastname"
t.text "school"
t.text "major"
t.string "sex"
t.integer "zipcode"
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
create_table "weak_ins", :force => true do |t|
t.string "subject"
t.string "topic"
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
end
end
The user_id column should appear in the schema after running the migration. It's not in your listing, so I'd say that's the problem. Make sure rake db:migrate is completing without errors. You can redo the migration with rake db:rollback && rake db:migrate, if necessary.

Resources