I am trying to add comments withour refresh a page - javascript

When I try to add a comment, it doesnt append on table. When i refresh a page then it append. I dont know what is problem. I think I did everything well. There is no errors on page. And it goes in table whatever I add to table, but only after refresh a page.
show.html.erb
...
<table id="comments">
<tbody>
<% #article.comments.each do |comment| %>
<%= render 'comments/comment', comment: comment %>
<% end %>
</tbody>
...
_comment.html.erb
<tr>
<td><p><%= comment.name %></p></td>
<td><p><%= comment.body %></p></td>
<td><p><%= time_ago_in_words(comment.created_at) %> Ago</p></td>
<% if User.find_by(email: comment.name) == current_user %>
<td><%= link_to 'Delete', [comment.article, comment], method: :delete, data: { confirm: 'Are you sure?' } %></td>
<% else %>
<td> </td>
<% end %>
</tr>
create.js.erb
$('table#comments tbody').append("<%= j render #comment %>")
terminal
ActionController::UnknownFormat (ActionController::UnknownFormat):
app/controllers/comments_controller.rb:7:in `create'
routes.rb
Rails.application.routes.draw do
get 'search/index'
devise_for :users
get 'welcome/index'
get '/search', to: 'search#search'
resources :user
resources :articles do
resources :comments
member do
put "like" => "articles#like"
put "unlike" => "articles#unlike"
end
end
resources :search, only: [:index]
root 'welcome#index'
end
comments_controller.rb
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.create(params[:comment].permit(:name, :body))
#comment.name = current_user.email
respond_to do |format|
if #comment.save
format.js
format.html { redirect_to #comment }
format.json { render :show, status: :created, location: #comment }
else
end
end
end

Because by default, format return from controller is html. So you need to add another formant js in controller to make js.erb work.

Your controller should be something like this:
def create
............
if #comment.save
respond_to do |format|
format.js
end
end
end
to handle the errors: in create.js.erb file, check #comment.errors.any? - then do whatever you want to do.

Related

Rails: Using remote: true to stop page refresh

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">

undefined method `company' for nil:NilClass

