I have the following tables:
class FinalExam < ActiveRecord::Base
belongs_to :course
has_many :pages, :as => :course_unit, :dependent => :destroy
end
class Page < ActiveRecord::Base
belongs_to :course_unit, :polymorphic => true
has_one :quiz
has_one :slide
end
class Quiz < ActiveRecord::Base
belongs_to :page
end
class Answers < ActiveRecord::Base
belongs_to :quiz
end
So, we have Answer.Quiz.Page.FinalExam
Given the FianlExam id, what is the fastest way to find all Answers count ? how to get it ?
I can re-design the DB to have belongs_to :final_exam in Answers
class Answers < ActiveRecord::Base
belongs_to :quiz
belongs_to :final_exam
end
this way, I can say Answers.where(:final_exam_id=> params[:id]).count
Do I have to change the DB design ? or its a matter of a query ?
I need an expert advice please.
First of all I'm guessing that Quiz should read:
class Quiz < ActiveRecord::Base
belongs_to :page
has_many :answers
end
If so you can add these lines to your FinalExam model:
has_many :quizzes, :through => :pages
has_many :answers, :through => :quizzes
Allowing you to then call
FinalExam.first.answer.count
(Note: if you're on a version of Rails < 3.1, you'll need this plugin)
The drawback to this approach is that it becomes slow with a lot of data. In this case, you'd want to set up a counter cache in the FinalExam that updates every time an answer is added. It'd a little more complicated because of the many-layered relationships you have; see this post for more info:
counter_cache has_many_through sql optimisation, reduce number of sql queries
Related
This is probably a fairly straight forward answer that I feel like I should know, but occasionally I run across something like this that stumps me.
I'm working on a rails app that requires me to essentially create a leasing system for rentals.
I've got a user, a building, a lease and an unit. The way I've got it structured right now is:
class Buildings < ActiveRecord::Base
has_many :units
has_many :users
end
class User < ActiveRecord::Base
belongs_to :buildings
has_many :units, through :lease
end
class Lease < ActiveRecord::Base
belongs_to :user
belongs_to :unit
end
class Unit < ActiveRecord::Base
belongs_to :building
belongs_to :user
has_one :lease
end
I'm running into syntax errors and association errors and the documentation is as clear as mud. Perhaps someone can help me to properly structure these associations.
Your syntax error is on the User class
Change
has_many :units, through :lease
to
has_many :unit, through: :lease
or
has_many :units, :through => :lease
I have these 2 models, and I'm trying to add an association between them so I can add some extra details later:
class Ticket < ActiveRecord::Base
belongs_to :user
has_many :event_tickets
has_many :events, :through => :event_tickets
end
class Event < ActiveRecord::Base
has_many :event_tickets
has_many :tickets, :through => :event_tickets
end
class EventTicket < ActiveRecord::Base
belongs_to :event
belongs_to :ticket
end
I've tried adding an association like this, just to see it's working:
event_ticket = EventTicket.new(:ticket => ticket, :event => Event.all[0])
event_ticket.save!
This gives me:
can't write unknown attribute `ticket_id`
The ticket and event exist and are working fine, but can't get the event_ticket object working.
What am I doing wrong?
It sounds like you don't have an event_tickets table, or at least it doesn't have a ticket_id column. Are you sure you wrote the migration and ran it?
I apologize if this is a big question. I used to be good at rails but it has been a long time.
I am working a rails project and am having trouble with the has_many relation.
I have the following tables:
User
SchoolClass
Question
UserClassQuestion
Inside the models i have:
user.rb
has_many :questions, :through => :user_class_questions
has_many :user_class_questions
school_class.rb
has_many :questions, :through => :user_class_questions
has_many :user_class_questions
question.rb
belongs_to :schoolclass
belongs_to :user
user_class_question.rb
belongs_to :question
So, what I want is to on a users home page, display let them view the questions they have asked with current_user.questions. This works.
But on the SchoolClass show page, if i say #school_class.questions, i get the following error:
!!<ActiveRecord::StatementInvalid: SQLite3::SQLException: no such colum:
user_class_questions.school_class_id: SELECT "questions".* FROM "questions"
INNER JOIN "user_class_questions" ON "questions"."id" =
"user_class_questions"."question_id" WHERE
"user_class_questions"."school_class_id" = ?>
#school_class is an object set by the params
def set_school_class
#school_class = SchoolClass.find(params[:id])
end
The columns in UserClassQuestion table are:
{ user_id: , schoolclass_id: , question_id }
So, do I have something set up wrong?
The error you're experiencing is most likely due to the variation in your column name. In Rails, school_class_id is not the same as schoolclass_id. I think a quick way to work around, is to specify the primary_key/foreign_key in your belongs_to option.
A more lasting solution is to run a migration to rename your column to school_class_id rather than schoolclass_id.
Let me know if I was able to help.
UPDATE
if the belongs_to :school_class is defined on question, then you have access to question.school_class and your school_class model should just have has_many :questions, no need of running to a join table to do that as that would confuse rails a bit. If however you don't want it this way you could comment out the belongs_to :school_class assoication and instead have a has_many :user_class_questions on question
class User
has_many :questions, through: :user_class_questions
has_many :user_class_questions
end
class SchoolClass
has_many :questions, through: :user_class_questions
has_many :user_class_questions
end
class Question
#belongs_to :school_class
belongs_to :user
has_many :user_class_questions
end
class UserClassQuestion
belongs_to :question
belongs_to :school_class
belongs_to :user
end
Your Data model needs a bit of a change, your UserClassQuestion is a join model and it should have data about the User, SchoolClass, and Question. So the relationship should be something like
UserClassQuestion
rails g model UserClassQuestion user:references school_class:references question:references
class UserClassQuestion < ActiveRecord::Base
belongs_to :user
belongs_to :school_class
belongs_to :question
end
school_class.rb
class SchoolClass < ActiveRecord::Base
has_many :user_class_questions
has_many :questions, through: :user_class_questions
end
user.rb
class User < ActiveRecord::Base
has_many :user_class_questions
has_many :questions, through: :user_class_questions
end
And then you can do user.questions and school_class.questions
Also try not to use has_many_and_belongs_to association, I feel it is a bad idea, it creates a table without a primary id, and later on if you want to do something else with this join table, then this will come and bite you. has_many, through is a bit extra step but it is worth it.
I have an array of posts called #posts. Post model has_many :feelings :through => :feelingships.
How do I take the array of posts and narrow them it down to only the posts with a specific feeling?
I tried the code below but it doesn't work :(
#specific_feeling_posts = #posts.feeling.where(:feeling => "happy")
Models
class Post < ActiveRecord::Base
has_many :feelingships
has_many :feelings, :through => :feelingships
belongs_to :user
end
class Feeling < ActiveRecord::Base
has_many :feelingships
has_many :posts, :through => :feelingships
end
class Feelingship < ActiveRecord::Base
belongs_to :post
belongs_to :feeling
end
#happy_posts = Post.joins(:feelings).where("feelings.title = ?", "happy")
That should work.
#specific_feelings_post=Post.join(:feelings).where("feelings.title= ?","specific_feeling")
Its the same line as bricker has written above. The question mark is to avoid SQL injection.
In short, the security of the database is handled by the ActiveRecord in Rails. By doing this, you will create properly escaped SQl and is immune from SQL injection.
I’m creating a voting feature for our website in the style of YouTube “Likes” and “Dislikes” and Digg using Ruby on Rails 3. I have having trouble coming up with the right scheme.
I have three models, Users, Topics, and Votes. Each User will make one vote “Like” or “Dislike” for one Topic. Like these sites, Users can Vote on a Topic, but they can also create new Topics. I’d like to be able to not only view all of a User’s Votes, but also both the Topics they have created and the Topics they have voted on. I am trying to build this on our own and decide how best to setup the database to handle this process.
My first idea was to use :has_many and belongs_to exclusively like so…
class User < ActiveRecord::Base
has_many :votes
has_many :topics
class Topic < ActiveRecord::Base
has_many :votes
belongs_to :users
class Vote < ActiveRecord::Base
belongs_to :topics
belongs_to :users
boolean choice #tracks whether the User chooses Like or Dislike
But it became evident that this might not be the best way to do this. I began to think the best method would be to use a :has_many :through association like...
class User < ActiveRecord::Base
has_many :votes, :through => :topics
But I’m not sure. Any ideas on how best to set something like this up?
I think your initial setup is good but it can be further improved upon to better support what you want to accomplish. Perhaps like this:
class User < ActiveRecord::Base
has_many :votes
has_many :topics
#Lists all topics the user has voted on
has_many :voted_topics, :through => :votes, :source => :topic
#Lists all votes for the users topics
has_many :topic_votes, :through => :topics, :source => :votes
end
class Topic < ActiveRecord::Base
has_many :votes
belongs_to :user
end
class Vote < ActiveRecord::Base
belongs_to :topic
belongs_to :user
end