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.
Related
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
I'm trying to add sorting to my activscaffold. Example code is:
active_scaffold :user do |config|
config.columns = [:id, :name, :rating]
config.list.per_page = 25
config.columns[:rating].sort = true
But when i check column 'RATING' isn't sortable.
try this
list.sorting = {:rating => 'ASC'}
Add this method to your controller
def custom_finder_options
{reorder: 'rating ASC'}
end
i have a model called Fund and a model called Company .. where fund belongs_to a company.
i have this validation in my Fund table:
validates :name, presence: true, uniqueness: true
This works both on server side and client side using client_side_validations. But i want my fund names to be unique across both fund.name values and fund.company.name values. And i want to do it in a way it would work with client_side_validations too.
Suggestions?
Ended up creating a very specific validator and adding it to client-side-validation. Here'z the breakdown
In models/fund.rb
validates_fund_name_not_company_name :name
new file in config/initializers/validators .. called fund_name_not_company_name_validator.rb
class FundNameNotCompanyNameValidator < ActiveModel::EachValidator
def validate_each(record, attr_name, value)
if ::Company.exists?(name: value)
record.errors.add(attr_name, :fund_name_not_company_name, options.merge(:value => value))
end
end
end
# This allows us to assign the validator in the model
module ActiveModel::Validations::HelperMethods
def validates_fund_name_not_company_name(*attr_names)
validates_with FundNameNotCompanyNameValidator, _merge_attributes(attr_names)
end
end
module ClientSideValidations::Middleware
class FundNameNotCompanyName < ClientSideValidations::Middleware::Base
def response
if ::Company.exists?(name: request.params[:name])
self.status = 404
else
self.status = 200
end
super
end
end
end
then in app/assets/javascripts/rails.validations.custom.js
clientSideValidations.validators.remote['fund_name_not_company_name'] = function(element, options) {
if ($.ajax({
url: '/validators/fund_name_not_company_name',
data: { name: element.val() },
// async must be false
async: false
}).status == 404) { return options.message; }
}
This helped a great deal
I have a basic rails question where I need to save two associated objects.
The association is Rtake has_many :companies and Company belongs_to :rtake
def create
#rtake = RTake.new(:email => params[:contact_email])
#rtake.role = "PROVIDER"
#company = #rtake.companies.build(params[:company])
#company.rtake = #rtake
respond_to do |format|
if #company.save_company_and_rtake
format.html{ redirect_to admin_companies_url}
else
flash.now[:errors] = #company.errors.full_messages.join(", ")
format.html{ render "new" }
end
end
end
In my company.rb class I have
def save_company_and_rtake
status1 = self.save(:validate => false)
status2 = self.rtake.save(:validate => false)
status = status1 && status2
status
end
The problem I face is that the company.rtake_id remains nil. Ideally shouldn't the company.rtake_id get updated to the #rtake.id after save.
I know I am missing something basic. Would appreciate some help.
You shouldn't need this line:
#company.rtake = #invitation
#invitation is nil from what you've shown .
But also, when you built the #company, #rtake.id isn't set because it hasn't been saved.
#company = #rtake.companies.build(params[:company])
#company.rtake = #rtake
#rtake.companies.build(params[:company]) This already means #company.rtake == #rtake. it's redundent here.
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/