I keep receving an error on my home page saying
'undefined method `company' for nil:NilClass'
for the first line of the following code displayed below. I am not really sure on how to fix this. I have two Controllers for both companies and customers because I am creating a two-sided marketplace.
When the user clicks the logo at the top instead of being redirected to the welcome page, the login page is being rendered since the home page is the root_path but I am using devise for before_action authenticate is being used.
<% if((current_user.company) || (current_user.customer)) %>
<%= render 'pages/welcome' %>
<% else %>
<% if current_user.is_company %>
<%= render 'companies/form', company: #company%>
<% else %>
Here is the home.html.erb file with the code which is the root_path
<% if((current_user.company) || (current_user.customer)) %>
<%= render 'pages/welcome' %>
<% else %>
<% if current_user.is_company %>
<%= render 'companies/form', company: #company%>
<% else %>
<%= render 'customers/form', customer: #customer%>
<% end %>
<% end %>
Here is my companiesController
class CompaniesController < ApplicationController
before_action :set_company, only: [:show, :edit, :update, :destroy]
def index
#companies = Company.all
end
# GET /companies/1
# GET /companies/1.json
def show
#company = Company.find(params[:company_id])
end
# GET /companies/new
def new
#company = Company.new
end
# GET /companies/1/edit
def edit
end
# POST /companies
# POST /companies.json
def create
#company = Company.new(company_params)
respond_to do |format|
if #company.save
format.html { redirect_to #company, notice: 'Company was successfully created.' }
format.json { render :show, status: :created, location: #company }
else
format.html { render :new }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /companies/1
# PATCH/PUT /companies/1.json
def update
respond_to do |format|
if #company.update(company_params)
format.html { redirect_to #company, notice: 'Company was successfully updated.' }
format.json { render :show, status: :ok, location: #company }
else
format.html { render :edit }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# DELETE /companies/1
# DELETE /companies/1.json
def destroy
#company.destroy
respond_to do |format|
format.html { redirect_to companies_url, notice: 'Company was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_company
#company = Company.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the
white list through.
def company_params
params.require(:company).permit(:username, :phone, :website, :street, :city, :state, :country, :user_id)
end
end
it just says that the current_user is nil, you need to make sure that the user is logged in to use current_user.company
The log is giving you details as to why the company is returning a nil. The company requires an object in it for the page to load properly. But that is not so because no user is logged in for the company to have an object to return.
<% if((current_user.company) || (current_user.customer)) %> <%=
render 'pages/welcome' %> <% else %>
<% if current_user.is_company %> <%= render 'companies/form',
company: #company%> <% else %>
is returning a nil because no user is logged in.
You can first check if there is a user logged in and then render
something before this to prevent the error page
<% if(current_user) <% if((current_user.company) ||
(current_user.customer)) %>
<%= render 'pages/welcome' %> <% else %>
<% if current_user.is_company %>
<%= render 'companies/form', company: #company%> <% end %> <% else %> render something here <% end %>
Or simply log in to make sure this does not return a nil. But the first fix is the most ideal.

Ajax and Rails Completed 406 Not Acceptable

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.

Rails ajax append single item from collection

In my app I have a commenting system in place that displays comments as a collection and I've got ajax commenting working but currently it renders the entire collection again but what I want is to just append the latest comment. Here's my code:
comments_controller.rb
class CommentsController < ApplicationController
before_filter :authenticate_member!
before_filter :load_commentable
before_filter :find_member
def index
redirect_to root_path
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
#comment.member = current_member
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back }
format.json
format.js
end
end
end
def destroy
#comment = Comment.find(params[:id])
respond_to do |format|
if #comment.member == current_member || #commentable.member == current_member
#comment.destroy
format.html { redirect_to :back }
else
format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
end
end
end
private
def load_commentable
klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] }
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
end
statuses_controller
def show
#status = Status.find(params[:id])
#commentable = #status
#comments = #commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
#comment = Comment.new
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to profile_path(current_member) }
format.js
end
end
statuses/show.html.erb
<% if member_signed_in? %>
<div id="comm_form_wrap">
<%= render "shared/comment_form" %>
</div>
<div id="comments_<%= #commentable.id %>">
<%= render partial: "shared/comments", :collection => #comments, :as => :comment %>
</div>
<% end %>
shared/_comments.html.erb
<div id="comment_<%= comment.commentable.id %>_<%= comment.id %>" class="comments">
<span class="comment_av">
<%= comment_avatar_link_2 comment.member, :class => "com_av", title: comment.member.full_name, alt: comment.member.full_name %>
</span>
<span>
<div class="comment_name">
<% if comment.member == #commentable.member %>
<%= link_to comment.member.user_name, profile_path(comment.member) %> <span class="owner">Creator</span>
<% else %>
<%= link_to comment.member.user_name, profile_path(comment.member) %>
<% end %>
<% if comment.member == current_member || #commentable.member == current_member %>
<span class="comment_del">
<%= link_to image_tag("Delete.png", title: 'Delete'), [#commentable, comment], remote: true, method: :delete, data: { confirm: 'Are you sure?' } %>
</span>
<% end %>
<span class="meta">
<%= time_ago_in_words(comment.created_at) %>
</span>
</div>
<div class="com_con">
<%= Rinku.auto_link(comment.content).html_safe %>
</div>
</span>
</div>
comments/create.js.erb
$("#comments_<%= #commentable.id %>").html("<%= escape_javascript(render :partial => 'shared/comments', :collection => #comments, :as => :comment) %>");
$('#comment_form')[0].reset();
If I just change html to append in the create.js.erb file it will append the entire collection of comments. I guess I could copy and paste the code from my comments partial but that'd be a lot of code and I wouldn't know how to define the variables that way. What's the best way for me to append the single new comment? Thanks in advance.
I was able to figure this one out. Instead of rendering or appending the collection I could just append #comment like so:
$("#comments_<%= #commentable.id %>").append("<%= escape_javascript(render :partial => #comment, :locals => {:comment => #comment}) %>");
Then I just needed to create a _comment.html.erb partial in my comments folder.

Submit Rails from on change of selected value in dropdown form

I have a Rails app with listing of leads in a table. In one of the collumns I display status of a lead in a drop down menu. I want to enable changing this status of the lead on changing the value selected in the drop down.
This is what I tried:
The code to display the form in a table cell:
<% #leads.each do |lead| %>
<tr>
<td><%= lead.id %></td>
<td><%= form_for(lead,:url => 'update_lead_status') do |f| %>
<div class="field">
<%= f.select :status, ["to_call","called","confirmed","lite"], :selected => lead.status, onchange: "this.form.submit();" %>
</div>
<% end %>
</td>
my update_lead_status method in leads controller:
#PUT
def update_lead_status
#lead = Lead.find(params[:id])
respond_to do |format|
# format.js
if #lead.update_attributes(params[:lead])
format.html { redirect_to leads_url, notice: 'Lead was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #lead.errors, status: :unprocessable_entity }
end
end
end
Also I want the submission to be Ajax style without refreshing.
Set form id and then submit form
<%= form_for(lead,:url => 'update_lead_status',:html=>{:id=>'lead_form'}) do |f| %>
<%= f.select :status, ["to_call","called","confirmed","lite"], :selected => lead.status, onchange: "$('#lead_form').submit();" %>
<% end %>

Categories