SQLite3 exception in action cable - ruby-on-rails

I'm trying to create notifications in rails 5 with action cable. Wondering if anyone could help with my troubles .
Currently I have my notifications table
Schema
create_table "notifications", force: :cascade do |t|
t.string "activity"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "recipient_id"
t.string "action"
t.string "notifiable_type"
t.integer "notifiable_id"
t.index ["user_id"], name: "index_notifications_on_user_id"
end
My Notification Model
class Notification < ApplicationRecord
belongs_to :user
belongs_to :recipient, class_name: "User"
belongs_to :notifiable, polymorphic: true
after_create_commit { NotificationBroadcastJob.perform_later(Notification.count,self)}
validates :user_id, presence: true
end
I'm having trouble understanding how to represent the user notifications within a controller and views.
For example I have the notification create method when a specific action is created.
class Comment < ApplicationRecord
after_create_commit { create_notification }
private
def create_notification
Notification.create action: "Your comment has been created", user_id: comment.user, recipient_id: comment.user
end
end
Here I attempt to tie the User & Notifications together within a helper method in application controller.
helper_method :current_notifications
def current_notifications
if current_user
#notifications = current_user.notifications.all
else
end
end
The error I receive is
SQLite3::SQLException: no such column: notifications.recipient_type: SELECT COUNT(*) FROM "notifications" WHERE "notifications"."recipient_id" = ? AND "notifications"."recipient_type" = ?
My problem again lies within how to represent the user's notifications. I'm pretty sure I'm confused on how to tie things together. I was attempting to follow Chris Oliver tutorial which I listed below.
https://gist.github.com/excid3/4ca7cbead79f06365424b98fa7f8ecf6
Any help or corrections would be helpful

In Comment:
def create_notification
Notification.create action: "Your comment has been created", user_id: comment.user.id, recipient_id: comment.user.id
end
I'm wondering if the error is coming from passing the entire user object to user_id and recipient_id rather than the id itself?

A little more critical thinking allowed me to answer my issue at least so far.
Within the application controller I ended up using
def current_notifications
if current_user
#notifications = Notification.all.where(user_id: [current_user.id])
else
end
end
So far that has solved the error I have been recieving

Related

Issue creating a car for a user in my rails app

Im very new tor ails and still learning. My project that I am working on is set up for a user to have many cars and cars belong to a user.
class User < ApplicationRecord
validates :name, presence: true, uniqueness: true
has_secure_password
has_many :cars
end
class Car < ApplicationRecord
belongs_to :user
end
My flow is set up to where after a user signs in they can create their vehicle. However I am having trouble creating the car so that it will attach to the user and I am getting an error each time I try different methods.
def create
#car = Car.new(car_params)
#user = User.find(params[:id])
#car.save
redirect_to user_path
end
private
def car_params
params.require(:car).permit(:user_id, :make, :model, :color)
end
my schema seems to be set up correctly
create_table "cars", force: :cascade do |t|
t.string "make"
t.string "model"
t.string "color"
t.integer "user_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["user_id"], name: "index_cars_on_user_id"
end
But again, I am clearly doing something wrong and I am having trouble finding my answers online.
Well, if you have a login, you probably have a current_user set up. The logged one. Inside your create method on your controller you can set the car information using the logged in user like:
def create
#car = Car.new(car_params)
#car.user_id = current_user.id
#car.save
redirect_to user_path
end
You can also remove the :user_id from the car_params if you have the information about the logged user.
If you don't have the current_user or whatever method to get the logged in user created, you will need to select the user inside the form via a HTML select or something like that, then you can keep the :user_id inside car_params and just remove the line about setting the user_id on #car to save.

How can I create a resource in Rails/SQL that belongs_to many different resources but does not require a foreign id for all of them?

