Proper Quantity into Cart - ruby-on-rails

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.

Related

Rails app - extra record displaying

I have an app that allows users to add albums they like to a database. Anyone can then come along and write a review for that album. Pretty simple.
I am running into a problem where an extra record appears to be created for the reviews on each album's show page. Every album, even if it has not ever been reviewed, has an additional, seemingly empty review being displayed when I use .each to display each review in the album show page. I want to get rid of that.
Here is an image of the problem. I have used CSS to highlight reviews in red. As you can see, there is an empty review at the bottom. When I inspect the review in question, it's raty title is "Not reviewed yet!"
Here is my albums_controller:
class AlbumsController < ApplicationController
before_action :set_album, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, only: [:edit, :new, :update, :destroy]
def index
#albums = Album.all
if params[:search].nil?
#albums = Album.all.order(year: :desc).order(title: :asc).paginate(:page => params[:page], :per_page => 24)
else
#albums = #albums.where("albums.title || albums.year || albums.artist LIKE ?", "%#{params[:search]}%").order(year: :desc).order(title: :asc).paginate(:page => params[:page], :per_page => 24)
end
end
def show
if #album.reviews.blank?
#average_review = 0
else
#average_review = #album.reviews.average(:rating).round(2)
end
#review = #album.reviews.build
end
def new
#album = Album.new
end
def edit
end
def create
#album = current_user.albums.build(album_params)
respond_to do |format|
if #album.save
format.html { redirect_to #album, notice: 'Album was successfully created.' }
format.json { render :show, status: :created, location: #album }
else
format.html { render :new }
format.json { render json: #album.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #album.update(album_params)
format.html { redirect_to #album, notice: 'Album was successfully updated.' }
format.json { render :show, status: :ok, location: #album }
else
format.html { render :edit }
format.json { render json: #album.errors, status: :unprocessable_entity }
end
end
end
def destroy
#album.destroy
respond_to do |format|
format.html { redirect_to albums_url, notice: 'Album was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_album
#album = Album.find(params[:id])
end
def album_params
params.require(:album).permit(:title, :artist, :year, :cover)
end
end
Here is the album show page, which is where the extra review is being displayed:
<div class="row">
<div class="col-xs-10 col-md-6 col-md-push-3 col-xs-push-1 top bottom">
<%= image_tag #album.cover, class: 'show_image' %>
<h2><%= #album.title %></h2>
<h4><%= #album.artist %></h4>
<h5><%= #album.year %></h5>
<p class="white">Average Review<div class="average-review-rating" data-score=<%= #average_review %>></div></p>
<% if user_signed_in? %>
<% if #album.user_id == current_user.id %>
<%= link_to 'Edit', edit_album_path(#album), class: 'grey' %>
| <%= link_to 'Delete', album_path, method: :delete, data: {confirm: "Are you sure?"}, class: 'grey' %>
<% end %>
<% end %>
<br /><br />
<h4>Reviews</h4>
<% if user_signed_in? %>
<p class="grey">Write a review</p>
<%= form_for [#album, #review] do |r| %>
<div class="form-group">
<div id="rating-form">
<label>Rating</label>
</div>
</div>
<div class="form-group">
<%= r.text_area :comment, class: 'form-control', placeholder: "Write a comment" %>
</div>
<div class="form-group">
<%= r.submit "Create", class: 'btn btn-success' %>
</div>
<% end %>
<% end %>
<br />
<% #album.reviews.each do |r| %>
<div class="red">
<div class="review-rating" data-number="<%= r.rating %>">
</div>
<p class="white"><%= r.comment %></p>
<% if user_signed_in? %>
<% if current_user.id == r.user_id %>
<%= link_to 'Edit', edit_album_review_path(#album, r.id), class: 'grey' %> |
<%= link_to 'Delete', album_review_path(#album, r.id), method: :delete, data: {confirm: "Are you sure?"}, class: 'grey' %>
<% end %>
<% end %>
<br /><br />
</div>
<% end %>
</div>
</div>
<script>
$('.review-rating').raty({
readOnly: true,
score: function() {
return $(this).attr('data-number');
},
path: '/assets/'
});
$('#rating-form').raty({
path: '/assets/',
scoreName: 'review[rating]'
});
$('.average-review-rating').raty({
readOnly: true,
path: '/assets/',
score: function() {
return $(this).attr('data-score')
}
});
</script>
Any help would be very appreciated!
The problem here is on the last line of your show method: #review = #album.reviews.build. This line not only creates a new Review instance and assigns it to #review, but it also adds that instance to the array in #album.reviews. So, in your view, when you iterate over #album.reviews, you will see all of the persisted reviews as well as the one new, not persisted review that was built with build.
The easiest way to fix this would be to add this line in your view:
<% #album.reviews.each do |r| %>
<% next unless r.persisted? %>
Another solution would be to associate the new review with the album, but not on the #album instance. In the controller:
#review = Review.new(album: #album)
I think it could be because of last line in show.
#review = #album.reviews.build
It builds an empty review.

Rails don't render layout when create record with Ajax

My problem is after I create a new record with ajax I get a NOMETHODERROR and I must reload the page to see the new record.
The Error I get in terminal.
Rendered time_entries/_time_entry.html.erb (3.4ms) Rendered
time_entries/create.js.erb (4.9ms) Completed 500 Internal Server Error
in 41ms (ActiveRecord: 4.4ms)
NoMethodError - undefined method `each' for nil:NilClass:
app/views/time_entries/_time_entry.html.erb:1:in '_app_views_time_entries__time_entry_html_erb___4086905375499854267_70174828432680'
What I do wrong?
time_entries_controller.erb
class TimeEntriesController < ApplicationController
...
respond_to :html, :js
def index
#time_entries = current_user.time_entries.all.order("date DESC")
#time_entries_days = #time_entries.group_by{ |t| t.date.beginning_of_day }
respond_with(#time_entry)
end
def create
#time_entry = TimeEntry.new(timeentry_params)
#time_entry.user_id = current_user.id
respond_to do |format|
if #time_entry.save
format.html { redirect_to #time_entry, notice: 'Arbeitszeit wurde eingetragen' }
format.json { render :show, status: :created, location: #time_entry }
format.js
else
format.html { render :new }
format.json { render json: #time_entry.errors, status: :unprocessable_entity }
format.js
end
end
end
...
_time_entry.html.erb
the partial
<% #time_entries_days.each do |day, time_entries| %>
<% if day.today? %>
<div class="column-12 list-group">Today, <%= l day, format: :dm %></div>
<% else %>
<div class="column-12 list-group"><%= l day, format: :dm %></div>
<% end %>
<ul class="lists">
<% time_entries.each do |time_entry| %>
<li class="list-item" id="time_entry_<%= time_entry.id %>">
<div class="list-item__content">
<h3 class="list-item__title">
<%= link_to time_entry.category.name, time_entry %>
<span><%= l time_entry.start_time, format: :hm %></span> - <span><%= l time_entry.end_time, format: :hm %></span>
</h3>
<p><%= time_entry.note %></p>
</div>
<span class="list-item__label"><%= time_entry.hours %>h</span>
</li>
<% end %>
</ul>
<% end %>
index.html.erb
<% if can? :create, TimeEntry %>
<%= link_to 'Add new Time Entry', new_time_entry_path, remote: true, class: 'btn btn-primary', :data => { :'popup-open' => 'popup-1' } %>
<% end %>
...
<div class="row" id="container_time_entries">
<%= render "time_entry" %>
</div>
create.js.erb for testing
I don't get an alert after I create a new time entry.
alert("HALLO");
create.js.erb normal
$('.modal-bg').hide();
$('.popup').fadeOut(350);
$('#container_time_entries').html("<%= j(render 'time_entry') %>");
You do not set the variable #time_entries_days in your create method, but you need it in your _time_entry.html.erb .
Set it and you should be good to go.

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

Value update automatically though javascript is off

In my application I am showing all the products like this
store.html.erb
<% #products.each do |product| %>
<div class="entry" >
<%= image_tag(product.image_url) %>
<h3><%= product.title %></h3>
<%= sanitize(product.description) %>
<div class="price_line" >
<span class="price" ><%= number_to_currency(product.price) %></span>
<%= button_to "add to cart", line_items_path(:product_id => product),
:remote => true %>
</div>
</div>
<% end %>
I am sending ajax request with :remote => true and in my line items controller I don't have any .js format
line_items_controller.rb
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
respond_to do |format|
if #line_item.save
format.html { redirect_to(store_url) }
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
What I understand so far is that, since there is no format.js add to cart should not add any product to the cart and nothing should happen. But when I add .js format in the controller
format.js { #current_item = #line_item }
and update the page I see that add to cart worked behind but did not show the result. after updating the page I see 15 or so items in the cart. How is this happening?
Make changes here
<% #products.each do |product| %>
<div class="entry" >
<%= image_tag(product.image_url) %>
<h3><%= product.title %></h3>
<%= sanitize(product.description) %>
<div class="price_line" >
<span class="price" ><%= number_to_currency(product.price) %></span>
<%= button_to "add to cart", line_items_path(:product_id => product.id),
:remote => true %> #changes line
</div>
</div>
<% end %>
and for update you have to make .js file for that and update elements and onject of html page through jquery or javascript.
And use only one format so controller method go to one responsive area.

view incorrectly reloads after uniqueness validation error

After you try to submit a new guideline and you see an error message on the form (due to the guidelines correctly failing validation)...the list of #specialties does not reload correctly (ie. it just says yes/no rather than the proper list you could see before you submitted with an error). I can't work out which part is wrong here...
VIEWS _form.html.erb
<%= simple_form_for(#guideline, html: {class: "form-horizontal"}) do |f| %>
<% if #guideline.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#guideline.errors.count, "error") %> prohibited this guideline from being saved:</h2>
<ul>
<% #guideline.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.input :title, label: 'Title (e.g. Asthma for under 12 months)' %>
<%= f.input :specialty, as: :select, collection: #specialties %>
<%= f.input :hospital %>
<%= f.input :content, as: :string, label: 'Link' %>
<div class="form-actions">
<%= f.button :submit, :class => "btn btn-info btn-large" %>
</div>
<% end %>
guidelines_controller.rb
def new
#guideline = Guideline.new
#specialties = Guideline.order(:specialty).uniq.pluck(:specialty)
respond_to do |format|
format.html # new.html.erb
format.json { render json: #guideline }
end
end
def create
#guideline = current_user.guidelines.new(params[:guideline])
respond_to do |format|
if #guideline.save
format.html { redirect_to #guideline, notice: 'Guideline was successfully created.' }
format.json { render json: #guideline, status: :created, location: #guideline }
else
#specialties = Guideline.order(:specialty).uniq.pluck(:specialty)
format.html { render action: "new" }
format.json { render json: #guideline.errors, status: :unprocessable_entity }
end
end
end
this is a common error. in your create action you should declare #specialties if the validation fails since that is needed in the new template.
def create
#guideline = Guideline.new params[:guideline]
if #guideline.save
else
# you need to declare #specialties here since it is needed in the new template
# which you want to render
#specialties = Specialty.all
render :new
end
end

Resources