How do I get rid of undefined method `to_sym' for nil:NilClass error when deleting rows in rails? - ruby

My project is at this github: https://github.com/hoolahoop/RoR_Projects.
I have a project which has Users, Events, and a join table between the two tables. An event is owned by a user, with a foreign key on the event table. The join table allows many users to be guests for many events.
I'm trying to let owners of events add and delete multiple guests at a time.
Below is the controller action code that throws the error when deleting rows from the join table. Ctrl + f "error thrown here" to see where the error is thrown.
def create
Rails.logger.event.debug("===New Create===\n")
#user_check = true;
##event = Event.new(event_params)
#event = Event.new(event_user_params)
#users = User.new
#event.users.each do |user|
user.password = SecureRandom.base64
user.password_confirmation = user.password
#test all saves here
if(!user.try(:save))
user_check = false;
end
end
Rails.logger.event.debug("Can we save all users: #{#user_check}. If true, continue.")
if(#user_check)
#add all saves here
#add all associations here
#event.users.each do |user|
#user_in_database = User.find_by email: user.email
Rails.logger.event.debug("User in database check. Id: #{#user_in_database.id}. Email: #{#user_in_database.email}.")
if (#user_in_database.nil?) # if user is not in the database (unique email check)
# create a new user
User.transaction do
user.save
end
Rails.logger.event.debug("User id check: #{#user}")
#event_user = EventUser.new(user_id: user.id, event_id: params[:event_id])
# create a new join table record
EventUser.transaction do
#event_user.save
end
else
#event_user_join = EventUser.find_by user_id: #user_in_database.id, event_id: params[:event_id]
Rails.logger.event.debug("Is there a join on this event for this user?. Join object: #{#event_user_join}. If this is nil, no join exists.")
if (#event_user_join.nil?)
#event_user = EventUser.new(user_id: #user_in_database.id, event_id: params[:event_id])
EventUser.transaction do
#event_user.save
end
else
Rails.logger.event.debug("Join user_id: #{#event_user_join.user_id}. Join event_id: #{#event_user_join.event_id}.")
Rails.logger.event.debug("Try removing join.")
EventUser.transaction do
#event_user_join.delete
end
Rails.logger.event.debug("Removal success.")
end
end
end
Rails.logger.event.debug("===Redirect to Event Guests Page===\n")
redirect_to event_display_path(params[:event_id])
else
render 'new'
Rails.logger.event.debug("===Render New===\n")
end
end
private
def event_user_params
#params.require(:user).permit(:first_name, :last_name, :email)
params.require(:event).permit(users_attributes: [:id, :first_name, :last_name, :email, :_destroy])
end
def random_password
random_pass = SecureRandom.base64
end
Models:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :event_users
has_many :events, through: :event_users
#validation code...
end
class EventUser < ApplicationRecord
belongs_to :event
belongs_to :user
end
class Event < ApplicationRecord
#belongs_to :user
belongs_to :owner, class_name: "User", foreign_key: :user_id
has_many :event_users
has_many :users, through: :event_users
accepts_nested_attributes_for :users
#validation code...
end
Migrations:
class DeviseCreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
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.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
end
end
class AddNamesToUsers < ActiveRecord::Migration[5.1]
def change
add_column :users, :first_name, :string, null: false, default: ""
add_column :users, :last_name, :string, null: false, default: ""
end
end
class CreateEvents < ActiveRecord::Migration[5.1]
def change
create_table :events do |t|
t.string :name, null: false, default: ""
t.text :description, null: true
t.integer :option, null: false, default: 1
t.string :street_address, null: true
t.integer :apartment_number, null: true
t.string :city, null: true
t.date :date, null: true
t.time :time, null: true
t.string :password, null: false, default: ""
t.references :user, foreign_key: true
end
end
end
class CreateJoinTableEventUser < ActiveRecord::Migration[5.1]
def change
create_join_table :events, :users do |t|
t.index [:event_id, :user_id]
t.index [:user_id, :event_id]
end
end
end
class RenameTableEventsUsers < ActiveRecord::Migration[5.1]
def change
rename_table :events_users, :event_users
end
end
Full error in command prompt:
app/controllers/users_controller.rb:21:in `create'
Started POST "/events/16/users" for 127.0.0.1 at 2018-03-05 10:06:40 -0500
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"√", "authenticity_token"=>"ph5zsZQ0HhHt2NAsCtGFDUo/+PmlrQmKyeXt6dcQMnnXFVoEgeh4Srp+p0z0C8mtOhF6Uf48suCw+2YO72+bzw==", "event"=
{"users_attributes"=>{"0"=>{"first_name"=>"Test1", "last_name"=>"Test11", "email"=>"test1#test.com", "_destroy"=>"false", "id"=>"8"}, "1"=>{"first_na
me"=>"Test4", "last_name"=>"Test44", "email"=>"test4#test.com", "_destroy"=>"false", "id"=>"11"}, "2"=>{"first_name"=>"Test5", "last_name"=>"Test55",
"email"=>"test5#test.com", "_destroy"=>"false", "id"=>"12"}}}, "commit"=>"Save", "event_id"=>"16"}
Unpermitted parameter: :id
Unpermitted parameter: :id
Unpermitted parameter: :id
(0.0ms) begin transaction
User Exists (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", "test1#test.com"], ["LIMIT", 1]]
(0.0ms) rollback transaction
(0.0ms) begin transaction
User Exists (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", "test4#test.com"], ["LIMIT", 1]]
(0.0ms) rollback transaction
(0.0ms) begin transaction
User Exists (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", "test5#test.com"], ["LIMIT", 1]]
(0.0ms) rollback transaction
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", "test1#test.com"], ["LIMIT", 1]]
EventUser Load (0.0ms) SELECT "event_users".* FROM "event_users" WHERE "event_users"."user_id" = ? AND "event_users"."event_id" = ? LIMIT ? [["us
er_id", 8], ["event_id", 16], ["LIMIT", 1]]
(0.0ms) begin transaction
(0.0ms) rollback transaction
Completed 401 Unauthorized in 441ms (ActiveRecord: 2.0ms)
NoMethodError (undefined method `to_sym' for nil:NilClass):
app/controllers/users_controller.rb:56:in block (2 levels) in create'
app/controllers/users_controller.rb:54:inblock in create'
app/controllers/users_controller.rb:34:in `create'
Full error on browser
NoMethodError in UsersController#create
undefined method `to_sym' for nil:NilClass
Extracted source (around line #65):
63
64
65
66
67
68
Rails.logger.event.debug("Try removing join.")
EventUser.transaction do
#event_user_join.delete
end
Rails.logger.event.debug("Removal success.")
end
Rails.root: D:/Development/RoR_Projects/Maestro/blog
Application Trace | Framework Trace | Full Trace
app/controllers/users_controller.rb:65:in block (2 levels) in create'
app/controllers/users_controller.rb:64:inblock in create'
app/controllers/users_controller.rb:39:in `create'
Request
Parameters:
{"utf8"=>"✓","authenticity_token"=>"HfCo+U+X7DtWUrCn/O2KFEkioGtXyut99NEsjUL08DBs+4FMWkuKYAH0x8cCN8a0OQwiwwxbUBeNz6dqeotZhg==",
"event"=>
{"id"=>"16",
"owner"=>"5",
"users_attributes"=>
{"0"=>{"first_name"=>"Test1", "last_name"=>"Test11", "email"=>"test1#test.com", "_destroy"=>"false", "id"=>"8"},
"1"=>{"first_name"=>"Test4", "last_name"=>"Test44", "email"=>"test4#test.com", "_destroy"=>"false", "id"=>"11"},
"2"=>{"first_name"=>"Test5", "last_name"=>"Test55", "email"=>"test5#test.com", "_destroy"=>"false", "id"=>"12"}}},
"commit"=>"Save",
"event_id"=>"16"}
Version information:
OS: Windows 7 Professional Service Pack 1
Ruby -v: ruby 2.4.3p205 (2017-12-14 revision 61247) [x64-mingw32]
Rails -v: Rails 5.1.4
Libraries: please check gemfile.
Related lib's to this problem include gem 'bcrypt', '~> 3.1.11', gem 'devise', and gem 'cocoon'.
Additional Information:
If you need any more information to help debug this problem, I will be happy to edit this post.
I don't know where the to_sys no method error is coming from. I've found a few places inside devise where it is used, but I'm having trouble deciphering why it's happening, and which exact place it's being used.
I'm using cocoon to generate multiple user fields on my form, and then trying to save them all. Perhaps I'm using cocoon incorrectly. The sample projects didn't seem to cover my use case of having a join table.
Devise github: https://github.com/plataformatec/devise
Cocoon github: https://github.com/nathanvda/cocoon

Related

Active Record has_many :messages not saving records properly

I'm building a sinatra app with Active record. The idea is to essentially have a custom email app. Here I have the models User and Message. A User has_many :messages and a Message belongs_to :user. This may be where I have the issue. I also have it set up for a Message belongs_to :user and has_many :users.
here are the models
Now when I create a message in the action controller I am attempting to use the shove methods to put the new message in a user's messages array. If I attempt to "share" this message with multiple users at once with all the user's id's in params( #user = User.find(id) and then user.messages << #new_message) the last user will have the message stored in it's .messages array. However only the last one to be iterated.
class Message < ActiveRecord::Base
belongs_to :user
has_many :users
end
class User < ActiveRecord::Base
validates :username, presence: true, uniqueness: true
has_secure_password
has_many :messages
end
The idea is the writer "owns" the message but can share it with many users. Here are the tables
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :password_digest
end
end
end
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.string :message
t.string :author
t.integer :user_id
t.integer :user_ids
t.integer :share_id
t.string :title
t.timestamps
end
end
end
# action controller
new_params = {}
new_params[:message] = params["message"]
new_params[:title] = params["title"]
new_params[:author] = params["author"]
new_params[:user_id] = params["user_id"]
#message = Message.create(new_params)
# #share = Share.create
# #message.share_id = #share.id
response.map do |x|
x.messages << #message
x.save!
end
#all = User.all
#user = User.find_by(username: #message.author)
erb :"/user/sent"
I am fairly sure this is because my associations are not set up properly.
You need to have has-and-belongs-to-many relationship between users and messages to implement sharing multiple messages to multiple users. Create an additional record, e.g. MessageShare and do has many to it from both sides:
class MessageShare < ActiveRecord::Base
belongs_to :user
belongs_to :message
end
class Message < ActiveRecord::Base
has_many :message_shares
end
class User < ActiveRecord::Base
has_many :message_shares
end
message_shares table should have user_id and message_id integer columns.

ActiveModel::MissingAttributeError: can't write unknown attribute `attendee_id`

I am trying to create an association between a User model and an Attendance model in which an attendee_id references a user. The association is a many to many relationship between users and concerts. The join table attendances has two fields
:attendee and :concert.
seed.rb file:
require 'faker'
Concert.destroy_all
User.destroy_all
Attendance.destroy_all
15.times do
Concert.create(band: Faker::RockBand.name, venue: "#{Faker::LordOfTheRings.location}", date: Faker::Date.forward(rand(30)), start_time: "8:00 PM")
end
5.times do |number|
User.create(first_name: Faker::Name.first_name, last_name: Faker::Name.last_name, email: "#{number}#email.com", password: "password")
end
concerts = Concert.all
users = User.all
15.times do
Attendance.create(attendee: users.sample, concert: concerts.sample)
end
Here are the models:
class Attendance < ApplicationRecord
belongs_to :attendee, class_name: "User"
belongs_to :concert
end
class Concert < ApplicationRecord
validates :band, :venue, :date, :start_time, presence: true
has_many :attendances
has_many :attendees, through: :attendances
end
class User < ApplicationRecord
validates :first_name, :last_name, :email, presence: true
validates_format_of :email, with: /#/
has_secure_password
has_many :attendances, foreign_key: :attendee_id
has_many :concerts, through: :attendances
end
Here are the migrations:
class CreateAttendances < ActiveRecord::Migration[5.0]
def change
create_table :attendances do |t|
t.references :attendee
t.references :concert, index: true
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :password_digest
t.timestamps
end
end
end
class CreateConcerts < ActiveRecord::Migration[5.0]
def change
create_table :concerts do |t|
t.string :band
t.string :venue
t.datetime :date
t.time :start_time
t.timestamps
end
end
end
Looks like there are no attendee_id column
bundle exec rails db:reset (same as db:drop + db:create + db:migrate + db:seed)
And for tests bundle exec rails db:test:prepare
If it`s not solve the problem, i think, we need moar stacktraces)
I run bundle exec rake db:drop and then I created the database bundle exec rake db:create and bundle exec rake db:migrate I was then able to seed the database.
Please try to change t.references to special alias t.belongs_to.
It worked for me with Rails 5.2.1

Getting ActiveModel::MissingAttributeError: while inserting data using ROR

I am getting the following error while inserting the data into database through rails console using ROR.
Error:
irb(main):004:0> book.comments << comment
(1.0ms) begin transaction
(0.0ms) rollback transaction
ActiveModel::MissingAttributeError: can't write unknown attribute `book_id`
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4
.2.5.1/lib/active_record/attribute.rb:138:in `with_value_from_database'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4
.2.5.1/lib/active_record/attribute_set.rb:39:in `write_from_user'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4
.2.5.1/lib/active_record/attribute_methods/write.rb:74:in `write_attribute_with_
type_cast'
Here I am trying to link one table (comments) with another table (books) by inserting some data. My code flow is below:
irb(main):004:0>book=Book.find(1)
comment = Comment.new :text => "This is an comment", :author => "Adam"
book.comments << comment
.......create_comments.rb:
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.text :text
t.string :author
t.timestamps null: false
end
end
end
book.rb:
class Book < ActiveRecord::Base
has_many :comments
end
comment.rb:
class Comment < ActiveRecord::Base
belongs_to :book
end
While I am executing the last line this error is coming.
You have not book_id column in your comments table.
Follow this below steps:
rails g migration AddBookToComments book:references
which will create a migration file as:
class AddBookToComments < ActiveRecord::Migration
def change
add_reference :comments, :book, index: true, foreign_key: true
end
end
run rake db:migrate
add book_id in strong paremeters in comments_controller.rb
Then try:
> book=Book.find(1)
> comment = book.comments.new(:text => "This is an comment", :author => "Adam")
> comment.save!

How do I get Devise 3.4 to permit Parameters Rails 4.2

Suggestions on how to improve this question are welcome
I added 3 things to the Devise user after generating it.
t.integer "role"
t.string "firstname"
t.string "lastname"
At User Signup these parameters are permitted and user is created correctly.
When a user tries to edit their account the "firstname" and "lastname" values can be changed fine but when a user tries to change their role on their /users/edit page, no error is given, flash says "account updated successfully" but the role value have not changed.
From /log/development.log showing all 3 parameters as unpermitted, if this really is the case I don't know why the other two can be updated.
Parameters: {"utf8"=>"✓", "authenticity_token"=>"LnVPFFJKV+RtnB21ZUGr4HF1siVcEuT/BRXaLVkch1nWQXiGRFVGhdWchlQSZ9A7mFgKX2njEjCbqR4CHp5hmQ==", "user"=>{"role"=>"worker", "firstname"=>"asdfDe Wet", "lastname"=>"Blomerus", "email"=>"dewet#blomerus.org", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "current_password"=>"[FILTERED]"}, "commit"=>"Update"}
[1m[36mUser Load (0.8ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1[0m [["id", 6]]
[1m[35mUser Load (0.4ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 6]]
Unpermitted parameters: role, firstname, lastname
Redirected to http://localhost:3000/
Completed 302 Found in 84ms (ActiveRecord: 1.5ms)
/config/initializers/devise_permitted_parameters.rb
module DevisePermittedParameters
extend ActiveSupport::Concern
included do
before_filter :configure_permitted_parameters
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << [:firstname, :lastname, :role]
devise_parameter_sanitizer.for(:account_update) << [:firstname, :lastname, :role]
end
end
DeviseController.send :include, DevisePermittedParameters
Relevant parts of /app/controllers/users_controller.rb
def update
#user = User.find(params[:id])
if #user.update_attributes(secure_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
private
def secure_params
params.require(:user).permit(:role, :firstname, :lastname)
end
The update action never runs, I can completely comment it out and nothing changes.
This is what works for me with devise:
I change the users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_permitted_parameters, only: [:create]
before_filter :configure_account_update_params, only: [:update]
def create
super
end
# GET /resource/edit
def edit
super
end
# PUT /resource
def update
super
end
# DELETE /resource
def destroy
super
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:first_name, :last_name, :user_name, :email, :password, :password_confirmation, :avatar, :avatar_cache)
end
end
def configure_account_update_params
devise_parameter_sanitizer.for(:account_update)do |u|
u.permit(:first_name, :last_name, :user_name, :email, :password, :password_confirmation, :current_password, :avatar, :avatar_cache)
end
end
I don't define any update action in the users_controller.rb . It is not needed. Also, I don;t use any type of module that you are defining and it works fine.

Rails -- ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column:

Having major Rails issues currently. I'm creating a School-Dashboard app that takes an xref table called Enrollments that relates Courses and Students.
Any time I try to update a grade for an Enrollment, I constantly get this line
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: UPDATE
"enrollments" SET "grade" = ?, "updated_at" = ? WHERE "enrollments"."" IS NULL
This line does not appear when I update attributes for Courses or Students. Only for the :grade attribute in Enrollment.
For some reason, it isn't being read properly, even though it is a legitimate attribute in my db for Enrollment (check out my schema).
I do all of my preliminary work in the rails sandbox.
Using ruby 2.1.1, Rails 4.1.0.rc1
I'd really love some help here.
Here are my corresponding models
class Student < ActiveRecord::Base
has_many :enrollments
has_many :courses, through: :enrollments
end
class Course < ActiveRecord::Base
has_many :enrollments
has_many :students, through: :enrollments
end
class Enrollment < ActiveRecord::Base
belongs_to :student
belongs_to :course
end
The controllers:
Students
class StudentsController < ApplicationController
def index
#students = Student.all
end
def new
#student = Student.new
end
def show
end
def update
#student.update_attributes(student_params) ? redirect_to #student : render 'edit'
end
def create
#student = Student.new(student_params)
#student.save ? redirect_to #student : render 'new'
end
def destroy
end
def edit
end
private
def student_params
params.require(:student).permit(:first_name, :last_name, :student_number, :email)
end
end
Courses
class CoursesController < ApplicationController
def index
#courses = Course.all
end
def new
#course = Course.new
end
def show
end
def update
#course.update_attributes(course_params) ? redirect_to #course : render 'edit'
end
def create
#course = Course.new(course_params)
#course.save ? redirect_to #course : render 'new'
end
def destroy
end
def edit
# code here
end
private
def course_params
params.require(:course).permit(:course_name, :course_number)
end
end
Enrollments
class EnrollmentsController < ApplicationController
attr_accessor :course_id, :student_id, :grade
def index
#enrollments = Enrollment.all
end
def new
#enrollment = Enrollment.new
end
def create
#enrollment = Enrollment.new(enrollment_params)
#enrollment.save ? redirect_to #enrollment : render 'new'
end
def update
#enrollment.update_attributes(enrollment_params) ? redirect_to #enrollment : render 'edit'
end
def show
end
def destroy
#enrollment.destroy
end
def edit
# code here
end
private
def enrollment_params
params.require(:enrollment).permit(:course_id, :student_id, :grade)
end
end
And finally my schema.rb
ActiveRecord::Schema.define(version: 20140417152720) do
create_table "courses", force: true do |t|
t.string "course_name"
t.integer "course_number"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "enrollments", id: false, force: true do |t|
t.integer "course_id", null: false
t.integer "student_id", null: false
t.decimal "grade", precision: 5, scale: 2
t.datetime "created_at"
t.datetime "updated_at"
end
# noinspection RailsParamDefResolve
add_index "enrollments", ["course_id", "student_id"], name: "index_enrollments_on_course_id_and_student_id"
# noinspection RailsParamDefResolve
add_index "enrollments", ["student_id", "course_id"], name: "index_enrollments_on_student_id_and_course_id"
create_table "students", force: true do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.integer "student_number"
t.datetime "created_at"
t.datetime "updated_at"
end
end
Looks like I figured it out on my own!
So here's a bit of rails convention that needs to be addressed. The problem was with my database setup for 'Enrollments'. When I run the command
rails g migration CreateJoinTableEnrollments course student
Rails does too much work for me in my migration file (except for the table name and grade, I added that)
class CreateJoinTableEnrollments < ActiveRecord::Migration
def change
create_join_table :courses, :students, table_name: :enrollments, id: false, force: true do |t|
t.index [:course_id, :student_id], null: false
t.index [:student_id, :course_id], null :false
t.decimal :grade, precision: 5, scale: 2
t.timestamps
end
end
end
In reality, I didn't need any of that. In order to manipulate specific data in a row for Enrollments, there has to be an identifier for that row. With id: false, force: true that option got nullified. I also simplified things with the indexing. I just created regular old columns instead. Now my migration file looks like this.
class CreateJoinTableEnrollments < ActiveRecord::Migration
def change
create_table :enrollments do |t|
t.integer :course_id, null: false
t.integer :student_id, null: false
t.decimal :grade, precision: 5, scale: 2
t.timestamps
end
end
end
And with that, no issues! I've just been breaking my head over that for the past 2 days. Hope this helps anyone else who has this issue.

Resources