What would be the best way to update a record and display a flash success notice without leaving the page?
Here is part of my code but it redirects back to root path:
View
<%= form_for #user, url: record_testimonial_path(#user) do |f| %>
<%= f.text_area :testimonial %>
<%= f.submit "Submit"%>
<% end %>
Controller
def record_testimonial
#user.update_attribute(:testimonial, params[:user][:testimonial])
flash[:success] = "Thank you!"
redirect_to root_path
end
You can redirect back:
redirect_to :back, flash: { success: t('flash.thank_you') }
Or you have to do it via remote:
<%= form_for #user, url: record_testimonial_path(#user), remote: true do |f| %>
<%= f.text_area :testimonial %>
<%= f.submit "Submit"%>
<% end %>
And in the controller:
def record_testimonial
if #user.update_attribute(:testimonial, params[:user][:testimonial])
respond_to do |format|
format.js { render 'record_testimonial', layout: false }
end
else
render nothing: true # This will silently fail. Probably not intended.
end
end
And then the record_testimonial.js.erb:
$('#some_id').html('<%= j render "some_partial", user: #user %>');
These are the most common and I would say sensible ways. If you use ajax don't forget to manually display the flash message, should be 1 line of JS.
Best way to avoid a page refresh completely would be to set the form to use :remote => true like this
<%= form_for #user, url: record_testimonial_path(#user), :remote => true do |f| %>
and then respond accordingly in the controller:
def record_testimonial
respond_to do |format|
if #user.update_attribute(:testimonial, params[:user][:testimonial])
render :success
else
render :error
end
end
end
You would need a corresponding template for success and error here, with which to handle the displaying of a success or error message.
For further info, look here.
Related
I have a projects/show.html.erb page. A project has_many project_messages and from the projects/show.html.erb page, a user can create a new project_message successfully, however, when the new project_message is created through a _formpartial, the page refreshes.
I want to use :remote => true to add project_messages to the project without having to refresh the page.
Please see the code I used below. This does not work and the page still refreshes. I am new to rails so any help would be greatly appreciated.
Please see the code for each file below
In projects/show.html.erbto display the project_message and create a new project_message, I have the following code which is successful:
<div class="au-chat au-chat--border">
<div class="au-message-list">
<% #project.project_messages.each do |project_message| %>
<%= render partial: 'project_messages/project_message', locals: { project_message: project_message } %>
<% end %><br>
</div>
<div class="au-chat-textfield">,
<%= render partial: 'project_messages/form', locals: { project_message: #project_message } %>
</div>
</div>
In the project_messages_controller.rb file the create method is as follows, I have added format.js { }
def create
#project_message = ProjectMessage.new(project_message_params)
#project_message.user_id = current_user.id if current_user
#project_message.project_id = current_user.team.project_id if current_user
respond_to do |format|
if #project_message.save
format.html { redirect_to #project_message.project }
format.json { render :show, status: :created, location: #project_message }
format.js { }
else
format.html { render :new }
format.json { render json: #project_message.errors, status: :unprocessable_entity }
end
end
end
The project_message _form partial then includes the :remote => true
<%= form_with(model: project_message, local: true, :remote => true) do |form| %>
<% if project_message.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(project_message.errors.count, "error") %> prohibited this project_message from being saved:</h2>
<ul>
<% project_message.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form.text_field :pMessage, id: :project_message_pMessage, :class => 'au-input au-input--full au-input--h65', placeholder: 'Type a message' %>
<div class="actions" >
<%= form.submit "Send" %>
</div>
<% end %>
I then created a new create.js.erb file in views/project_messages/create.js.erb and added the following code:
# confirm file called
console.log('create.js.erb file');
# add new comment to end of comments section
$("#project_message").append("<%= j render(#project_message) %>");
With the code above, the page still refreshes.
When I remove local: true from the project_message _form partial, it does not refresh and creates the model but the projects/show.html.erb view is not updated!
I used the following link here and also other posts on stackoverflow
respond_to do |format|
format.js { render 'project_messages/create.js'}
end
it seems you are using Rails 5
remove remote: true and local: true from your code
read about this in here
and make sure that you a html element with id = project_message
your code is $("#project_message").append("<%= j render(#project_message) %>");
so check your HTML code , is there any element with ID like that
you can use traditional form_for http://guides.rubyonrails.org/working_with_javascript_in_rails.html#remote-elements
update below code in your views
<%= form_for project_message, :remote => true do |form| %>
and make sure that you a html element with id like <div class="au-message-list" id="project_message">
I'm building an events app using Rails 5.0 and have comments as a nested resource. Users can create and destroy comments, I'm trying to implement the edit/update function using Ajax/ remote: true so they can update a comment on the same page but it's not working. When I click on the edit link nothing happens. Here's the relevant code -
comments_controller.rb
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
def create
#event = Event.find(params[:event_id])
#comment = #event.comments.create(comment_params)
#comment.user_id = current_user.id
if #comment.save
redirect_to #event
else
render 'new'
end
end
# GET /comments/1/edit
def edit
#event = #comment.event
#comment = #event.comments.find(params[:id])
respond_to do |format|
format.html { render :edit }
format.js {}
end
end
def show
end
def update
if #comment.update(comment_params)
redirect_to #event, notice: "Comment was successfully updated!"
else
render 'edit'
end
respond_to do |f|
format.html { redirect_to #event, notice: "Comment Successfully updated!" }
format.js # render 'comments/update.js.erb'
end
end
def destroy
#event = Event.find(params[:event_id])
#comment = #event.comments.find(params[:id])
#comment.destroy
redirect_to event_path(#event)
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:name, :body)
end
end
_comment.html.erb
<div class="comment clearfix">
<div class="comment_content">
<div id="comments" class="comment">
<p id="comment_name"><strong><%= #comment.name %></strong></p>
<p id="comment_body"><%= #comment.body %></p>
</div>
<p><%= link_to 'Edit', edit_event_comment_path(comment.event), id: "comments", remote: true %></p>
<p><%= link_to 'Delete', comment.event,
method: :delete,
class: "button",
data: { confirm: 'Are you sure?' } %></p>
</div>
</div>
update.js.erb
$('#comments').append("<%= j render #comment %>");
edit.js.erb
$('#comments').html("<%= j render 'form' %>");
_form.html.erb
<%= simple_form_for([#event, #comment], remote: true) do |f| %>
<%= f.label :comment %><br>
<%= f.text_area :body %><br>
<br>
<%= f.button :submit, label: 'Add Comment', class: "btn btn-primary" %>
<% end %>
I've never implemented this action before using Ajax so I'm probably making a few schoolboy errors here. Any assistance appreciated.
You are calling edit method on controller with this
<%= link_to 'Edit', [comment.event, comment], id: "comment", remote: true %>
And you have no edit.js.erb
For updating your comment, you would have to create a form with it's action url pointing to your update method, and marking it as remote true. Then when you submit, it will reach update directly, there is no need to pass through edit method.
There is a method for creating forms with ajax option as default called form_with, you can check it's guide and documentation here:
http://guides.rubyonrails.org/working_with_javascript_in_rails.html#form-with
Updating answer after your question update
Your form would need to become something like this
<%= simple_form_for :comment, :url => "/events/#{comment.event_id}/comments/#{comment.id}", :method => :put do |f| %>
<%= f.label :comment %><br>
<%= f.text_area :body %><br>
<br>
<%= f.button :submit, label: 'Add Comment', class: "btn btn-primary" %>
<% end %>
I currently have a basic to do list app that displays tasks "to do" and also tasks "completed" on the index page of the app. The model "tasks" has the attribute "completed" which I have a link to in the show page of the task:
<%= link_to "Completed", complete_task_path, method: :patch%>
The lists update on page refresh, but I'm having trouble actually making an AJAX request to update this information on the index page.
I'm unsure as to what my url should be, as I've tried to use the one provided using "rake routes" in the console.
My complete.js.erb:
$(document).ready(function() {
console.log("working");
$('.task_submit_box').click(function() {
$.ajax({url: '/tasks/:id/complete', success: function(result) {
$('.task_area').html(result);
console.log(result);
}});
});
});
My html for displaying the tasks:
<ul class="wrapper_task_list">
<% #task.each do |task| %>
<% if task.completed == false %>
<li>
<div class="task_area", id="incomplete_task_area">
<%= link_to task.title, task_path(task), class: 'wrapper_task_name'%>
<%= form_for task, remote: true do |f| %>
<%= f.check_box :completed, class: 'task_check_box' %>
<%= f.submit 'update', class: 'task_submit_box' %>
<% end %>
</div>
</li>
<% end %>
<% end %>
</ul>
And my complete method in my controller:
def complete
#task = current_user.tasks.find(params[:id])
#task.update_attribute(:completed_at, Time.now)
#task.update_attribute(:completed, true)
respond_to do |format|
format.js
format.html
end
redirect_to root_path
end
regarding the route, this is what is displayed for "rake routes" command:
complete_task PATCH /tasks/:id/complete(.:format) tasks#complete
I'm completely lost as to how to make this request go through ajax without throwing back a 406 error. I am trying to add an item to a cart with ajax, and the item does get added and after a refresh the cart is updated. All I receive as an xhr notice with the 406 error. Any help is highly appreciated.
Product Controller
class ProductsController < ApplicationController
def index
#products = Shoppe::Product.root.ordered.includes(:product_categories, :variants)
#products = #products.group_by(&:product_category)
end
def show
#product = Shoppe::Product.root.find_by_permalink(params[:permalink])
end
def buy
#product = Shoppe::Product.root.find_by_permalink!(params[:permalink]) || params[:variant] ? Shoppe::Product.root.find_by_permalink!(params[:permalink]).variants.find(params[:variant].to_i) : #product
current_order.order_items.add_item(#product, 1)
respond_to do |format|
format.js
end
end
end
Show.html.erb
<h2><%= #product.name %></h2>
<% if #product.default_image %>
<%= image_tag #product.default_image.path, :width => '200px', :style => "float:right" %>
<% end %>
<p><%= #product.short_description %></p>
<p>
<% if #product.has_variants? %>
<% #product.variants.each do |v| %>
<%= form_tag product_path(#product.permalink, #product.permalink, :variant => v.id ),id: '#submit-form', remote: true do %>
<%= submit_tag 'Add to basket', :disabled => !v.in_stock? %>
<% end %>
<% end %>
<% else %>
<b><%= number_to_currency #product.price %></b>
<%= link_to "Add to basket", product_path(#product.permalink), :method => :post %>
<% end %>
</p>
<hr>
<%= simple_format #product.description %>
<hr>
<p><%= link_to "Back to list", root_path %></p>
routes.rb
Rails.application.routes.draw do
mount Shoppe::Engine => "/admin"
get "product/:permalink", to: "products#show", as: "product"
post "product/:permalink", to: "products#buy", as: "buy"
get "basket", to: "orders#show"
delete "basket", to: "orders#destroy"
root to: "products#index"
end
products.js.erb
$(document).ready(function() {
var data = $('#submit-form').attr('action')
$.ajax({
type: 'POST',
url: data
});
});
Looking up what format.js does, I found this: rails respond_to format.js API
It seems format.js in your buy action will render the buy.js file. You haven't shown this file, so I'm figuring it doesn't exist.
I'm figuring what you're trying to do is render json, which is simple enough. You could replace:
respond_to do |format|
format.js
end
with this:
render json: <your object>.to_json
make sure to strip any private data before sending the response.
By the way, you should probably be attaching a callback to your $.ajax call.
I have an order form on an item show page:
<%= form_for(Order.new, remote: true) do |f| %>
<%= f.number_field :quantity_requested, value: 0, max: #item.quantity, min: 1, class: "item-quantity form-control" %>
<%= f.hidden_field :item_id, value: #item.id %>
<% end %>
I have to reload the page in order for the new quantity to update in the database. I would like for it to update in the db without having to refresh the page.
This is what I have in my item coffeescript:
$ ->
$('.item-quantity').click () ->
$(this).closest('form').submit();
$.ajax(url: item_url).done (html) ->
$('.item-quantity').append html
And this is what I have in my order controller:
def create
#order = Order.find_or_initialize_by(user_id: current_user.id, item_id: params[:order][:item_id])
#order.update_attribute(:quantity_requested, params[:order][:quantity_requested])
#order.save
respond_to do |format|
format.html { redirect_to :back }
format.js { redirect_to :back }
end
end
I suspect my error is in coffeescript. I've tried adding return false and prevent default but that doesn't work. Can anyone help? Thanks a lot in advance.