I have five models: Course, Lesson, Question, Answer and User.
What I'm trying to do is determine if the User has Answers for all of the Questions in a Lesson (so I can put "Done" next to the lesson in the view if this is the case).
My models:
class Course < ActiveRecord::Base
has_many :lessons, dependent: :destroy
has_many :questions, :through => :lessons
has_many :users, through: :purchases
end
class Lesson < ActiveRecord::Base
belongs_to :course
has_many :questions, dependent: :destroy
has_many :answers, through: :questions
end
class Question < ActiveRecord::Base
belongs_to :lesson
belongs_to :course
has_many :answers, dependent: :destroy
end
class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :user
end
class User < ActiveRecord::Base
has_many :answers
has_one :author
has_many :courses, through: :purchases
end
What I tried to do was to check if a Lesson's Questions were in the Questions the User Answered, but the includes? line doesn't seem to be working the way I want.
in my controller, I have:
#lessons = #course.lessons
#answers = current_user.answers
#questions = Question.where(:id => #answers.map(&:question_id))
in my view, I have:
<% #lessons.each do |lesson| %>
<% lesson_questions = lesson.questions %>
<%= user_questions = #questions.where("lesson_id = ?", lesson.id)%>
<% if user_questions.include?(lesson_questions)%>
Done!
<% end %>
<% end %>
I'm not sure if this is the cause, but I noticed the lesson_questions are #<Question::ActiveRecord_Associations_CollectionProxy:0x9c49698>
While the user_questions are: #<Question::ActiveRecord_Relation:0x9c48330>
I'm wondering, (a) how I accomplish my objective of finding the Lessons with all of the Questions answered, and (b) if there's a more efficient way to do this. Thanks!
Problem
You can't check if an array includes another array just like this:
user_questions.include?(lesson_questions)
You need to check if each element from lesson_questions is included in the user_questions.
Try these instead:
Solution: 1
lesson_questions.all? { |lq| user_questions.include?(lq) }
This should return true if all the lesson_questions are included in the user_questions.
Solution: 2
(lesson_questions - user_questions).empty?
Related
I am new to rails, I want to calculate the total number of responses for different options for each question. How to calculate the average for each question. These are my models. Thank you for your kind help.
class User < ActiveRecord::Base
has_many :surveys
end
class Survey < ActiveRecord::Base
belongs_to :user
has_many :questions, :dependent => :destroy
end
class Question < ActiveRecord::Base
belongs_to :survey
has_many :options, :dependent => :destroy
has_many :answers, :dependent => :destroy
end
class Option < ActiveRecord::Base
belongs_to :question
has_many :answers, :dependent => :destroy
end
class Answer < ActiveRecord::Base
belongs_to :option belongs_to :question
end
You simply have to create a field in your question class such as responseCount:integer and use update in your question controller to manipulate your data.
def update
# update 'response' count
end
And once you finish, you can count the average by doing so:
#totalResponseCount = 0
#averageResponseCount = 0
for #question.each do |question|
totalResponseCount += question.responseCount
averageResponseCount = totalResponseCount/Question.count
end
I have three tables: illnesses, symptoms and a third table to map the relationship between the first two, called symptom_illness.
This third table has symptom_id, illness_id and its own id
I need a way to show, for example, all symptoms of a given "Common Cold" illness. In this example, "Common Cold" has an id of 1 and its symptoms have ids of 1 through 5.
This means that symptom_illness has 5 entries, where:
symptom_illness.illness_id = 1, symptom_id = 1
symptom_illness.illness_id = 1, symptom_id = 2
symptom_illness.illness_id = 1, symptom_id = 3
And so on. I need a way to display, in a single page, all the symptoms that have the same illness_id but I can't seem to find a way how to.
EDIT 1: My classes are related as such:
Symptom:
has_many :symptom_illness
has_many :illnesses, through: :symptom_illness
And similar for Illness.
Illness_symptom has belongs_to :symptom and belongs_to :illness
You have three models
class Symptom
has_many :symptom_illnesses
has_many :illnesses, through: :symptom_illnesses
end
class SymptomIllness
belongs_to :illness
belongs_to :symptom
end
class Illness
has_many :symptom_illnesses
has_many :symptoms, through: :symptom_illnesses
end
You can easily access al illness symptoms with something like that:
Illness.find(1).symptoms.each do |symptom|
# do something with this symptom
end
What do you want to show in the page?
If the symptom has a name attribute you can initialize a
#symptoms = Illness.find(1).symptoms
array in controlller and in the page you do something like
<% #symptomps.each do |symptom| %>
<% = symptom.name %>
<% end %>
You should use a has_many through: relationship.
class Illness < ActiveRecord::Base
has_many :symptom_illness
has_many :symptom, through: :symptom_illness
end
class SymptomIllness < ActiveRecord::Base
belongs_to :symptom
belongs_to :illness
end
class Symptom < ActiveRecord::Base
has_many :symptom_illness
has_many :illness, through: :symptom_illness
end
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Class Symptom < ActiveRecord::Base
belongs_to :symptom_illness
has_many :ilnesses, through: symptom_illness
end
class SymptomIllness < ActiveRecord::Base
belongs_to :symptom
belongs_to :illness
scope :ilness, ->(*i) {
where(ilness_id: i.flatten.compact.uniq
}
end
class Illness < ActiveRecord::Base
belongs_to :symptom_illness
has_many :symptoms, through: :symptom_illness
end
Ilness.find(1).symptoms
Sorry about the title, couldn't come up with a better one to describe what I'm trying to do.
In a previous question, some users suggested I could simplify the models. I didn't get anymore comments but I think I'm doing it 'the right way' because I need to store additional attributes in the join tables.
Anyway my models are setup like this.
class Student < ActiveRecord::Base
has_many :student_notes
has_many :notes, :through => :student_notes
has_many :relationships
has_many :users, :through => :relationships
end
class Note < ActiveRecord::Base
has_many :student_notes
has_many :students, :through => :student_notes
end
class StudentNote < ActiveRecord::Base
belongs_to :student
belongs_to :note
end
class User < ActiveRecord::Base
has_many :relationships
has_many :students, :through => :relationships
has_many :notes, :through => :students
end
class Relationship < ActiveRecord::Base
belongs_to :student
belongs_to :user
end
Now, in my note show view I have this:
...
<% #note.students.each do |student| %>
<tr>
<td><%= link_to student.full_name, student %></td>
</tr>
<% end %>
...
This works, except I would like to show only the students that belong to current_user.
Any tips on how can I achieve it? I guess a helper method in the model would be the way to go, but I'm totally lost.
Thank you!
On Student:
scope :belonging_to, -> (u) { joins(:users).where users: { id: u.id } }
Then:
#note.students.belonging_to(current_user)...
I have FamilyTree, Node, Comment, & User models.
The relationship is like this:
FamilyTree
class FamilyTree < ActiveRecord::Base
belongs_to :user
has_many :memberships, dependent: :destroy
has_many :members, through: :memberships, source: :user, dependent: :destroy
has_many :nodes, dependent: :destroy
end
Node
class Node < ActiveRecord::Base
belongs_to :family_tree
belongs_to :user
has_many :comments, dependent: :destroy
end
Comment
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :node
end
User
class User < ActiveRecord::Base
has_one :family_tree, dependent: :destroy
has_many :memberships, dependent: :destroy
has_many :nodes, dependent: :destroy
has_many :comments
end
Membership ## This is just to store the user memberships on various family_trees
class Membership < ActiveRecord::Base
belongs_to :family_tree
belongs_to :user
end
In my Dashboard#IndexController where I am using this, I have:
def index
#family_tree = current_user.family_tree
#nodes = #family_tree.nodes.includes(:comments)
#node = current_user.nodes.new
#memberships = current_user.memberships.limit(3)
end
When I am trying to optimize my app with the Bullet gem, I get this message:
N+1 Query detected
Comment => [:user]
Add to your finder: :include => [:user]
N+1 Query method call stack
My _comments partial that is generating this N+1 issue is called like this - in my views/dashboard/index.html.erb:
<% #nodes.each do |node| %>
<%= render partial: "shared/comments", locals: {node: node} %>
<% end %> <!-- node -->
This is where the n+1 offending queries occur, around these lines in my _comments partial.
<% node.comments.each do |comment| %>
<li class="clearfix">
<a class="avatar" href="#">
<%= image_tag(comment.user.avatar.url)%>
So it seems the solution is to optimize my controller call, but I am not quite sure how to do 2-levels of association. I tried this:
#nodes = #family_tree.nodes.includes(:comments).includes(:user)
But that doesn't seem to get rid of the N+1 query problem.
Any ideas?
You have to pass a hash to the includes
#nodes = #family_tree.nodes.includes(:comments => :user)
There has to be a better way to do this. My Favorite model belongs to User while Applicant belongs to both Gig and User. I am trying to efficiently determine whether a user has applied for Gig that was favorited (<% if #application.present? %>).
I tried chaining the collection by using something like #favorites.each.gig to no avail. While the below index action for Favorites seems to work, it's really verbose and inefficient. What is a more succinct way of doing this?
def index
#favorites = Favorite.where(:candidate_id => current_candidate)
#applications = Applicant.where(:candidate_id => current_candidate)
#favorites.each do |favorite|
#applications.each do |application|
if favorite.gig.id == application.id
#application = application
end
end
end
end
class User
has_many :applicants
has_many :gigs, :through => :applicants
has_many :favorites
end
class Favorite < ActiveRecord::Base
belongs_to :candidate
belongs_to :gig
end
class Applicant < ActiveRecord::Base
belongs_to :gig
belongs_to :candidate
end
class Candidate < ActiveRecord::Base
has_many :applicants
has_many :gigs, :through => :applicants
has_many :favorites
end
class Gig < ActiveRecord::Base
belongs_to :employer
has_many :applicants
has_many :favorites
has_many :users, :through => :applicants
end
For lack of a better answer, here's my idea:
--
User
Your user model should be structured as such (I just highlighted foreign keys, which I imagine you'd have anyway):
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :applicants
has_many :gigs, :through => :applicants, foreign_key: "candidate_id"
has_many :favorites, foreign_key: "candidate_id"
end
This means you'll be able to call:
current_candidate.favorites
current_candidate.applicants
This will remove the need for your #applications and #favorites queries
--
Favorite
You basically want to return a boolean of whether applicant is part of the favorite model or not. In essence, for each favorite the candidate has made, you'll be able to check if it's got an application
I would do this by setting an instance method on your favorites method using an ActiveRecord Association Extension, like so:
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :favorites do
def applied?
self.applicant.exists? proxy_association.owner.gig.id
end
end
end
This will allow you to call:
<%= for favorite in current_candidate.favorites do %>
<%= if favorite.applied? %>
<% end %>
This is untested & highly speculative. I hope it gives you some ideas, though!