Here is my recurring payment model. I want it to optionally belong to each of the included resources, but to allow creation with only one parent resource. I tried setting the default for each foreign key to 0, but I still get an error when I try to create instances saying "bank account must exist", "investment must exist", etc. I am sure there must be a way to accomplish this, but I cannot see how? *Edit: I solved this by defaulting the foreign id's to 1 instead of 0, since this will just be seed data anyway, but I would still love to know if anyone has a better solution!
class RecurringPayment < ApplicationRecord
belongs_to :bank_account
belongs_to :credit_card
belongs_to :investment
belongs_to :loan
def bank_account_name
self.try(:bank_account).try(:name)
end
def bank_account_name=(name)
bank_account = BankAccount.find_by(name: name)
if bank_account
self.bank_account = bank_account
end
end
def credit_card_provider
self.try(:credit_card).try(:provider)
end
def credit_card_provider=(provider)
credit_card = CreditCard.find_by(provider: provider)
if credit_card
self.credit_card = credit_card
end
end
def investment_name
self.try(:investment).try(:name)
end
def investment_name=(name)
investment = Investment.find_by(name: name)
if investment
self.investment = investment
end
end
def loan_name
self.try(:loan).try(:name)
end
def loan_name=(name)
loan = Loan.find_by(name: name)
if loan
self.loan = loan
end
end
end
Here is the schema:
create_table "recurring_payments", force: :cascade do |t|
t.string "source"
t.boolean "status"
t.date "pay_date"
t.integer "pay_amount"
t.integer "duration"
t.integer "bank_account_id", default: 0
t.integer "credit_card_id", default: 0
t.integer "loan_id", default: 0
t.integer "investment_id", default: 0
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "payment_frequency"
end
In Rails 5, belongs_to associations are required by default.
You can change this behavior in a config file, by adding:
Rails.application.config.active_record.belongs_to_required_by_default = false
Or in a specific class:
class RecurringPayment < ApplicationRecord
belongs_to :bank_account, optional: true
belongs_to :credit_card, optional: true
belongs_to :investment, optional: true
belongs_to :loan, optional: true
end
In your code you should always check before using the association model, as it may not exist.
Check section 4.20 in this documentation: http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html

Simple association issue with rails and not working

