I have a DB that stores students answers to quiz questions. These are linked to Student Learning Outcomes that I want to review through a series of relationships described below. I am trying to do a count for how many questions were answered correctly and how many questions were answered incorrectly for each student learning outcome, but I keep receiving errors. Thank you in advance for any help you provide.
The general mapping is
“Answer” answers a question that tests a “KnowledgeTopic” that covers many (“KtCoveredBySLO”) “StudentLearningOutcome”
My models have the following relationships:
class Answer < ActiveRecord::Base
belongs_to :KnowledgeTopic
end
class KnowledgeTopic < ActiveRecord::Base
has_many :answers
has_many :kt_covered_by_slos
has_many :student_learning_outcomes, through: :kt_covered_by_slos
end
class KtCoveredBySlo < ActiveRecord::Base
belongs_to :StudentLearningOutcome
belongs_to :KnowledgeTopic
end
class StudentLearningOutcome < ActiveRecord::Base
has_many :kt_covered_by_slos
has_many :knowledge_topics, through: :kt_covered_by_slos
end
The query I am attempting to run is:
#answers = Answer.joins(:KnowledgeTopic => {:kt_covered_by_slos => :StudentLearningOutcome})
.select( 'student_learning_outcomes.id As student_learning_outcomes_id',
:is_correct, "count(answers.id) AS total_answers")
.group('student_learning_outcomes.id', :is_correct)
The error I am receiving is:
SQLite3::SQLException: no such column:
kt_covered_by_slos.knowledge_topic_id: SELECT
student_learning_outcomes.id As student_learning_outcomes_id,
"answers"."is_correct", count(answers.id) AS total_answers FROM
"answers" INNER JOIN "knowledge_topics" ON "knowledge_topics"."id"
= "answers"."KnowledgeTopic_id" INNER JOIN "kt_covered_by_slos" ON "kt_covered_by_slos"."knowledge_topic_id" = "knowledge_topics"."id"
INNER JOIN "student_learning_outcomes" ON
"student_learning_outcomes"."id" =
"kt_covered_by_slos"."StudentLearningOutcome_id" GROUP BY
student_learning_outcomes.id, is_correct
Migrations:
class CreateKtCoveredBySlos < ActiveRecord::Migration
def change
create_table :kt_covered_by_slos do |t|
t.references :StudentLearningOutcome, index: true
t.references :KnowledgeTopic, index: true
t.timestamps
end
end
end
class CreateAnswers < ActiveRecord::Migration
def change
create_table :answers do |t|
t.references :Question, index: true
t.references :Section, index: true
t.references :Student, index: true
t.references :KnowledgeTopic, index: true
t.boolean :is_correct
t.string :answer_text
t.references :Enroll, index: true
t.timestamps
end
end
end
class CreateKnowledgeTopics < ActiveRecord::Migration
def change
create_table :knowledge_topics do |t|
t.string :knowledge_area
t.string :knowledge_unit
t.string :knowledge_topic
t.integer :year_added
t.boolean :active
t.integer :correct_answers
t.integer :incorrect_answers
t.integer :temp_correct_answer
t.integer :temp_incorrect_answer
t.timestamps
end
end
end
class CreateStudentLearningOutcomes < ActiveRecord::Migration
def change
create_table :student_learning_outcomes do |t|
t.string :accredidation_body
t.string :title
t.string :description
t.integer :year_added
t.boolean :active
t.integer :correct_answers
t.integer :incorrect_answers
t.integer :temp_correct_answer
t.integer :temp_incorrect_answer
t.timestamps
end
end
end
Thanks Everyone. Using Ave's explanation, I changed the reference names, and then updated everything else accordingly. After that I was able to run the query with
#answers = Answer.joins(knowledge_topic: :student_learning_outcomes)
.select( 'student_learning_outcomes.id As student_learning_outcomes_id', :is_correct,
"count(answers.id) AS total_answers")
.group('student_learning_outcomes.id', :is_correct)
Related
I have two models 'Tutorial' and 'Tutorialcategory'
class Tutorialcategory < ActiveRecord::Base
has_many :tutorials
class Tutorial < ActiveRecord::Base
belongs_to :tutorialcategory
Tutorials are associated with multiple categories like html,rubyonrails where html and ruby on rails are tutorialcategories
followings are migrations
class CreateTutorials < ActiveRecord::Migration
def change
create_table :tutorials,force: true do |t|
t.string :title
t.text :body
t.integer :rating
t.string :videoid
t.belongs_to :tutorialcategory
t.timestamps
end
end
end
class CreateTutorialcategories < ActiveRecord::Migration
def change
create_table :tutorialcategories do |t|
t.string :title
t.timestamps null:false
end
end
end
All tutorials are listing properly on index page but when I see category page it gives me following error
PG::Error: ERROR: column tutorials.tutorialcategory_id does not exist
I have no idea why you named your model Tutorialcategory instead of TutorialCategory which follow Rails naming convention and make it easier to understand.
Firstly, rollback your db one step
rake db:rollback
Change your migration file to:
class CreateTutorials < ActiveRecord::Migration
def change
create_table :tutorials,force: true do |t|
t.string :title
t.text :body
t.integer :rating
t.string :videoid
t.belongs_to :tutorial_category, index: true
t.timestamps
end
end
end
class CreateTutorialCategories < ActiveRecord::Migration
def change
create_table :tutorial_categories do |t|
t.string :title
t.timestamps null:false
end
end
end
Run the migration again and edit your model to match with new schema.
class TutorialCategory < ActiveRecord::Base
has_many :tutorials
class Tutorial < ActiveRecord::Base
belongs_to :tutorial_category
I have this table structure:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :encrypted_password
t.string :salt
t.timestamps
end
end
end
And I want to add a new table as shown below:
class CreateHolidays < ActiveRecord::Migration
def change
create_table :holidays do |t|
t.string :earn_leave
t.string :seek_leave
t.string :unplanned_leave
t.timestamps
t.timestamps
end
add_index(users,id)
end
end
What should I do for this, please also suggest commands that can/should be used for migration.
You want to look up about foreign_keys:
#app/models/holiday.rb
class Holiday < ActiveRecord::Base
belongs_to :user
end
#app/models/user.rb
class User < ActiveRecord::Base
has_many :holidays
end
This will mean you have to add the user_id foreign key to your holidays data table:
class CreateHolidays < ActiveRecord::Migration
def change
create_table :holidays do |t|
t.references :user
t.string :earn_leave
t.string :seek_leave
t.string :unplanned_leave
t.timestamps
t.timestamps
end
end
end
You must remember that Rails is designed to be built on top of a relational database. As such, it uses foreign_keys in the tables to locate associated records:
The above will allow you to call:
#user.holidays
and
#holiday.user
I have a class 'Report' that has columns 'description', 'pending', etc.
/app/models/report.rb
class Report < ActiveRecord::Base
end
class CreateReports < ActiveRecord::Migration
def change
create_table :reports do |t|
t.boolean :pending, :default => true
t.boolean :accepted, :default => false
t.text :description
t.timestamps null: false
end
end
end
But I also have two other classes: ReportPost (when a User report a Post), and ReportTopic (when a User report a Topic). I used this approach because I can user 'belongs_to :topic' for ReportTopic and 'belongs_to :post' for ReportPost. So, here comes the problem:
Since ReportPost and ReportTopic have the same columns of 'Report', I need to use the inheritance from 'Report'. But I also need to use ActiveRecord inheritance to capture new attributes from :report_topic migrates.
But, how?
Here are the other classes:
class ReportTopic < Report
belongs_to :topic
end
class ReportPost < Report
belongs_to :post
end
`And, the migrates:
class CreateReportPosts < ActiveRecord::Migration
def change
create_table :report_posts do |t|
t.belongs_to :post
t.timestamps null: false
end
end
end
class CreateReportTopics < ActiveRecord::Migration
def change
create_table :report_topics do |t|
t.belongs_to :topic
t.timestamps null: false
end
end
end
You could use Single Table Inheritance (STI) in this case. Just add a column named 'type' to your report table.
def change
create_table :reports do |t|
t.boolean :pending, :default => true
t.boolean :accepted, :default => false
t.text :description
t.string :type
t.timestamps null: false
end
end
Rails will understand this as STI. Any subclass that you may create will have its type equal to the name of the class (e.g. type = 'ReportTopic')
I have models:
Category:
class Category < ActiveRecord::Base
has_many :entities, as: :resourcable
end
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :name
t.text :short_descr
t.text :full_descr
t.timestamps
end
end
end
Language:
class Language < ActiveRecord::Base
has_many :entities, as: :resourcable, dependent: :destroy
validates :code, uniqueness: true
end
class CreateLanguages < ActiveRecord::Migration
def change
create_table :languages do |t|
t.string :name
t.string :code
t.timestamps
end
end
end
And Entity:
class Entity < ActiveRecord::Base
belongs_to :language
belongs_to :resourcable, polymorphic: true
end
class CreateEntities < ActiveRecord::Migration
def change
create_table :entities do |t|
t.integer :language_id
t.string :name
t.text :short_descr
t.text :full_descr
t.references :resourcable, polymorphic: true
t.timestamps
end
end
end
In Categories there are default values for fields (short_descr, full_descr), In Entities there are translations for this fields. I need to render as json all Categories with appropriate translations: at first, I need to take Language with appropriate code (for example ru), next, I need to find all language Entities for this language, next, if Entity have filled short_descr and full_descr I need to render Category with this values, else I need to render the Category with default values (this values in Categories table). How to do this? I prefer ActiveRecord buy consider pure SQL.
EDITED
Now I'm trying to use gem 'squeel':
Language.joins{entities.category}.
select{coalesce(entities.short_descr, categories.short_descr)}.
where{languages.code == 'en'}
but it doesn't work (undefined methodshort_descr' for nil:NilClass`). There is the problem?
Entity.joins(:language, :category).
select('categories.*, coalesce(entities.short_descr, categories.short_descr) as short_descr,
coalesce(entities.full_descr, categories.full_descr) as full_descr').
where('languages.code = ?', 'en')
In my web app, I have nodes and links. A link has two nodes. One node is a source node, and the other node is a target node. Basically, I want source and target columns in the database that hold references to nodes. I am trying to figure out how to implement this.
Here is the migration for the nodes model:
class CreateNodes < ActiveRecord::Migration
def change
create_table :nodes do |t|
t.string :name
t.integer :group
t.references :link, index: true
t.timestamps
end
end
end
Here is the node model:
class Nodes < ActiveRecord::Base
belongs_to :link
end
I am trying to figure out how to set up the migration for the links model. Here is what I have so far:
class CreateLinks < ActiveRecord::Migration
def change
create_table :links do |t|
t.integer :value
t.boolean :checked
t.timestamps
end
end
end
Here is what I have in my model:
class Links < ActiveRecord::Base
has_many :nodes
end
Would the correct migration look like this?
class CreateLinks < ActiveRecord::Migration
def change
create_table :links do |t|
t.integer :value
t.boolean :checked
t.references :source
t. references :target
t.timestamps
end
end
end
t.references :smith is basically a shortcut for t.integer :smth_id so if your Nodes belong to Links, then yes that construction seems correct.
not sure where your links#source and links#target point to though.