Devise-JWT Rails: Logging in returns wrong user's data - ruby-on-rails

I'm using the devise-jwt gem for authenticating my Rails backend and React frontend. Everything was working perfectly with this until I created a second user and tried logging them in. Even though the backend is processing the correct email and password, it returns the wrong user in the response. Any ideas here?
class Users::SessionsController < Devise::SessionsController
include RackSessionFix
respond_to :json
private
def respond_with(resource, _opts = {})
render json: {
status: {code: 200, message: 'Logged in sucessfully.'},
data: UserSerializer.new(resource).serializable_hash[:data][:attributes]
}, status: :ok
end
def respond_to_on_destroy
if current_user
render json: {
status: 200,
message: "logged out successfully"
}, status: :ok
else
render json: {
status: 401,
message: "Couldn't find an active session."
}, status: :unauthorized
end
end
end
class CurrentUserController < ApplicationController
before_action :authenticate_user!
def index
render json: UserSerializer.new(current_user).serializable_hash[:data][:attributes], status: :ok
end
end
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
include Devise::JWT::RevocationStrategies::JTIMatcher
devise :database_authenticatable, :validatable,
:jwt_authenticatable, :timeoutable, jwt_revocation_strategy: self
end
ActiveRecord::Schema[7.0].define(version: 2023_02_17_165020) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "foods", force: :cascade do |t|
t.string "name"
t.float "price"
t.string "category"
t.text "add_ons"
t.text "details"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "jti", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["jti"], name: "index_users_on_jti", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
There's much more to this file, but the most important:
config.jwt do |jwt|
jwt.secret = Rails.application.credentials.fetch(:secret_key_base)
jwt.dispatch_requests = [
['POST', %r{^/login$}]
]
jwt.revocation_requests = [
['DELETE', %r{^/logout$}]
]
jwt.expiration_time = 15.seconds
end

Related

how i display seller products on seller dashboard no other seller can delete or edit his product and show seller product to buyer

Here is the application controller
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
private
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:role])
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:name, :email, :password, :first_name, :last_name,
:user_name, :Address, :city, :postal_code, :password_confirmation, :role)}
end
protected
def after_sign_in_path_for(resource)
if current_user.Buyer?
root_path
else
dashboard_path
end
end
end
here is the home controller
class HomeController < ApplicationController
def homepage
end
def dashboard
end
end
Here is the product controller
class ProductsController < InheritedResources::Base
private
def product_params
params.require(:product).permit(:title, :description, :price, images: [])
end
end
Here is the product model
class Product < ApplicationRecord
has_many_attached :images
validates :title, presence: true
validates :description, presence: true
validates :price, presence: true
validate :image_type
belongs_to :user
private
def image_type
if images.attached? ==false
errors.add(:images, " are missing")
end
end
end
Here is the user model
class User < ApplicationRecord
validates :email, format: { with: /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i, message: "Email invalid" },
uniqueness: { case_sensitive: false },length: { minimum: 4, maximum: 254 }
has_many :products
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
enum role: { Buyer: 0, Seller: 1 }
devise :registerable, :confirmable
end
Here is the schema
ActiveRecord::Schema.define(version: 2022_03_03_093335) do
create_table "active_admin_comments", force: :cascade do |t|
t.string "namespace"
t.text "body"
t.string "resource_type"
t.integer "resource_id"
t.string "author_type"
t.integer "author_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id"
t.index ["namespace"], name: "index_active_admin_comments_on_namespace"
t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id"
end
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.integer "record_id", null: false
t.integer "blob_id", null: false
t.datetime "created_at", null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
create_table "active_storage_blobs", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
t.text "metadata"
t.bigint "byte_size", null: false
t.string "checksum", null: false
t.datetime "created_at", null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
create_table "admin_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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_admin_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true
end
create_table "products", force: :cascade do |t|
t.string "title"
t.string "description"
t.decimal "price"
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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "role", default: 0
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.string "first_name"
t.string "last_name"
t.string "user_name"
t.string "city"
t.string "Address"
t.integer "postal_code"
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
end
end
In the home folder file dasboard.html.erb
<h1>Dashboard</h1>
<%= link_to 'Products', products_path %>
When user signup as a seller it should add products add product images delete product
and when someone signin as buyer the buyer see seller products only how i can implement this

Create action in controller to create an appointment between users and doctors - 204 NO RESPONSE

