before_create callback generates random array - ruby-on-rails-3

When I create a randomly generate exam I would like to store all the correct answer in an array. The reason that I am doing this is because when I grade the exam I would like to see if the answer is correct by matching the user_answer with the same element in the correct_answer array. Unfortunately, when i use a callback its putting the correct answers in a random order where I cannot match them appropriately.
##controller##
class ExamsController < ApplicationController
def create
exam = current_user.exams.create!(test_bank_questions: TestBankQuestion.all.sample(5))
exam.answers
redirect_to exam_question_path(exam, '1')
end
end
#####Model######
class Exam
include Mongoid::Document
before_create :answers
field :user_answer, type: Array, default: []
field :correct_answers_ids, type: Array, default: []
belongs_to :user
has_and_belongs_to_many :test_bank_questions
#### This is where my problem is ####
#I am trying to get all the id's of the correct answer
#and put them in an array when the object is created
def answers
exam_questions = self.test_bank_questions
exam_questions.each do |question|
answer_choices = question.answer_choices
answer_choices.each do |choice|
if choice.correct_choice == true
self.correct_answers_ids << choice.id.to_s
end
end
end
return correct_answers_ids
end
end
####Model ####
class TestBankQuestion
include Mongoid::Document
field :question_url, type: String
embeds_many :answer_choices
has_and_belongs_to_many :exams
end
###Model ###
class AnswerChoice
include Mongoid::Document
field :choice_url, type: String, default: []
field :correct_choice, type: Boolean, default: []
embedded_in :test_bank_question
end

Related

Find cards with today date when user receive mails in RoR

Every day I need to send letters to users with today's tasks.
For do this I need to find all users who are allowed to send letters, and among these users to find all cards that have a deadline today. The result is three array elements with a nil value. How is this better done and right?
#users = User.all {|a| a.receive_emails true}
#user_cards = []
#users.each_with_index do |user, index|
#user_cards[index] = user.cards.where(start_date: Date.today).find_each do |card|
#user_cards[index] = card
end
end
My user model:
class Card < ApplicationRecord
belongs_to :user
# also has t.date "start_date"
end
My card model:
class User < ApplicationRecord
has_many :cards, dependent: :destroy
# also has t.boolean "receive_emails", default: false
end
Something like #cards_to_send = Card.joins(:users).where("users.receive_emails = true").where(start_date: Date.today)
Have a look at https://guides.rubyonrails.org/active_record_querying.html#specifying-conditions-on-the-joined-tables for the docs on how to query on a joined table.
You could do this with a SQL join like this
User.joins(:cards).where(receive_emails: true, cards: { start_date: Date.today })
https://guides.rubyonrails.org/active_record_querying.html#joining-tables

RoR, Mongoid: How to update nested attributes?

