I'm trying to create an app where a user can click on a quiz and it will take them to the page where they can answer the quiz questions and submit their responses to a results page.
I'm having trouble saving the users' responses - it's either only saving the last records rather than all of them or not saving to the database at all.
Here is my code:
Question.rb:
belongs_to :quiz
has_many :answered_questions, dependent: :destroy
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, reject_if: :all_blank, allow_destroy: true
Answer.rb:
belongs_to :question
has_many :answered_questions, dependent: :destroy
User.rb:
has_many :answered_questions, dependent: :destroy
accepts_nested_attributes_for :answered_questions
AnsweredQuestion.rb:
belongs_to :user
belongs_to :question
belongs_to :answer
belongs_to :quiz
Quiz.rb
has_many :questions, dependent: :destroy
has_many :answered_questions, through: :questions, dependent: :destroy
accepts_nested_attributes_for :answered_questions, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true
quizzes_controller.rb:
class QuizzesController < ApplicationController
before_action :user_completed_quiz, only: [:show]
def show
#quiz = Quiz.find(params[:id])
#questions = Question.all
#answered_questions = current_user.answered_questions.build
#quiz.answered_questions.build
end
def create
#quiz = Quiz.new(show_params)
if #quiz.save
flash[:success] = "You have created a new quiz!"
redirect_to #quiz
else
render 'new'
end
end
def results
#quiz = Quiz.find(params[:id])
end
def post_answered_questions
#quiz = Quiz.find(params[:quiz][:id])
#answered_question = #quiz.answered_questions.build(show_params)
if #answered_question.save
flash[:success] = "You have completed the quiz!"
redirect_to results_quiz_path(params[:quiz][:id])
else
render ''
end
end
private
def user_completed_quiz
if(current_user.answered_questions.pluck(:quiz_id).uniq.include?(params[:id].to_i))
redirect_to quizzes_path
end
end
def show_params
params.require(:quiz).permit(:title, answered_questions_attributes: [:id, :answer_id, :question_id, :user_id, :quiz_id], questions_attributes: [:id, :question_title, :quiz_id, :done, :_destroy, answers_attributes: [:id, :answer_title, :question_id, :quiz_id, :correct_answer, :_destroy]])
end
end
show.html.erb - quizzes (where the form is):
<%= form_for(#answered_questions, url: answered_questions_path, method: "POST") do |f| %>
<%= #quiz.title %>
<%= f.hidden_field :id, :value => #quiz.id %>
<% #quiz.questions.each do |question| %>
<%= f.fields_for :answered_questions do |answer_ques| %>
<h4><%= question.question_title %></h4>
<%= answer_ques.hidden_field :question_id, :value => question.id %>
<%= answer_ques.hidden_field :quiz_id, :value => #quiz.id %>
<%= answer_ques.select(:answer_id, options_for_select(question.answers.map{|q| [q.answer_title, q.id]})) %>
<% end %>
<% end %>
<%= submit_tag %>
<% end %>
Related
Solverd: see bottom
I am building a ordering system of many products, with a HBTM from Join Table to anotherModel, but I have some problems when creating and editing a new record of a nested form.
I have tried many solutions from other questions and followed some tutorial like this or this, but nothing solved my issues.
Product Model:
class Product < ApplicationRecord
belongs_to :subcategory
has_many :order_products, inverse_of: :product
has_many :order, :through => :order_products
end
Order Model:
class Order < ApplicationRecord
has_many :order_products, inverse_of: :order
has_many :products, :through => :order_products
accepts_nested_attributes_for :products, reject_if: :all_blank, allow_destroy: true
end
Join Table:
class OrderProduct < ApplicationRecord
belongs_to :order
belongs_to :product
has_and_belongs_to_many :ingredients
accepts_nested_attributes_for :ingredients, reject_if: :all_blank, allow_destroy: true
end
Ingredients Model associated with join table: (many-to-many to save added ingredients to every products on the order)
class Ingredient < ApplicationRecord
has_and_belongs_to_many :order_products
end
Order Controller:
# GET /orders/new
def new
#order = Order.new
end
# GET /orders/1/edit
def edit
end
# POST /orders
# POST /orders.json
def create
#order = Order.new(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render :show, status: :created, location: #order }
else
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
def order_params
params.require(:order).permit(:subtotal, :discount, :total,
order_products_attributes: [[:id, :order_id, :product_id , :_destroy]])
end
Views:
<%= simple_form_for(#order) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :subtotal %>
<%= f.input :discount %>
<%= f.input :total %>
</div>
<%= f.simple_fields_for :order_products do |o| %>
<%= render 'order_product_fields', f: o %>
<% end %>
<%= link_to_add_association "aggiungi prodotto", f, :order_products %>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Partial: (unable to add cocoon's destroy link: undefined method `reflect_on_association' for NilClass:Class due to auto add of blank fields)
<div class="nested-fields order-product-fields">
<%= f.input :product %>
<%= f.input :order %>
<%= f.check_box :_destroy %>
</div>
I get this on console:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PRNzrnxk/jrsAyPK5OzFxix2hIUmjCeWpD8Fkuhuhx8Wp3/xYTbTTvsfQkhnMDEBNnC/iNL46kl68XR7skb03g==", "order"=>{"subtotal"=>"", "discount"=>"", "total"=>"", "order_products"=>{"product"=>"", "order"=>"", "_destroy"=>"0"}}, "commit"=>"Create Order"}
Unpermitted parameter: order_products
My throubles are: EDIT: Solution on each point
When I load order pages, blanks fields for nested attributes are automatically created ()
Was wrong nested_attributes on Order Model:
accepts_nested_attributes_for **:order_products**, reject_if: :all_blank, allow_destroy: true
When submitting form no entry are created. (but I can add product to order via console .ex: order.products << product1)
When I add more product via cocoon's add link, only first is sent to controller
Don't know how to implements Strong Parameters and views for Ingredient's attributes inside the form of Order
Got this working:
Ingredient model:
has_many :ingredient_order_products, inverse_of: :ingredient
has_many :order_products, :through => :ingredient_order_products
IngredientOrderProduct model:
belongs_to :ingredient
belongs_to :order_product
Order Product model:
has_many :ingredient_order_products, inverse_of: :order_product
has_many :ingredients, :through => :ingredient_order_products
accepts_nested_attributes_for :ingredient_order_products, reject_if: :all_blank, allow_destroy: true
Order Controller:
def order_params
params.require(:order).permit(:customer_id, :subtotal, :discount, :total,
order_products_attributes: [[:id, :order_id, :product_id, :qty, :gift, :_destroy,
ingredient_order_products_attributes: [:id, :order_id, :ingredient_id, :_destroy]]])
end
_order_product_fields Partial:
<div id="ingredient">
<%= f.simple_fields_for :ingredient_order_products do |ingredient| %>
<%= render 'ingredient_order_product_fields', f: ingredient %>
<% end %>
<%= link_to_add_association "Aggiungi Ingrediente", f, :ingredient_order_products %>
</div>
I want to create an appointment form with dynamics forms. But I'm not getting what I'm doing wrong
I'm having trouble with the partial _appointment_record_form_fields and with appointment_controller.
Someone can help me fix the controller and the view?
My Models:
class Appointment < ActiveRecord::Base
has_many :appointment_record_forms, dependent: :destroy
has_many :record_forms, through: :appointment_record_forms
accepts_nested_attributes_for :appointment_record_forms, allow_destroy: true
end
class AppointmentRecordForm < ActiveRecord::Base
belongs_to :appointment
belongs_to :record_form
serialize :properties, Hash
def validate_properties
record_form.record_form_fields.each do |record_form_field|
if record_form_field.required? && properties[record_form_field.name].blank?
errors.add record_form_field.name, "must not be blank"
end
end
end
end
class RecordForm < ActiveRecord::Base
has_many :record_form_fields
has_many :appointment_record_forms, dependent: :destroy
has_many :appointments, through: :appointment_record_forms
accepts_nested_attributes_for :record_form_fields, allow_destroy: true
end
class RecordFormField < ActiveRecord::Base
belongs_to :record_form
end
My Controller
class AppointmentsController < ApplicationController
.
.
.
def appointment_params
params.require(:appointment).permit(:duration, :appointment_date, :patient_id, :doctor_id,
:record_forms => [:id, :name, :_destroy],
:record_form_fields => [:id, :name, :field_type, :require, :record_form_id, :_destroy])
end
end
Views:
views/appointment/_form
...
<%= f.fields_for :appointment_record_forms do |builder| %>
<%= render 'appointment_record_form_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Field", f, :appointment_record_forms %>
...
partial/_appointment_record_form_fields
<fieldset>
<%= f.fields_for :properties, OpenStruct.new(#appointment_record_forms.properties) do |builder| %>
<% #appointment_record_forms.record_form.record_form_fields.each do |record_form_field| %>
<%= render "appointments/fields/#{record_form_field.field_type}", record_form_field: record_form_field, f: builder %>
<% end %>
<% end %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
TKS
I have the following models
class Survey < ActiveRecord::Base
has_many :survey_sections
accepts_nested_attributes_for :survey_sections
end
class SurveySection < ActiveRecord::Base
belongs_to :survey
has_many :questions
accepts_nested_attributes_for :questions
end
class Question < ActiveRecord::Base
belongs_to :survey_section
has_many :answers
belongs_to :question_group
accepts_nested_attributes_for :question_group
accepts_nested_attributes_for :answers
end
class Answer < ActiveRecord::Base
belongs_to :question
end
class QuestionGroup < ActiveRecord::Base
has_many :questions
end
My Controller:
def new
#survey = Survey.new
survey_section = #survey.survey_sections.build
survey_section.questions.build
end
def create
#survey = Survey.new(survey_params)
if #survey.save
redirect_to #survey, notice: 'Super'
else
render 'new'
end
end
def survey_params
params.require(:survey).permit(:title, :description, survey_sections_attributes:[:id, :title, questions_attributes:[:id, :text, answers_attributes:[:id, :text]]])
end
How it is possible to save data in more then 3 models?
At the moment i can save from my survey form data into the survey, survey section and question model. But i don't know what i have to in the controller that i can save data into the other models.
You can handle as many forms as you need, if you use the fields_for helper properly.
This is where you're falling short I think (your controller seems okay).
I also wrote an answer about this some time back.
#app/models/survey.rb
class Survey < ActiveRecord::Base
has_many :sections
accepts_nested_attributes_for :sections
end
#app/models/section.rb
class Section < ActiveRecord::Base
belongs_to :survey
has_many :questions
accepts_nested_attributes_for :questions
end
#app/models/question.rb
class Question < ActiveRecord::Base
belongs_to :section
has_many :answers
end
Try and keep your model names as succinct as possible.
#app/controllers/surveys_controller.rb
class SurveysController < ApplicationController
def new
#survey = Survey.new
#survey.sections.build.questions.build
end
def create
#survey = Survey.new survey_params
#survey.save
end
private
def survey_params
params.require(:survey).permit(:title, sections_attributes: [:title, questions_attributes:[:title]])
end
end
#app/views/surveys/new.html.erb
<%= form_for #survey do |f| %>
<%= f.text_field :title %>
<%= f.fields_for :sections do |section| %>
<%= section.text_field :title %>
<%= section.fields_for :questions do |question| %>
<%= question.text_field :title %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
You can get best explanation here with same type of model
http://railscasts.com/episodes/196-nested-model-form-part-1
#app/models/survey.rb
class Survey < ActiveRecord::Base
has_many :sections, :dependent => :destroy
accepts_nested_attributes_for :sections, :allow_destroy => true
end
#app/models/section.rb
class Section < ActiveRecord::Base
belongs_to :survey
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :allow_destroy => true
end
#app/models/question.rb
class Question < ActiveRecord::Base
belongs_to :section
has_many :answers
end
now in controller
def new
#survey = Survey.new
section = #survey.sections.build
section.questions.build
end
end
Now in views
<%= form_for #survey do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :sections do |builder| %>
<%= builder.text_field :title %>
<%= builder.fields_for :questions do |question| %>
<%= question.text_field :content%>
<% end %>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
When I add a new Book to my Library, I want to be able to specify what Shelves (note: "Shelf" is the term I used in my app for the model that groups Books together within a Library; a better name for this model would have been Category or Genre, but I was stupid) in that Library it should belong to. Right now, I'm able to add a Book to my Library, but I'm having issues with the Shelves. I'm pretty new at learning Rails and I'd appreciate any help.
Models
user.rb:
class User < ActiveRecord::Base
has_one :library, dependent: :destroy
...
end
library.rb:
class Library < ActiveRecord::Base
belongs_to :user
has_many :shelves, dependent: :destroy
has_many :catalogs, dependent: :destroy
has_many :books, :through => :catalogs, dependent: :destroy
...
end
book.rb:
class Book < ActiveRecord::Base
has_many :catalogs, dependent: :destroy
has_many :libraries, :through => :catalogs, dependent: :destroy
has_many :bookshelves, dependent: :destroy
has_many :shelves, :through => :bookshelves, dependent: :destroy
...
end
catalog.rb:
class Catalog < ActiveRecord::Base
belongs_to :book
belongs_to :library
end
shelf.rb:
class Shelf < ActiveRecord::Base
belongs_to :library
has_many :bookshelves, dependent: :destroy
has_many :books, :through => :bookshelves, dependent: :destroy
...
end
bookshelf.rb
class Bookshelf < ActiveRecord::Base
belongs_to :book
belongs_to :shelf
end
Controller
books_controller.rb
class BooksController < ApplicationController
...
def create
#book = Book.new(book_params)
#library = current_user.library
if #book.save
#book.catalogs.create(:library_id => #library.id)
flash[:success] = "Book added to library!"
redirect_to current_user
else
render 'current_user'
end
end
...
private
def book_params
params.require(:book).permit(:title, :author, :publisher, :isbn)
end
...
end
View
_book_form.html.erb:
<%= form_for(#book) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_field :title, placeholder: "Book Title" %>
<%= f.text_field :author, placeholder: "Author" %>
<%= f.text_field :publisher, placeholder: "Publisher" %>
<%= f.text_field :isbn, placeholder: "ISBN" %>
<%= f.fields_for :catalogs do |ff| %>
<%= ff.hidden_field :library_id %>
<% end %>
<%= f.fields_for :bookshelves do |ff| %>
<%= ff.collection_select :shelf_ids, current_user.library.shelves.all.collect {|x| [x.name, x.id]}, {}, multiple: true %>
<% end %>
</div>
<%= f.submit "Add Book to Library", class: "btn btn-primary" %>
<% end %>
In your book_params method, you don't have shelf_ids listed. So it won't be passed into the .new method and thus it won't be saved. Since you wan't multiple ids, you want to do this:
def book_params
params.require(:book).permit(:title, :author, :publisher, :isbn, shelf_ids: [])
end
That way, the controller knows it's an array and not just a single value.
Oh, and btw, shelf_ids and any other array values like that must be at the end or it will throw an error.
Edit:
Also change this part of code:
<%= f.fields_for :bookshelves do |ff| %>
<%= ff.collection_select :shelf_ids, current_user.library.shelves.all.collect {|x| [x.name, x.id]}, {}, multiple: true %>
<% end %>
to this:
<%= f.collection_select :shelf_ids, current_user.library.shelves.all.collect {|x| [x.name, x.id]}, {}, multiple: true %>
You don't need to worry about the through part of the association. Just set up the has_many part and it'll work.
I am implementing a follow feature for my users. For this, I followed instruction of micheal hartl tutorial link needed, yet I am getting this error:
undefined method id' for nil:NilClass <% if current_user.following?(#user) %>
this is my user model
has_many :relationships, foreign_key: "follower_id", dependent: :destroy
has_many :followed_users, through: :relationships, source: :followed
has_many :reverse_relationships, foreign_key: "followed_id",
class_name: "Relationship",
dependent: :destroy
has_many :followers, through: :reverse_relationships, source: :follower
def following?(user)
relationships.find_by(followed_id: user.id)
end
def follow!(user)
relationships.create!(followed_id: user.id)
end
def unfollow!(user)
relationships.find_by(followed_id: user.id).destroy
end
this is my relationship model
class Relationship < ActiveRecord::Base
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
end
and this is my view
<% if current_user.id && current_user.id != user.id %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= form_for(current_user.relationships.find_by(followed_id: #user.id),
html: { method: :delete }) do |f| %>
<%= f.submit "Unfollow", class:"unfollow-button" %>
<% end %>
<% else %>
<%= form_for(current_user.relationships.build(followed_id: #user.id)) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class:"follow-button" %>
<% end %>
<% end %>
this is the user controller
def show
#user= User.find_by_slug(params[:id])
if #user
#posts= Post.all
render action: :show
else
render file: 'public/404', status: 404, formats: [:html]
end
end
def index
#users = (current_user.blank? ? User.all : User.find(:all, :conditions => ["id != ?", current_user.id]))
end
This means #user is nil. Make sure that #user object is not null by doing
= debug #user
That should print all the details about #user object.