I'm building an API for an app where a user can make appointments with a doctor.
Everything is working just fine but it's returning 204 - No content when I try to post a new appointment in Postman.
My schema:
create_table "appointments", force: :cascade do |t|
t.date "date"
t.time "time"
t.bigint "user_id"
t.bigint "doctor_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["doctor_id"], name: "index_appointments_on_doctor_id"
t.index ["user_id"], name: "index_appointments_on_user_id"
end
create_table "doctors", force: :cascade do |t|
t.string "name"
t.string "speciality"
t.integer "years_of_experience"
t.integer "likes"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email"
t.string "password_digest"
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "appointments", "doctors"
add_foreign_key "appointments", "users"
end
My appointments controller:
class Api::V1::AppointmentsController < ApplicationController
include CurrentUserConcern
def index
#appointments = Appointment.all
render json: #appointments
end
def create
if #current_user
#appointment = #current_user.appointments.build(appointment_params)
if #appointment.save
render json: #appointment
else
render json: { status: 401 }
end
end
end
private
def appointment_params
params.require(:appointment).permit(:time, :date, #current_user.id, :doctor_id)
end
end
First of all there's not need of sending #current_user.id in appointment_params as user_id will be assigned automatically when this line #appointment = #current_user.appointments.build(appointment_params) execute.
Coming to your issue make sure you are sending a POST request and "body" data in the correct JSON format from PostMan. As per your method appointment_params the request body should look like this
{
appointment: {
time: "",
date: "",
doctor_id:
}
}

Rails: Show action in controller is unable to access foreign key value

I am attempting to build a chess application, and am testing the logic of the ability to only select pieces that match the color of the player. The method in the Piece model is passing all RSpec tests, but I run into an error while testing the show action in the pieces controller. I have narrowed down the issue to the pieces controller being unable to access the white_player_id column. It is able to access all other columns in the games table. I do not have white_player or black_player models, but I do assign the IDs based on the current_user. When a game is created, the current_user automatically becomes the white player (user.id = white_player_id), and the black player is the second user who joins the game after its creation.
How can I get the pieces controller to access the white_player_id value? I don't want to create white_player and black_player models, because they are only needed for color checks.
If it matters, the database I am using is PostgreSQL.
This is the Piece model:
class Piece < ApplicationRecord
belongs_to :game
validates :x, numericality: true
validates :y, numericality: true
scope :black_pieces, ->() { where(color: 'black') }
scope :white_pieces, ->() { where(color: 'white') }
scope :active, -> { where(captured: false) }
def white?
color == 'white'
end
def black?
color == 'black'
end
def piece_color_matches_user_color?(user)
if color == 'white' && user.id == game.white_player_id
true
elsif color == 'black' && user.id == game.black_player_id
true
else
false
end
end
# ...
end
This is the Game model:
class Game < ApplicationRecord
has_many :pieces
belongs_to :user
before_save :start_game_when_black_player_is_added
after_create :populate
scope :available, -> { where(state: "pending") }
after_create :current_user_is_white_player
def add_black_player!(player)
self.black_player_id = player.id
self.total_players = 2
save
end
def current_user_is_white_player
self.white_player_id = user_id
end
def populate
(1..8).each do |piece|
pieces.create(x: piece, y: 2, color: 'white', type: 'Pawn')
pieces.create(x: piece, y: 7, color: 'black', type: 'Pawn')
end
["Rook", "Knight", "Bishop", "King", "Queen", "Bishop", "Knight", "Rook"].each.with_index(1) do |klass, index|
pieces.create(x: index, y: 1, color: 'white', type: klass)
pieces.create(x: index, y: 8, color: 'black', type: klass)
end
end
end
This is the User model:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :games
end
This is the Pieces controller:
class PiecesController < ApplicationController
before_action :authenticate_user!
skip_before_action :verify_authenticity_token
def show
#piece = Piece.find_by_id(params[:id])
if #piece.blank?
return render_not_found
end
if #piece.game.white_player_id # white_player_id does not exist to the controller
# returns 404 error
# if #piece.piece_color_matches_user_color?(current_user)
return render plain: "Success"
else
render_not_found
end
# #game = #piece.game
# #pieces = #game.pieces.all
end
def update
#piece = Piece.find_by_id(params[:id])
#game = #piece.game
x_target = piece_params[:x].to_i
y_target = piece_params[:y].to_i
if #piece.attempt_move(x_target, y_target)
#piece.save
else
return render_not_found
end
render plain: "Success"
end
private
def render_not_found(status=:not_found)
render plain: "#{status.to_s.titleize} :(", status: status
end
def piece_params
params.require(:piece).permit(:x, :y)
end
end
This is the schema:
ActiveRecord::Schema.define(version: 20180109032015) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "games", force: :cascade do |t|
t.string "name"
t.boolean "finished"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "total_players"
t.bigint "white_player_id"
t.bigint "black_player_id"
t.string "state", default: "pending", null: false
t.bigint "user_id"
t.bigint "winner_id"
end
create_table "pieces", force: :cascade do |t|
t.bigint "game_id"
t.string "type"
t.integer "x"
t.integer "y"
t.string "color"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "captured", default: false
t.index ["game_id"], name: "index_pieces_on_game_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.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
This is the error:
PiecesController pieces#show action should return success if the piece color matches the user color
Failure/Error: expect(response).to have_http_status :success
expected the response to have a success status code (2xx) but it was 404
# ./spec/controllers/pieces_controller_spec.rb:48:in `block (3 levels) in <top (required)>'
This is the Controller spec:
RSpec.describe PiecesController, type: :controller do
describe 'pieces#show action' do
it 'should return success if the piece color matches the user color' do
game = FactoryBot.create(:game)
piece = game.pieces.active.find_by({x: 1, y: 2})
sign_in game.user
get :show, params: { id: piece.id }
expect(response).to have_http_status :success
end
end
end
This is the Model spec:
RSpec.describe Piece, type: :model do
describe '#piece_color_matches_user_color?' do
it '#piece_color_matches_user_color? returns true if the piece color and user color match' do
game = FactoryBot.create(:game)
piece = game.pieces.active.find_by({x: 1, y: 2})
user = game.user
result = piece.piece_color_matches_user_color?(user)
expect(result).to eq true
end
end
end
Great and well-described question!
With ActiveRecord, after it queries your database it maps each returned column to a public method inside itself; so there's nothing stopping you from accessing the column directly your controller — or any class.
Having said, you have an after_create callback in your game.rb which is assigning a User#id to your Game#white_player_id, but it's not saving that column. Changing it to before_create :current_user_is_white_player should get you on the right track.

Model as a group that can add other User models

I am having trouble trying to achieve the following, mostly in the controller part:
I have a User model and a Firm model.
A User can create a Firm, this will mean that this user will be the firm owner. Additionally, this user can add other users to join the firm.
So far, my Models are as follows:
class Firm< ActiveRecord::Base
has_many :users, dependent: :destroy
end
class User < ActiveRecord::Base
...
belongs_to :bufete
end
Here is my create action in my firms controller:
def create
#bufete = Bufete.create(bufete_params)
#user = current_user
#bufete.users.create(#user) # Mark that this user belongs to a bufete
#user.owner = true # Mark this user as the owner of the Bufete
respond_to do |format|
if #bufete.save && #user.save
format.html { redirect_to #bufete, :flash => { :success => 'Tu bufete ha sido creado exitosamente.' } }
format.json { render :show, status: :created, location: #bufete }
else
format.html { render 'new', :flash => { :danger => 'Hubo un error al tratar de crear tu bufete.
Porfavor asegurese de que el correo electronico es una direccion valida' } }
format.json { render json: #bufete.errors, status: :unprocessable_entity }
end
end
end
Schema.rb file:
ActiveRecord::Schema.define(version: 20150730061404) do
create_table "bufetes", force: :cascade do |t|
t.string "name"
t.string "address"
t.string "telephone"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "description"
t.string "code"
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", null: false
t.datetime "updated_at", null: false
t.boolean "admin", default: false
t.boolean "premium", default: false
t.integer "bufete_id"
t.string "name"
t.string "last_name"
t.boolean "owner", default: 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
I believe my associations are correct, but I could be mistaken. My main problem is in the controller. When a user creates a firm, how do I assign this user to be the owner of this Firm? At the same time how do I add this user to the Firm.users collection?
Also, how would I go for adding future users to a specific firm's users collection?
Important: A user can only create ONE Firm. At the same time, a user can only belong to ONE firm as well. If a user creates a firm, it will belong to THAT firm.
I assume Bufete is equal to Firm model, in the code below I'll use Bufete instead of Firm. You can check whether the user can create a new Bufete before creating the Bufete record.
def create
#user = current_user
if #user.can_create_bufete?
#bufete = Bufete.create(bufete_params)
# assign user to #bufete instead of #bufete.users.create()
#user.bufete = #bufete
#user.owner = true
# add your response_to block for #user.saved
else
# add your response_to block of not creating new Bufete
end
end
Then you'll check whether the user can create a Bufete object or not in your User model.
def can_create_bufete?
!owner && !bufete.present? # or any condition that meets your requirement
end

ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR: syntax error at or near "."

I am not sure why my query works on localhost but is failing on the server.
This happens when i try to create a quiz which routes to QuizzesController#new
# GET /quizzes/new
def new
#quiz = current_user.quizzes.new
end
This is the query:
SELECT COUNT(*) FROM "questions" INNER JOIN "question_categories" ON "question_categories"."question_id" = "questions"."id" WHERE "questions"."deleted_at" IS NULL AND (`question_categories`.`category_id` IN (87,1))
(1.0ms) ROLLBACK
Completed 500 Internal Server Error in 58ms (ActiveRecord: 13.4ms)
And i got an error as such.
ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR: syntax error at or near "." LINE 1: ...s"."deleted_at" IS NULL AND (`question_categories`.`category...
quiz.rb
before creating i would run build_parts which should randomly grab questions and place them into quizzes.
class Quiz < ActiveRecord::Base
belongs_to :user
belongs_to :subject
has_many :quiz_categories
has_many :categories, through: :quiz_categories
has_many :quiz_parts
accepts_nested_attributes_for :categories
accepts_nested_attributes_for :quiz_parts
validates :user, :subject, :number_of_questions, presence: true
validates :number_of_questions, numericality: { only_integer: true, greater_than_or_equal_to: 1 }
before_create :build_parts
before_save :set_completed_at, if: -> { completeness == 100.00 }
def completeness
answerable_quiz_parts = 0
quiz_parts.each do |q_part|
answerable_quiz_parts += 1 if q_part.answerable.answers.present?
end
quiz_parts.joins(:choice).count.to_f * 100 / answerable_quiz_parts
end
def score
quiz_parts.joins(:choice).where('choices.correct = ?', true).count { |qp| qp.choice.correct? }
end
private
# select random questions
def build_parts
category_ids = self.categories.map(&:id)
question_pool = Question.joins(:question_categories).where('`question_categories`.`category_id` IN (?)', category_ids)
#self.number_of_questions = [number_of_questions, question_pool.size].min
puts question_pool.size
if number_of_questions > question_pool.size
errors.add(:number_of_questions, 'is too high. Please select a lower question count or increase category selections')
return false
end
number_of_questions.times do |i|
question_pool.inspect
self.quiz_parts << question_pool[i].quiz_parts.new
question_pool[i].question_parts.each do |question_part|
self.quiz_parts << question_part.quiz_parts.new
end
end
end
def set_completed_at
self.completed_at = Time.zone.now
end
end
quizzes_controller.rb
class QuizzesController < ApplicationController
before_action :authenticate_user!
before_action :set_quiz, only: [:show, :edit, :update, :destroy]
# GET /quizzes
# GET /quizzes.json
def index
#quizzes = current_user.quizzes.order(created_at: :desc)
end
# GET /quizzes/1
# GET /quizzes/1.json
def show
end
# GET /quizzes/new
def new
#quiz = current_user.quizzes.new
end
# GET /quizzes/1/edit
def edit
end
# POST /quizzes
# POST /quizzes.json
def create
#quiz = current_user.quizzes.new(quiz_create_params)
respond_to do |format|
if #quiz.save
format.html { redirect_to edit_quiz_path(#quiz), notice: 'Quiz was successfully created.' }
format.json { render :show, status: :created, location: #quiz }
else
format.html { render :new }
format.json { render json: #quiz.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /quizzes/1
# PATCH/PUT /quizzes/1.json
def update
respond_to do |format|
if #quiz.update(quiz_update_params)
format.html { redirect_to #quiz, notice: 'Quiz was successfully updated.' }
format.json { render :show, status: :ok, location: #quiz }
else
format.html { render :edit }
format.json { render json: #quiz.errors, status: :unprocessable_entity }
end
end
end
# DELETE /quizzes/1
# DELETE /quizzes/1.json
def destroy
#quiz.destroy
respond_to do |format|
format.html { redirect_to quizzes_url, notice: 'Quiz was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_quiz
#quiz = current_user.quizzes.find(params[:id])
end
# For quiz setup
def quiz_create_params
params.require(:quiz).permit(:subject_id, :number_of_questions, category_ids: [])
end
# For quiz answering
def quiz_update_params
params.require(:quiz).permit(quiz_parts_attributes: [:id, choice_attributes: [:id, :content, :answer_id, :_destroy]])
end
end
schema.rb:
ActiveRecord::Schema.define(version: 20150726180000) do
create_table "admins", force: :cascade do |t|
t.string "email"
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "admins", ["confirmation_token"], name: "index_admins_on_confirmation_token", unique: true
add_index "admins", ["email"], name: "index_admins_on_email", unique: true
add_index "admins", ["reset_password_token"], name: "index_admins_on_reset_password_token", unique: true
create_table "answers", force: :cascade do |t|
t.integer "number"
t.text "content"
t.boolean "correct", default: false, null: false
t.integer "answerable_id"
t.string "answerable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "answers", ["answerable_type", "answerable_id"], name: "index_answers_on_answerable_type_and_answerable_id"
create_table "categories", force: :cascade do |t|
t.string "name"
t.integer "subject_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "categories", ["category_id"], name: "index_categories_on_category_id"
add_index "categories", ["subject_id"], name: "index_categories_on_subject_id"
create_table "choices", force: :cascade do |t|
t.string "content"
t.integer "quiz_part_id"
t.integer "answer_id"
t.boolean "correct"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "choices", ["answer_id"], name: "index_choices_on_answer_id"
add_index "choices", ["quiz_part_id"], name: "index_choices_on_quiz_part_id"
create_table "ckeditor_assets", force: :cascade do |t|
t.string "data_file_name", null: false
t.string "data_content_type"
t.integer "data_file_size"
t.integer "assetable_id"
t.string "assetable_type", limit: 30
t.string "type", limit: 30
t.integer "width"
t.integer "height"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "ckeditor_assets", ["assetable_type", "assetable_id"], name: "idx_ckeditor_assetable"
add_index "ckeditor_assets", ["assetable_type", "type", "assetable_id"], name: "idx_ckeditor_assetable_type"
create_table "levels", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "question_categories", force: :cascade do |t|
t.integer "question_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "question_categories", ["category_id"], name: "index_question_categories_on_category_id"
add_index "question_categories", ["question_id"], name: "index_question_categories_on_question_id"
create_table "question_parts", force: :cascade do |t|
t.text "content"
t.string "type"
t.integer "question_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
end
add_index "question_parts", ["deleted_at"], name: "index_question_parts_on_deleted_at"
add_index "question_parts", ["question_id"], name: "index_question_parts_on_question_id"
create_table "questions", force: :cascade do |t|
t.text "content"
t.string "type"
t.integer "level_id"
t.integer "subject_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
t.string "source"
end
add_index "questions", ["deleted_at"], name: "index_questions_on_deleted_at"
add_index "questions", ["level_id"], name: "index_questions_on_level_id"
add_index "questions", ["subject_id"], name: "index_questions_on_subject_id"
create_table "quiz_categories", force: :cascade do |t|
t.integer "category_id"
t.integer "quiz_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "quiz_categories", ["category_id"], name: "index_quiz_categories_on_category_id"
add_index "quiz_categories", ["quiz_id"], name: "index_quiz_categories_on_quiz_id"
create_table "quiz_parts", force: :cascade do |t|
t.integer "quiz_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "answerable_id"
t.string "answerable_type"
end
add_index "quiz_parts", ["answerable_type", "answerable_id"], name: "index_quiz_parts_on_answerable_type_and_answerable_id"
add_index "quiz_parts", ["quiz_id"], name: "index_quiz_parts_on_quiz_id"
create_table "quizzes", force: :cascade do |t|
t.integer "user_id"
t.datetime "completed_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "subject_id"
t.integer "number_of_questions"
end
add_index "quizzes", ["subject_id"], name: "index_quizzes_on_subject_id"
add_index "quizzes", ["user_id"], name: "index_quizzes_on_user_id"
create_table "subjects", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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
I believe you are using wrong quotes:
SELECT COUNT(*) ....... (`question_categories`.`category_id` IN (87,1))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use " " instead of ``
Update:
Yep, I have been right in your quiz model you're using wrong quotes:
def build_parts
category_ids = self.categories.map(&:id)
question_pool = Question.joins(:question_categories).where('`question_categories`.`category_id` IN (?)', category_ids)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Fix it to:
def build_parts
category_ids = self.categories.map(&:id)
question_pool = Question.joins(:question_categories).where('"question_categories"."category_id" IN (?)', category_ids)
^^^^^^^^^^^^^^^^^^^^^

Resources