Rails update creates a new object each time - ruby-on-rails

Apologies in advance for a noob question/bad formatting. Its my first post. I will try to explain clearly. In my app I have two objects quiz and quiz_question.
I want to create a quiz that has 10 questions associated with it, but want to create them over 10 'pages' rather than one long form on one page. I am trying to update the quiz object but when the update method is calls, it adds all the questions again, so the number of objects increases rapidly 1, 3, 7 etc.
quiz has many quiz questions
this is my controller:
def new
#quiz = Quiz.new
1.times{#quiz.quiz_questions.new}
end
def create
# return render json:params
#quiz = Quiz.new(quiz_params)
respond_to do |format|
if #quiz.save
format.html{ redirect_to edit_quiz_path(#quiz.id)}
else
format.html{ render :new}
end
end
end
def edit
# return render json:params
#quiz = Quiz.find params[:id]
1.times{#quiz.quiz_questions.new}
end
def update
#return render json:params
#quiz = Quiz.find params[:id]
#quiz.update(quiz_params)
respond_to do |format|
if #quiz.save && #quiz.quiz_questions.count < 10
format.html{ redirect_to edit_quiz_path(#quiz.id)}
elsif #quiz.save && #quiz.quiz_questions.count > 10
format.html{ redirect_to dashboard_teachers_path, notice: "Quiz Created Successfully"}
else
format.html{ render :edit}
end
end
end
And this is my edit view
<%= simple_form_for(#quiz, :defaults => { :input_html => { :class => "hello" } }) do |f| %>
<%= f.error_notification %>
<%= f.simple_fields_for :quiz_questions do |builder| %>
<p><%= builder.input :question %></p>
<p><%= builder.input :correct_answer %></p>
<p><%= builder.input :incorrect_answer1 %></p>
<p><%= builder.input :incorrect_answer2 %></p>
<p><%= builder.input :incorrect_answer3 %></p>
<% end %>
<%= f.button :submit, class: "btn btn-default" %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(window).load(function () {
$('input[type=text], textarea').each(function () {
// Cache pointer to selected dom element.
// Don't need to parse entire html each time you need that.
var input = $(this);
// .val() will return empty string if there is no value
// 0 means false in this case don't need to use equality check
if (!input.val()) {
input.parent().css("display", "block");
} else {
input.parent().css("display", "none");
}
});
})
</script>
EDIT: For clarity. I want to advance through the edit action 10 times, each time adding a new quiz_question object and assigning it to the quiz object.

if you want to call the update action, you need to use PUT:
<%= simple_form_for(#quiz, :method => :put, :defaults => { :input_html => { :class => "hello" } }) do |f| %>

Related

Like button likes all posts

I've implemented a like/unlike function in my app. On the show page for an item, you can like/unlike without any issues. On a user's profile page though, where it lists all the foods they've uploaded, I have two issues: First, when I click the like button for one food, it triggers it for every food and then the button text under every food says "unlike this food", instead of only having the button text change for just the food that was clicked on. The like gets saved to the db for the correct food, but obviously I don't want the button text to change for foods that I haven't liked. Second, when I try to like a different food on the page without refreshing, the liked gets saved in the db as the original food that I clicked on, instead of the one I actually clicked on.
users.show.html.erb
<% #user.foods.each do |food| %>
<div class="row col-md-12">
<div class="food col-md-4">
<h3 class="title"><%= link_to food.title.capitalize, food_path(food.id) %></h3>
<%= link_to (image_tag (food.image.url)), food_path(food.id) %>
<%= render 'shared/vote_form', :food => food %>
<%= link_to pluralize(food.votes.count, "person"), user_votes_path(:user_id => current_user.id, :food_id => food.id) %> <%= food.votes.count == 1 ? 'wants' : 'want' %> to gobble this
</div>
<div class="description col-md-6">
<% if #user.id == current_user.id %>
<% if food.description.length == 0 %>
<p><%= link_to "Add Description", edit_food_path(food) %></p>
<% else %>
<p><%= food.description %><p>
<p><%= link_to "Edit Description", edit_food_path(food) %></p>
<% end %>
<% if food.recipe.length == 0 %>
<p><%= link_to "Add Recipe", edit_food_path(food) %></p>
<% end %>
<% else %>
<% if food.description.length == 0 %>
<p>No Description</p>
<% else %>
<p><%= food.description %><p>
<% end %>
<% if food.recipe.length == 0 %>
<p>No Recipe</p>
<% else %>
<p><%= link_to "View Recipe", food_path(food) %></p>
<% end %>
<% end %>
</div>
</div>
<% end %>
votes controller
class VotesController < ApplicationController
def index
#votes = Food.find(params[:food_id]).votes
end
def new
#vote = current_user.votes.new
end
def create
#user = current_user
#vote = current_user.votes.build(vote_params)
if #vote.save!
#food = #vote.food
respond_to do |format|
format.html {redirect_to :back, notice: "Liked!"}
format.js
end
puts #vote.food.id
else
puts "No"
redirect_back(fallback_location: root_path)
end
end
def show
#user = current_user
#vote = Vote.find(params[:id])
end
def destroy
#vote = Vote.find(params[:id])
#food = #vote.food
if #vote.destroy!
respond_to do |format|
format.html {redirect_to :back, notice: "Unliked!"}
format.js
end
else
puts "NOOOOOO"
end
end
private
def vote_params
params.require(:vote).permit(:food_id)
end
end
vote partial
<% unless current_user.votes.pluck(:food_id).include?(food.id) %>
<%= button_to "Like This Food", user_votes_path(current_user, { vote: { food_id: food.id } }), :remote => true %>
<% else %>
<% vote = food.votes.where(user_id: current_user.id).first %>
<%= button_to "Unlike This Food", user_vote_path(current_user, vote), :remote => true, method: "delete" %>
<% end %>
create.js.erb
$('.button_to').replaceWith("<%= j (render :partial => 'shared/vote_form', :locals => { :food => #food, :food_id => #food.id }) %>");
destroy.js.erb
$('.button_to').replaceWith("<%= j (render :partial => 'shared/vote_form', :locals => { :food => #food }) %>");
Take a look at your create.js.erb (destroy.js.erb has the same problem). You use select all elements with the class button_to - that is all buttons on the page. Then you call replaceWith that replaces all these buttons with the button provided as the argument. The result is that all buttons get replaced with the like button corresponding to the food you just liked. This is responsible for affecting all buttons on the page and making them refer the food you liked first.
The solution is to add an id attribute to the buttons that would include the ID of the food the button pertains to. For example, if Food with ID 1 is Lettuce then you need to add id="like-1" to the button and change $('.button_to') to $("#like-1").

Rails duplicates records when using ajax to submit the form

My form needs to customize before submitting to the rails. SO, I use ajax to submit the form, but every time, rails doubles records. Anyone has any idea how it happens.
my controller here:
def create
#school_current = School.find_by_id(params[:school_id])
#quiz = Quiz.new(params[:quiz])
#quiz.from_params(params)
questions = params[:quiz][:questions_attributes]
questions.each do |index, question|
#quiz.questions.build(question)
end
respond_to do |format|
if #quiz.save
format.html { render nothing: true }
else
format.html { render action: "new" }
end
end
end
def from_params(params)
self.name = params[:quiz][:name]
self.school_id = params[:school_id]
self.description = params[:quiz][:description]
end
form:
<div id="quizzes">
<%= form_for([#school_current, #quiz], :remote => true) do |f| %>
<div class="form-inputs" id="quiz_body">
<div class="form-group">
<label>Quiz Name (required)</label>
<%= f.text_field :name, class: "form-control", placeholder: "Enter quiz name here .." %>
</div>
<div class="form-group">
<label>Quiz Description (optional)</label>
<%= f.text_area :description, :rows => 10 , :cols => 10, class: "form-control", placeholder: "Enter quiz description here .." %>
</div>
</div>
<div id="question_list">
<ol>
<%= f.fields_for :questions do |builder| %>
<li class="question_field_item"><%= render "question_fields", f: builder %></li>
<% end %>
</ol>
</div>
<div class="form-actions">
<%= f.submit "save quiz", :data => {disable_with: "Saving ..."},class: "btn btn-primary text-uppercase", id: "save_quiz" %>
</div>
<% end %>
</div>
Make sure, single AJAX request is hitting the server
the following code block might be the culprit.
respond_to do |format|
if #quiz.save
format.html { render nothing: true }
else
format.html { render action: "new" }
end
end
Try extracting the saving from respond_to's block.
if #quiz.save
respond_to do |format|
format.html { render nothing: true }
end
else
respond_to do |format|
format.html { render action: "new" }
end
end
i figured out the problem. Call question.build twice in both new and create. That's why rails duplicates the record. Remove these lines of code. It will work.
questions.each do |index, question|
#quiz.questions.build(question)
end

Proper Quantity into Cart

Just added a text field for quantity in my products listing. Regardless of the number I enter in the text field, the cart will show just an increment of one for that click. Of course, I haven't told it to do anything otherwise. But, how do I? I can't find the solution anywhere.
Here's my cart add method :
def add_product(product_id)
line_items.find_or_initialize_by(product_id: product_id).increment(:quantity)
end
and in LineItems #create :
def create
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
quantity = params[:quantity]
Let me know if there is any other relevant code I can attach. Thanks.
View Code
<%= image_tag(product.image.url, class: 'prodli-img') %>
<h3><%= product.name %></h3>
<p><%= product.description %></p>
<span class="price"><%= number_to_currency(product.price) %></span>
<!--<p> <%= product.colors %> </p>-->
<div id= "text_field"><%= text_field_tag 'quantity' %> </div>
<%= button_to 'Add to Cart', line_items_path(:product_id => product) %>
<% end %>
LI create
def create
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
#line_item.quantity = params[:quantity]
respond_to do |format|
if #line_item.save
format.html { redirect_to "/#products", notice: "Product added to cart!" }
format.xml { render :xml => #line_item,
:status => :created, :location => #line_item }
else
format.html { render :action => "new" }
format.xml { render :xml => #line_item.errors,
:status => :unprocessable_entity }
end
end
end
You can't easily pass additional parameters with a "button_to"
This should work better
<h3><%= product.name %></h3>
<p><%= product.description %></p>
<span class="price"><%= number_to_currency(product.price) %></span>
<%= form_for :line_item, url: product_line_items_path(product) do |f| %>
<%= f.text_field 'quantity' %>
<%= f.submit 'Add to Cart' %>
<% end %>
Your params in the create method will then look like...
=> {"utf8"=>"V",
"authenticity_token"=>"blah blah"
"line_item"=>{"quantity"=>"12"},
"commit"=>"Add to Cart",
"action"=>"create",
"controller"=>"line_items",
"product_id"=>"1"}
So you can retrieve the quantity with...
#line_item.quantity = params[:line_item][:quantity]
Quantity is an attribute of the #line_item object.
So you should be doing
#line_item.quantity = params[:quantity]
And when you save #line_item it will then have the new value stored.

Answerer's username will not show in Rails?

I am fairly new to Rails 4, and I am creating a Q&A site similar to Stack Overflow.
I have a question page much like the one on Stack Overflow. The question part is working, and then I have answers, which are working too, HOWEVER, I want to be able to have the answerer's name next to their answer.
I am pretty sure I have the controller, model and view set up properly. I have reset the database but it still comes up with errors.
Here's my code:
#Answers_controller.rb create action
def create
#answer = #question.answers.new(answer_params)
#answer.user_id = current_user.username
respond_to do |format|
if #answer.save
format.html { redirect_to [#question], notice: 'Answer was successfully created.' }
format.json { render action: 'show', status: :created, location: #answer }
else
format.html { render action: 'new' }
format.json { render json: #answer.errors, status: :unprocessable_entity }
end
end
end
answer.rb (model):
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
validates :body, presence: true
end
#Then in user.rb I have has_many :answers, has_many :questions
#Also in question.rb has_many :answers
answers/_answer.html.erb:
<%= answer.username %>
<%= answer.body %>
</p>
<p>
<% if current_user.present? && current_user == answer.user %>
<%= link_to 'Delete Answer', [answer.question, answer],
method: :delete,
data: { confirm: 'Are you sure?' } %>
<% end %>
</p>
Then in questions/show:
<div class="container">
<div class="row">
<div class="span8">
<h3><%= #question.title %>
<% if current_user.present? && current_user == #question.user %>
<%= link_to 'Edit', edit_question_path(#question) %></h3>
<% end %>
<hr>
</div>
</div>
<div class="row">
<div class="span8">
<p><%= #question.description %></p>
Asked by <%= #question.user.full_name %>
<hr>
</div>
</div>
<%= render "answers/form" %>
<%= render #question.answers %>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('.wysihtml5').each(function(i, elem) {
$(elem).wysihtml5();
});
})
</script>
It looks like you wrong here
#answer = #question.answers.new(answer_params)
try
#answer = #question.answers.build(answer_params)
Explanaition: you build a new answer but do not refer it to question because according to has_many documentation it has collection.build(attributes = {}, …) not collection.new(attributes).
A couple of things that stand out:
#Answers_controller.rb create action
def create
#answer = #question.answers.new(answer_params)
#answer.user_id = current_user.username # ???? should be current_user.id ????
# omitted
end
answers/_answer.html.erb
<%= answer.username %> # ???? you have no username field on your answer model ???
# ??? should be <%= answer.user.username %> ???
<%= answer.body %>
</p>
# omitted

Instance Variable string collection lost after render => 'new'

When I get an error creating a quote, it renders the same page it was just on and displays the errors. Unfortunately two inputs are drop down menus of strings, and they disappear when the refresh happens.
I've looked at Rail 3: instance variable not available after redirection which talks about sessions, which looks like it could be the right way to go but I'm not sure. Any help would be appreciated.
quotes controller
def new
#quote = Quote.new
#quote.items.build
#types = ["T-Shirt", "Hoodie", "Sweatpants"]
#colors = ["White", "Black", "Red", "Blue", "Green"]
end
def create
#quote = Quote.new(params[:quote])
respond_to do |format|
if #quote.save
format.html { redirect_to root_url }
flash[:success] = "Your quote is being approved. You will recieve an email shortly!"
format.json { render json: #quote, status: :created, location: #quote }
else
format.html { render :action => 'new' }
format.json { render :json => #quote.errors, :status => :unprocessable_entry }
flash[:error] = "Quote failed to create! Try again!"
end
end
end
form partial
<!-- item form -->
<%= f.input :make, collection: #types, label: 'Thread Type' %>
<%= f.input :amount, label: 'How Many' %>
<%= f.input :color, collection: #colors %>
<!-- nested form for creating a design of an item -->
<%= f.simple_fields_for :designs, :html => { :multipart => true } do |designform| %>
<%= render "customdesign", g: designform %>
<% end %>
<!-- add/remove another design -->
<%= f.link_to_add "Add Design", :designs %>
<%= f.input :note, :input_html => { :cols => 50, :rows => 3 }, label: 'Special Notes or Requests' %>
<%= f.link_to_remove "Remove" %>
#colors and #types are only set in the new action, and not the create action. Rendering a template does not automatically call the action method in the controller; it goes straight to the view.
A possible solution is to define helper methods for these lists:
# app/helpers/quote_helper.rb
module QuoteHelper
def possible_types
["T-Shirt", "Hoodie", "Sweatpants"]
end
end
And in your view:
<%= f.input :make, collection: possible_types, label: 'Thread Type' %>

Resources