I have the model anwer_pair.rb
class AnswerPair
include Mongoid::Document
embedded_in :question
embedded_in :survey
field :answer1, type: String
field :answer2, type: String
...
field :correct, type: Boolean, default: true
...
def new(answer1 = "answer1", answer2 = "answer2", correct = false)
#answer1 = answer1
#answer2 = answer2
#correct = correct
end
...
end
which is nested in question.rb
class Question
include Mongoid::Document
...
field :name, type: String
...
embeds_many :answer_pairs
accepts_nested_attributes_for :answer_pairs, allow_destroy: true
...
end
Using a form to save a question to the database works fine (I use mongoid). Now I'd like to add some more answer pairs to the question, before it is updated or created. For that reason I invoke the following method in "update" and "create" in questions_controller.rb
class QuestionsController < ApplicationController
...
def update
...
fill_up_answer_pairs(#question)
...
end
def create
...
fill_up_answer_pairs(#question)
...
end
...
def fill_up_answer_pairs(question)
if(question.answer_pairs.any?)
question.answer_pairs.where(correct: false) do |pair|
pair.delete
end
question.answer_pairs.where(correct: true) do |pair1|
question.answer_pairs.where(correct: true) do |pair2|
if(pair1.answer1 != pair2.answer1 && pair1.answer2 != pair2.answer2)
question.add_to_set(:answer_pairs, AnswerPair.new(pair1.answer1, pair2.answer2, false))
end
end
end
# having "question.update_attributes(question.answer_pairs)" here would cause a "NameError ... undefined method `keys' for #<Array ..."
end
end
but it doesn't save the added answer pairs. What am I doing wrong?
Any help is appreciated!
Th following changes fixed the problem:
After the where clauses I forgot the "each"s and I changed the new method of answer_pair.rb to
def self.buildnew(answer1 = "answer1", answer2 = "answer2", correct = false)
ap = AnswerPair.new
ap.answer1 = answer1
ap.answer2 = answer2
ap.correct = correct
return ap
end
Using question.update_attributes is not necessary.

Elasticsearch: filtering by group with tire gem

I want to filtering search by age groups.
Now I have:
program.rb
class Program < ActiveRecord::Base
has_many :age_groups, through: :programs_age_groups_relations
include Tire::Model::Search
include Tire::Model::Callbacks
mapping do
indexes :name, analyzer: 'snowball', boost: 100
indexes :description, analyzer: 'snowball'
indexes :age_groups do
indexes :name, analyzer: 'snowball'
end
end
def to_indexed_json
to_json(include: {age_groups: {only: :name}})
end
def self.search(params, options={})
tire.search(load: {include: 'age_groups'}) do
query do
boolean do
must { string params[:name_query] } if params[:name_query].present?
end
end
filter do
boolean do
if params[:age_groups].present?
params[:age_groups].each do |ag_name|
must { string ag_name }
end
end
end
end
end
end
index.html.haml
= form_tag programs_path, method: :get do |f|
= text_field_tag :name_query, params[:name_query]
- AgeGroup.all.each do |ag|
= check_box_tag 'age_groups[]', ag.name, params[:age_groups].include?(ag.name)
in controller:
#programs = Program.search(params)
Age Groups:
AgeGroup.create([{name: 'Baby'}, {name: 'Toddler'}, {name: 'Preschoolers'}, {name: 'Elementary'}, {name: 'Middle School'}])
Realtion:
class ProgramsAgeGroupsRelation < ActiveRecord::Base
attr_accessible :age_group_id, :program_id
belongs_to :age_group
belongs_to :program
end
When I check one or more age_groups in search form nothing was happened with search result.
How can I correctly use tire for this task?
I'm not sure I understand your question, but please check this StackOverflow answer: Elasticsearch, Tire, and Nested queries / associations with ActiveRecord for info on ActiveRecord associations with Tire.
Once you have that sorted out, please update your question, as “nothing was happened with search result” hints at some kind of failed expectation, but I don't know which one.

Rails 3: Find parent of polymorphic model in controller?

I'm trying to find an elegant (standard) way to pass the parent of a polymorphic model on to the view. For example:
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Employee < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :pictures, :as => :imageable
end
The following way (find_imageable) works, but it seems "hackish".
#PictureController (updated to include full listing)
class PictureController < ApplicationController
#/employees/:id/picture/new
#/products/:id/picture/new
def new
#picture = imageable.pictures.new
respond_with [imageable, #picture]
end
private
def imageable
#imageable ||= find_imageable
end
def find_imageable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
Is there a better way?
EDIT
I'm doing a new action. The path takes the form of parent_model/:id/picture/new and params include the parent id (employee_id or product_id).
I'm not sure exactly what you're trying to do but if you're trying to find the object that 'owns' the picture you should be able to use the imageable_type field to get the class name. You don't even need a helper method for this, just
def show
#picture = Picture.find(params[:id])
#parent = #picture.imagable
#=> so on and so forth
end
Update
For an index action you could do
def index
#pictures = Picture.includes(:imagable).all
end
That will instantiate all 'imagables' for you.
Update II: The Wrath of Poly
For your new method you could just pass the id to your constructor, but if you want to instantiate the parent you could get it from the url like
def parent
#parent ||= %w(employee product).find {|p| request.path.split('/').include? p }
end
def parent_class
parent.classify.constantize
end
def imageable
#imageable ||= parent_class.find(params["#{parent}_id"])
end
You could of course define a constant in your controller that contained the possible parents and use that instead of listing them in the method explicitly. Using the request path object feels a little more 'Rails-y' to me.
I just ran into this same problem.
The way I 'sort of' solved it is defining a find_parent method in each model with polymorphic associations.
class Polymorphic1 < ActiveRecord::Base
belongs_to :parent1, :polymorphic => true
def find_parent
self.parent1
end
end
class Polymorphic2 < ActiveRecord::Base
belongs_to :parent2, :polymorphic => true
def find_parent
self.parent2
end
end
Unfortunately, I can not think of a better way. Hope this helps a bit for you.
This is the way I did it for multiple nested resources, where the last param is the polymorphic model we are dealing with: (only slightly different from your own)
def find_noteable
#possibilities = []
params.each do |name, value|
if name =~ /(.+)_id$/
#possibilities.push $1.classify.constantize.find(value)
end
end
return #possibilities.last
end
Then in the view, something like this:
<% # Don't think this was needed: #possibilities << picture %>
<%= link_to polymorphic_path(#possibilities.map {|p| p}) do %>
The reason for returning the last of that array is to allow finding the child/poly records in question i.e. #employee.pictures or #product.pictures

Ruby on Rails - Simplifying similar methods that access different variables

I'm working on a fairly simple site that allows users to choose recipe ingredients, their quantities and then shows them nutritional info based on their recipe and a large database.
Right now, I feel like I'm repeating myself a bit. I want to be able to make this "DRY" by having one method each in the Recipe and Recipe_Ingredient model that will do the same thing only accept the right parameter, which will be the type of nutrient.
Here is the relevant code in my view that currently calls two different methods (and will call more when extended to the other nutrients):
<ul>Calories <%= #recipe.total_calories %></ul>
<ul>Fat (grams) <%= #recipe.total_fat %></ul>
In my recipe model, I have methods that iterate over each of the ingredients in the recipe:
def total_calories
recipe_ingredients.to_a.sum { |i| i.total_calories }
end
def total_fat
recipe_ingredients.to_a.sum { |i| i.total_fat }
end
In the block, we call two separate methods that actually calculate the nutrients for each individual recipe ingredient:
def total_calories
ingredient.calories*ingredient.weight1*quantity/100
end
def total_fat
ingredient.fat*ingredient.weight1*quantity/100
end
This last piece is where we reference the database of ingredients. For context, here are the relationships:
class RecipeIngredient < ActiveRecord::Base
belongs_to :ingredient
belongs_to :recipe
class Recipe < ActiveRecord::Base
has_many :recipe_ingredients
Thanks in advance for any help.
Lev
The send method with a symbol parameter works well for that kind of DRY.
<ul>Calories <%= #recipe.total :calories %></ul>
<ul>Fat (grams) <%= #recipe.total :fat %></ul>
Recipe
def total(type)
recipe_ingredients.to_a.sum { |i| i.total type }
end
RecipeIngredient
def total(type)
ingredient.send(type) * ingredient.weight1 * quantity / 100
end
You could use meta programming to dynamically add the methods. Here is a start, you can get even more DRY than this.
class DynamicTotalMatch
attr_accessor :attribute
def initialize(method_sym)
if method_sym.to_s =~ /^total_of_(.*)$/
#attribute = $1.to_sym
end
end
def match?
#attribute != nil
end
end
Recipe
class Recipe
def self.method_missing(method_sym, *arguments, &block)
match = DynamicTotalMatch.new(method_sym)
if match.match?
define_dynamic_total(method_sym, match.attribute)
send(method_sym, arguments.first)
else
super
end
end
def self.respond_to?(method_sym, include_private = false)
if DynamicTotalMatch.new(method_sym).match?
true
else
super
end
end
protected
def self.define_dynamic_total(method, attribute)
class_eval <<-RUBY
def self.#{method}(#{attribute})
recipe_ingredients.to_a.sum { |i| i.send(attribute)
end
RUBY
end
end
RecipeIngredient
class RecipeIngredient
def self.method_missing(method_sym, *arguments, &block)
match = DynamicTotalMatch.new(method_sym)
if match.match?
define_dynamic_total(method_sym, match.attribute)
send(method_sym, arguments.first)
else
super
end
end
def self.respond_to?(method_sym, include_private = false)
if DynamicTotalMatch.new(method_sym).match?
true
else
super
end
end
protected
def self.define_dynamic_total(method, attribute)
class_eval <<-RUBY
def self.#{method}(#{attribute})
ingredient.send(attribute) * ingredient.weight1 * quantity / 100
end
RUBY
end
end
Example was copied from ActiveRecord and this page: http://technicalpickles.com/posts/using-method_missing-and-respond_to-to-create-dynamic-methods/