Here is my Schema file
ActiveRecord::Schema.define(version: 20150917104809) do
create_table "customers", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
end
create_table "orders", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "order_date"
t.integer "customers_id"
end
end
Here are the models
class Customer < ActiveRecord::Base
has_many :orders, dependent: :destroy
end
class Order < ActiveRecord::Base
belongs_to :customer
end
The migration file for association is
class AddForeignKeyToOrders < ActiveRecord::Migration
def change
add_reference :orders, :customers
end
end
Following the simple rails assoc example in the link
I created a customer record using the command
Customer.create(name: 'Someone')
and now trying to create the order
#order = #customer.orders.create(order_date: Time.now)
Am getting an error with a NilClass
NoMethodError: undefined method `orders' for nil:NilClass
May be another pair of eyes of help to tell what am I doing wrong.
You need to assign the return value of create to #customer:
#customer = Customer.create(name: 'Someone')
#order = #customer.orders.create(order_date: Time.now)
It also looks like you have a typo in your schema. It should be:
t.integer "customer_id"
EDIT: Your migration file is incorrect. It should be:
class AddForeignKeyToOrders < ActiveRecord::Migration
def change
add_reference :orders, :customer
end
end
See the add_reference API docs.
To add to #ghr's answer, your error is thus: for nil:NilClass
This means that you're trying to call a method on an object which doesn't exist. Ruby actually assigns nil classes to an NilClass object, so it's errors aren't easily recognized unless you've spent time with them.
--
You have to assign Customer.create... to a variable, otherwise Rails doesn't have the data stored for you to work with:
#customer = Customer.create(name: "Someone")
#customer.orders.create
As a note, you don't need order_date in your Order model - created_at will handle that. If you removed the order_date column from your table, you'd be able to call the following:
#app/models/order.rb
class Order < ActiveRecord::Base
belongs_to :customer
alias_attribute :date, :created_at
end
#customer.orders.first.date

Points are not adding up in my score system

I am currently working on a scoring system for my game application and for some reason points are not adding up. The goal is whenever the player guesses the correct answer, points are added. For each new player, the score is set to 0.
question#validate_answer:
def validate_answer
#correct_answer = Answer.where(correct: true).map(&:text)
#selected_answer = params[:answer]
#player_score = Player.where(id: params[:id]).map(&:score)
if #correct_answer.include? (#selected_answer)
#player_score[0] += 1
render :success
else
render :error
end
end
Quesiton.rb
class Question < ActiveRecord::Base
belongs_to :category
has_many :answers
has_one :video_clue
has_many :answers
def correct_answer
answers.find_by correct: true
end
end
Answer.rb
class Answer < ActiveRecord::Base
belongs_to :question
end
Player.rb
class Player < ActiveRecord::Base
has_secure_password
def admin?
self.admin == 'admin'
end
end
Schema Tables for Answers and Players
create_table "answers", force: :cascade do |t|
t.integer "question_id"
t.string "text"
t.boolean "correct"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "answers", ["question_id"], name: "index_answers_on_question_id", using: :btree
create_table "players", force: :cascade do |t|
t.string "user_name"
t.string "password_digest"
t.integer "score"
t.string "role"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I would restructure the code the like this:
def validate_answer
#question = Question.find(params[:q_id])
#correct_answer = Answer.find_by_question_id(params[:q_id]).text.downcase
#selected_answer = params[:answer].downcase
#player = Player.find(params[:id])
if #selected_answer == #correct_answer
#player.increment!(:score)
render :success
else
render :error
end
end
increment! automatically pings the #player object for the column specified. It saved the trouble of trying to convert it to an array and access the index which was sort of roundabout.
NOTE: Edited Answer per chat conversation.
just see how less lines of code are need to be done for that
def validate_answer
#i think this is a bad approach to compare the text of the answer
#with the text of the given answer
#the better one would be to assing UUID to the answer or just use the regular ID
# something like this params[:answer][:uuid]
# or params[:answer][:id]
# we need to find the answer related to the question, otherwise we
# could throw in just random IDs and they are still saying "correct"
given_answer = Questions.find(params[:question_id]).answers.find params[:answer][:id]
# if we use UUID we dont need to give the question id, since then the ID can't be guessed
if given_answer.correct?
# current_user is a player.
# current_user is a method from devise (u should use devise)
current_user.award_points! given_answer
render :success
else
ender :error
end
end
class Player
def award_points! answer
# adding the points to the user
# and save it
current_user.award_points += answer.points
current_user.save
#better approach would be to save the question which was answered for the user
# like has_many :answered_questions
# so then u could also track which questions already been answered by the user and not awarding him twice
end
end

Polymorphic Association and extra id field

I need some help with polymorphic associations. Below is my structure:
class Category < ActiveRecord::Base
has_ancestry
has_many :categorisations
end
class Categorisation < ActiveRecord::Base
belongs_to :category
belongs_to :categorisable, polymorphic: true
end
class classifiedAd < ActiveRecord::Base
belongs_to :user
has_one :categorisation, as: :categorisable
end
And here is my schema.rb
create_table "classifiedads", force: true do |t|
t.string "title"
t.text "body"
t.decimal "price"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "classifiedads", ["user_id"], name: "index_classifiedads_on_user_id", using: :btree
create_table "categories", force: true do |t|
t.string "name"
t.string "ancestry"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "categories", ["ancestry"], name: "index_categories_on_ancestry", using: :btree
create_table "categorisations", force: true do |t|
t.integer "category_id"
t.integer "categorisable_id"
t.string "categorisable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
It seems like the associations is correct as when I'm in the console I can do the appropriate commands and all seems to return the right results, for example: Category.first.categorisations or ClassifedAd.first.categorisation. But what I don't understand is saving the association from the Create and editing the record via the Update actions. I'm using simple_form to create my forms and when looking at the params I get the below:
{"title"=>"Tiger",
"body"=>"Huge Helicopter",
"price"=>"550.0",
"categorisation"=>"5"}
and this fails to update or even create as I get this error : Categorisation(#70249667986640) expected, got String(#70249634794540) My controller actions code are below:
def create
#classified = Classifiedad.new(classifiedad_params)
#classified.user = current_user
#classified.save
end
def update
#classified.update(classifiedad_params)
end
def classifiedad_params
params.require(:classifiedad).permit(:title, :body, :price)
end
I think it has something to do with the params as categorisation should be within a sub hash of results, is this right? Also, I need to do something extra within the actions, but what? What the params[:categorisation] value needs to do is save the number into the Categorisations.category_id table column and also save the polymorphic association. This table will be used across other models, which will also be a has_one association, as the user will only be able to select one category for each record. I really hope someone can help me here as the more I look into it the more I get confused :S Please let me know if you ned anymore info from me.
I'm using Rails 4 and Ruby 2
EDIT 2
I managed to get something working but I'm still not sure if its right. Below is the update code for the Create and Update actions. Would be good to know if there is a better way of doing this?
def create
#classified = Classifiedad.new(classifiedad_params)
#classified.user = current_user
**** NEW
cat = Categorisation.new(category_id: params[:classified][:categorisation])
#classified.categorisation = cat
**** END NEW
#classified.save
end
def update
**** NEW
#classified.categorisation.update_attribute(:category_id, params[:classified][:categorisation])
**** END NEW
#classified.update(classifiedad_params)
end

Resources