I am trying to create a simple rails website that I can use to practice my mental math. The idea is that I create a random question using a randomly selected ruby question_creator function I defined. This function returns two numbers, along with their answer.
If a user types in an answer that is incorrect, I want to display a quick error message and display the same question again. While redisplaying the question I would like to keep track of the number of attempts required to find the correct answer, as well as the total time taken to do so.
Where I am stuck now is that I can not figure out how to maintain the randomly generated question, along with the number of try's while reloading the simple_form_for after an incorrect input.
In order to do this I have created a model named Questions which holds the number of trys and time taken for each question. Ideally I would like to create an instance of this object whenever a question is answered correctly. The idea of having a single Question instance for every question answered is that I can then later use this to track my progression and improvements.
Right now the Questions Schema looks like this:
create_table "questions", force: :cascade do |t|
t.integer "trys"
t.integer "time"
t.bigint "user_id"
t.bigint "question_type_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["user_id"], name: "index_questions_on_user_id"
end
My Questions class method to generate random questions looks like this. I am not sure if this is even the correct place this method, so please feel free to feedback on this as well. My idea is that in the end I have several different questions e.g. add_two_numbers()
, multiply_two_numbers()
, subtract_three_numbers()
etc... from which I can randomly pick one each time.
def random_two_digit_number()
return rand(10..99)
end
def add_two_numbers()
num1 = random_two_digit_number()
num2 = random_two_digit_number()
answ = num1 + num2
return num1, num2, answ
end
In order to pass the users answer, along with the actual answer answ
to the create method I have added them as hidden fields in my simple_form_for.My Question/New page looks like this:
<% @question = Question.new() %>
<% num1, num2, answ = @question.add_two_numbers %>
<h3> <%= num1 %> + <%= num2 %></h3>
<p>Trys: <%= @question.trys %></p>
<%= simple_form_for @question do |f| %>
<%= f.hidden_field :trys, :value => @question.trys || 1 %>
<%= f.hidden_field :answ, :value => answ %>
<%= f.input :user_answ, input_html: {value: ''} %>
<%= f.button :submit %>
<% end %>
The create method in the questions controller:
def create
@question = Question.new(trys: question_params["trys"], time: question_params["time"])
@question.user_id = current_user.id
respond_to do |format|
if @question.save && (question_params["answ"] == question_params["user_answ"])
format.html { render :new, notice: 'Correct!' }
format.json { render :show, status: :created, location: @question }
else
format.html { render :new, notice: 'Thats wrong' }
format.json { render json: @question.errors, status: :unprocessable_entity }
end
end
end
Whenever I hit the point where question_params["answ"] == question_params["user_answ"]
, meaning that the user gave a wrong answer, I would like to increment the trys count by one and redirect him to the same question. As of right now, I can not get this to work however.
I have already build a quick prototype of this in python, if that is of any help: https://codeshare.io/arlrX7
I would be super glad I somebody could point me in the right direction, as I would really love to get this to work :)
There are many things wrong with this code, but let's tackle the ones preventing you from making it work.
new.html.erb
you have two problematic lines - <% @question = Question.new() %>
<% num1, num2, answ = @question.add_two_numbers %>
Having logic in your view is a bad idea, and it prevents you from reaching your goal, too. Define them inside new
action in your controller.
create
action, because when you render :new, notice: 'Thats wrong'
, it's being done inside the context of create, with local variables available in that context.So, add num1
and fiends as hidden fields in to your form, and assign those values inside the create
action.
@num1 = question_params[:num1]
This way, when you render :new
, you still have those @question
and @num1
and whatever else you passed along
if @question.save && (question_params["answ"] == question_params["user_answ"])
What it does is saving the question and then checking the answer. Instead, try:
@question.save if (question_params["answ"] == question_params["user_answ"])
if @question.persisted? # rest of your code
This way you only save the question if the answer is correct, and then check if it was saved to determine what to do next.