How to get model attributes to save in order? - ruby-on-rails

I'm building a quiz app, to create a quiz I do this:
def new
#quiz = Quiz.new
50.times do
question = #quiz.questions.build
5.times { question.answers.build }
end
end
enter code here
Which uses nested parameters. The problem is, sometimes the quiz doesn't save in order (such as when I create a new quiz OR I update an existing quiz). If I create a quiz in particular order, say Question 1, Question 2, Question 3, I want the questions in that quiz to remain in the same order after I update or create it. Right now, if I update a quiz the order gets jumbled up if I want to show the quiz using something like quiz.questions.each do |question|
I wasn't aware that ruby databases don't enforce order, so how do I make sure that if I create a quiz, the order in which I enter the questions (top to bottom) will always be the order that the questions are presented in?
If you are interested, this is the form I use to create the quiz:
<%= form_for(#quiz) do |f| %>
<% if #quiz.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#quiz.errors.count, "error") %> prohibited this quiz from being saved:</h2>
<ul>
<% #quiz.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class = 'field'>
<%= f.label :difficulty, "Difficulty of Quiz, 1 to 3 with 3 being most difficult" %>
<%= f.text_field :difficulty %>
</div>
<div class="field">
<%= f.label :for_unsubscribed, "Check to have this quiz be visible to logged in but unsubscribed users" %>
<%= f.check_box :for_unsubscribed %>
</div>
<%= f.fields_for :questions do |question_attribute| %>
<div class = 'inner-c'>
<p>
<%= question_attribute.label :content, "Question" %> <span><b><%= question_attribute.index + 1 %></b></span> <br/>
<%= question_attribute.text_area :content, :cols => 100, :rows => 4 %>
</p>
<p>
<%= question_attribute.label :explanation, "Answer Explanation" %> <br/>
<%= question_attribute.text_area :explanation, :cols => 100, :rows => 6 %>
</p>
<%= question_attribute.label :_destroy, "Remove Question"%>
<%= question_attribute.check_box :_destroy %><br/>
<%= question_attribute.label :passage, "Reference Passage" %> <br/>
<%= question_attribute.text_area :passage, :rows => 3, :class => 'passage-input' %>
<%#= question_attribute.label :question_explanation, "Question Explanation" %>
<%#= question_attribute.text_area :question_explanation, :rows => 10 %>
</p>
<%= question_attribute.fields_for :answers do |answer_attribute| %>
<p>
<%= answer_attribute.label :content, "Answer" %>
<%= answer_attribute.text_field :content %>
<%= answer_attribute.label :correct_answer, "Check to indicate correct answer", :class => 'inline' %>
<%= answer_attribute.check_box :correct_answer, :class => 'inline'%>
</p>
<% end %>
</div> <!-- inner-c -->
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

Related

I'm missing an attribute that needs to be permitted

I know I'm missing something, but I can't figure out what.
It's quite nested. I have a quiz which has_many questions which has_many answers. Answers belongs_to Questions which belongs_to a Quiz.
What I have so far:
params.require(:quiz).permit(:name, questions_attributes: [:content, :quiz_id, :explanation, :passage, answers_attributes: [:content, :question_id, :correct_answer]])
My form:
<%= form_for(#quiz) do |f| %>
<% if #quiz.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#quiz.errors.count, "error") %> prohibited this quiz from being saved:</h2>
<ul>
<% #quiz.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :questions do |question_attribute| %>
<div class = 'inner-c'>
<p>
<%= question_attribute.label :content, "Question" %> <span><b><%= question_attribute.index + 1 %></b></span> <br/>
<%= question_attribute.text_area :content, :cols => 100, :rows => 4 %>
</p>
<p>
<%= question_attribute.label :explanation, "Answer Explanation" %> <br/>
<%= question_attribute.text_area :explanation, :cols => 100, :rows => 6 %>
</p>
<%= question_attribute.label :_destroy, "Remove Question"%>
<%= question_attribute.check_box :_destroy %><br/>
<%= question_attribute.label :passage, "Reference Passage" %> <br/>
<%= question_attribute.text_area :passage, :rows => 3, :class => 'passage-input' %>
<%#= question_attribute.label :question_explanation, "Question Explanation" %>
<%#= question_attribute.text_area :question_explanation, :rows => 10 %>
</p>
<%= question_attribute.fields_for :answers do |answer_attribute| %>
<p>
<%= answer_attribute.label :content, "Answer" %>
<%= answer_attribute.text_field :content %>
<%= answer_attribute.label :correct_answer, "Check to indicate correct answer", :class => 'inline' %>
<%= answer_attribute.check_box :correct_answer, :class => 'inline'%>
</p>
<% end %>
</div> <!-- inner-c -->
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

Why do my model attributes save out of order?

This happens particularly often when I try and update a model.
I have a quiz app, and I add a quiz using this form:
<%= form_for(#quiz) do |f| %>
<% if #quiz.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#quiz.errors.count, "error") %> prohibited this quiz from being saved:</h2>
<ul>
<% #quiz.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class = 'field'>
<%= f.label :difficulty, "Difficulty of Quiz, 1 to 3 with 3 being most difficult" %>
<%= f.text_field :difficulty %>
</div>
<div class="field">
<%= f.label :for_unsubscribed, "Check to have this quiz be visible to logged in but unsubscribed users" %>
<%= f.check_box :for_unsubscribed %>
</div>
<%= f.fields_for :questions do |question_attribute| %>
<div class = 'inner-c'>
<p>
<%= question_attribute.label :content, "Question" %> <span><b><%= question_attribute.index + 1 %></b></span> <br/>
<%= question_attribute.text_area :content, :cols => 100, :rows => 4 %>
</p>
<p>
<%= question_attribute.label :explanation, "Answer Explanation" %> <br/>
<%= question_attribute.text_area :explanation, :cols => 100, :rows => 6 %>
</p>
<%= question_attribute.label :_destroy, "Remove Question"%>
<%= question_attribute.check_box :_destroy %><br/>
<%= question_attribute.label :passage, "Reference Passage" %> <br/>
<%= question_attribute.text_area :passage, :rows => 3, :class => 'passage-input' %>
<%#= question_attribute.label :question_explanation, "Question Explanation" %>
<%#= question_attribute.text_area :question_explanation, :rows => 10 %>
</p>
<%= question_attribute.fields_for :answers do |answer_attribute| %>
<p>
<%= answer_attribute.label :content, "Answer" %>
<%= answer_attribute.text_field :content %>
<%= answer_attribute.label :correct_answer, "Check to indicate correct answer", :class => 'inline' %>
<%= answer_attribute.check_box :correct_answer, :class => 'inline'%>
</p>
<% end %>
</div> <!-- inner-c -->
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
A new form would be generated by the controller like so:
def new
#quiz = Quiz.new
50.times do
question = #quiz.questions.build
5.times { question.answers.build }
end
end
Taking advantage of using nested models, where a Quiz has_many Questions which has_many Answers.
The problem is -- when I create a quiz (with 50 questions), then I try and update the quiz afterwards, to fix a mistake for example, The questions move out of order. Question 43 and Question 1 might switch places. I absolutely need the questions to stay in the same order after I update them but I can't figure out how to make this happen. Any ideas?
Generally in RDBMS order is not specified by default, unless you explicitly state it. Therefore if you don't specify the order you can get results in any order an that is an expected behaviour.
But according to your description question 43 swapped with question 1 after an update, so I can think you are ordering them by an updated_at timestamp. Try to order explicitly order questions by id – id is [normally] a PrimaryKey and it never changes, so your questions will stay in order.

Showing multiple iterations of form fields when in edit file of scaffold

First, I have a model called Answers for my trivia game. It stores the multiple possible answers there are to each trivia question (a quiz has_many answers). I created a form via scaffold to make an easy UI for submitting a question with a set of four answers.
I want to do this from one form. When the user currently hits submit, I can post all four answers -- each with a different answer_id but sharing the same question_id (so I can associate 4 answers with one question) -- successfully, like so:
<%= form_for(#question) do |f| %>
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #question.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<div class="field">
<%= f.label :question_text %><br>
<%= f.text_field :question_text, class: "form-control" %>
</div>
</div>
<div class="form-group">
<div class="field">
<%= f.label :category_id %><br>
<%= f.number_field :category_id, class: "form-control" %>
</div>
</div>
<h2>Answer Options</h2>
<%= f.fields_for :answers do |answer| %>
<div class="form-group">
<div class="answers">
<div class="field">
<%= answer.label :answer_1 %><br>
<%= answer.text_field :answer_text, class: "form-control" %>
</div>
</div>
</div>
<% end %>
<%= f.fields_for :answers do |answer| %>
<div class="form-group">
<div class="answers">
<div class="field">
<%= answer.label :answer_2 %><br>
<%= answer.text_field :answer_text, class: "form-control" %>
</div>
</div>
</div>
<% end %>
<%= f.fields_for :answers do |answer| %>
<div class="form-group">
<div class="answers">
<div class="field">
<%= answer.label :answer_3 %><br>
<%= answer.text_field :answer_text, class: "form-control" %>
</div>
</div>
</div>
<% end %>
<%= f.fields_for :answers do |answer| %>
<div class="form-group">
<div class="answers">
<div class="field">
<%= answer.label :answer_4 %><br>
<%= answer.text_field :answer_text, class: "form-control" %>
</div>
</div>
</div>
<% end %>
If I check in console, it works! I have four different answers (so they are four rows in the table but with the same question_id. What is weird is if I then use the edit route, instead of populating four inputs (like new does), it shows 16 text_field inputs for Answers (labeled Answer 1, Answer 2, Answer 3, Answer 4, Answer 1).
Finally, the other reason I think there could be an issue would be how I am updating the nested Answers attribute through the controller, like so:
def question_params
params.require(:question).permit(:question_text, :category_id, :correct_answer, :answers_attributes => [:id, :answer_text])
end
Am I setting this up incorrectly, such that it would iterate 4x when showing in the Edit file?
I think you need to do little different while rendering the form for edit action:
You can try something like this:
<%= form_for(#question) do |f| %>
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #question.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title, class: "form-control" %>
</div>
</div>
<% unless #question.new_record? %>
<% #question.answers.each_with_index do |ans,i| %>
<%= f.fields_for :answers, ans do |answer| %>
<%= answer.label "answer_#{i+1}" %><br>
<%= answer.text_field :answer_text, class: "form-control" %>
<% end %>
<% end %>
<% else %>
<h2>Answer Options</h2>
<%= f.fields_for :answers, Answer.new do |answer| %>
<%= answer.label :answer_1 %><br>
<%= answer.text_field :answer_text, class: "form-control" %>
<% end %>
<%= f.fields_for :answers,Answer.new do |answer| %>
<%= answer.label :answer_2 %><br>
<%= answer.text_field :answer_text, class: "form-control" %>
<% end %>
<%= f.fields_for :answers,Answer.new do |answer| %>
<%= answer.label :answer_3 %><br>
<%= answer.text_field :answer_text, class: "form-control" %>
<% end %>
<%= f.fields_for :answers,Answer.new do |answer| %>
<%= answer.label :answer_4 %><br>
<%= answer.text_field :answer_text, class: "form-control" %>
<% end %>
<% end %>
<%= f.submit #question.new_record? ? "Add" : "Update" %>
<% end %>

Date is not working in rails application with mongo id

I have create an rails application with mongoid but im facing one problem at DATE
I created an scaffold with a name "posting"
When im editing date it will updated....
I follow the instruction of Railscast #238 Mongoid here
there is my posting.rb file
class Posting
include Mongoid::Document
field :title
field :description
field :comments
field :published, :type => Date
end
this my _from.html.erb
<%= form_for(#posting) do |f| %>
<% if #posting.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#posting.errors.count, "error") %> prohibited this posting from being saved:</h2>
<ul>
<% #posting.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.label :published %><br>
<%= f.date_select :published %>
</div>
<div class="field">
<%= f.label :comments %><br>
<%= f.text_area :comments %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
and finally my show.html.erb file
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= #posting.title %>
</p>
<p>
<strong>Description:</strong>
<%= #posting.description %>
</p>
<p>
<strong>published:</strong>
<%= #posting.published %>
</p>
<p>
<strong>Comments:</strong>
<%= #posting.comments %>
</p>
<%= link_to 'Edit', edit_posting_path(#posting) %> |
<%= link_to 'Back', postings_path %>
What do you mean by not working? doesn't look like you have used published property in any of your views.
in your show.html.erb you are using
<%= f.date_select :pub %>
and in your show.html.erb you are using
<%= #posting.pub %>
However there is no property called pub in your Posting model. What you have there is called published
field :published, :type => Date
You either need to rename it in the model, or in the views to match.

Rails how to show on one page existing associated records AND permit new associated record input

My main record is a Plate (as in license plate).
It can have many Translations (meanings or comments).
On one page I want to:
1)show a plate record and allow users to rate the plate
2)show all existing translation records and allow users to vote for one
3)allow the user to create a new translation record
I am using form_for the Plate, and fields_for for the existing translation records.
My research suggests there should be a way to do this, but my code is not delivering a blank form. Currently I am trying a second fields_for loop.
At the moment, I am just focused on my rendered forms page, I have not gotten to processing the input yet.
The final fields_for which is meant to display a blank box for a new translation input, is instead showing the last existing translation.
I will appreciate any suggestions.
Below is my edit form: _rate_or_vote.html.erb
<!-- app/views/plates/_rate_or_vote.html.erb -->
<%= form_for(#plate) do |f| %>
<% if #plate.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#plate.errors.count, "error") %>
prohibited this plate from being updated:</h2>
<ul>
<% #plate.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<h1>Rate the Plate</h1>
<span class="form-group">
<%= f.label :input_rating, "Your Plate Rating" %>
<%= f.select :input_rating, options_for_select(RATINGS) %>
</span>&nbsp&nbsp
<span class="form-group">
<%= f.label :rating, "Average Rating" %>
<%= f.text_field :rating , :value => (number_with_precision(f.object.rating, :precision => 2) || 0) %>
</span>&nbsp&nbsp
<span class="form-group">
<%= f.label :plate_number, "Plate Number" %>
<%= f.text_field :plate_number %>
</span>&nbsp&nbsp
<span class="form-group">
<%= f.label :state, "State" %>
<%= f.text_field :state, class: "form-control" %>
</span><br><br>
<span style="background-color:#DCDCDC; color:#000000; font-style: normal; font-family:Georgia;">
Contributor</span>
<span style="border:1px solid black;padding:3pt;">
<%= #plate.user.full_name %></span>&nbsp&nbsp
<span class="form-group">
<%= f.label :plate_image, "Plate Image File" %>
<%= f.file_field :plate_image %>
</span><br><br>
<h1>Existing Translations and/or Comments - You can vote for one</h1>
<!-- %= f.fields_for :translations do |ff| %-->
<%= f.fields_for :translations, #plate.translations do |ff| %>
<span>Click this box to vote for this translation:</span>&nbsp
<span><%= check_box_tag "translation_ids[]", :id %></span>&nbsp&nbsp
<span><%= ff.label "Current votes" %>
<%= ff.text_field :votes, :value => (number_to_percentage(ff.object.votes / ( #plate.translation_votes.nonzero? || 1 ) * 100,
precision: 0)) %>
</span>&nbsp&nbsp
<span style="background-color:#DCDCDC; color:#000000; font-style: normal; font-family:Georgia;">
Contributor</span>
<span style="border:1px solid black;padding:3pt;">
<%= ff.object.user.full_name %></span><br><br>
<span>Translation and/or Comment</span><br>
<span>
<%= ff.text_area :meaning, :cols => 60, :rows => 10 %>
</span><br><br>
<% end %>
<h1>Offer a new Translation and/or Comment</h1>
<!-- %= f.fields_for :translations do |ff| %-->
<%= f.fields_for :translations, #plate.translations do |fff| %>
<div>
<!-- %= fff.label :meaning, "Translation" %-->
<%= fff.text_field :meaning %>
</div><br><br>
<% end %>
<%= f.submit "Save and/or Return", :name => "update", class: "btn btn-default" %>
ok, so #plate.translations is the set of current translations that are already on the plate.
If you want a fields-for section for a new one... you have to actually build a new one.
eg:
<%= f.fields_for :translations, [#plate.translations.build] do |fff| %>
<div>
<%= fff.text_field :meaning %>
</div><br><br>
<% end %>

Resources