I've having trouble with the following coffeescript:
jQuery ->
# Create a comment
$(".comment-form")
.on "ajax:beforeSend", (evt, xhr, settings) ->
$(this).find('textarea')
.addClass('uneditable-input')
.attr('disabled', 'disabled');
.on "ajax:success", (evt, data, status, xhr) ->
$(this).find('textarea')
.removeClass('uneditable-input')
.removeAttr('disabled', 'disabled')
.val('');
$(xhr.responseText).hide().insertAfter($(this)).show('slow')
# Delete a comment
$(document)
.on "ajax:beforeSend", ".comment", ->
$(this).fadeTo('fast', 0.5)
.on "ajax:success", ".comment", ->
$(this).hide('fast')
.on "ajax:error", ".comment", ->
$(this).fadeTo('fast', 1)
Basically, I have a user form that I add comments to. When a new comment is added it should change class and disable the textarea before sending the data off to the database. Then it should reset the class, clear the textarea and enable the textarea again. Then finally it should add the new comment after the textarea.
The first part of the code works and the class is added to the textarea and it is set to disabled but the rest of the script never happens. Of course the comment is actually saved to the database and a refresh of the page will show the comment.
I've gone over this a ton of times and can't figure out what is going wrong. I did have an earlier issue with the indenting being wrong with the script but that has been fixed.
My CommentController code is as below:
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :destroy]
def create
#comment_hash = comment_params
#obj = #comment_hash[:commentable_type].constantize.find(#comment_hash[:commentable_id])
# Not implemented: check to see whether the user has permission to create a comment on this object
#comment = Comment.build_from(#obj, current_user, #comment_hash[:body])
#comment.user = current_user
if #comment.save
render partial: "comments/comment", locals: { comment: #comment }, layout: false, status: :created
else
p #comment.errors
render js: "alert('error saving comment');"
end
end
def destroy
if #comment.destroy
render json: #comment, status: :ok
else
render js: "alert('error deleting comment');"
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit( :commentable_id, :commentable_type, :body, :user_id)
end
end
Here's my form for creating comments:
<div class='comment-form'>
<%= simple_form_for comment, remote: true do |f| %>
<%= f.input :body, input_html: { rows: "2" }, label: false %>
<%= f.input :commentable_id, as: :hidden, value: comment.commentable_id %>
<%= f.input :commentable_type, as: :hidden, value: comment.commentable_type %>
<%= f.button :submit, 'Save Note', class: "button tiny radius", disable_with: "Submitting…" %>
<% end %>
</div>
And here's my code for displaying comments:
<div class='comment'>
<hr>
<%=link_to "×", comment_path(comment), method: :delete, remote: true, data: { confirm: 'Are you sure you want to remove this comment?',disable_with: 'x' }, class: 'close' %>
<small><%=comment.updated_at.to_s(:short) %></small>
<p><%= comment.body %></p>
By the way, the delete action partially works. It deletes the comment from the database and it hides all of the comments. A page refresh shows the comments that have not been deleted.
Any help would be greatly appreciated since I don't know where to go with this not at all. In my mind it should work so I must be missing something simple.
It's an issue with your indentation. The line .on "ajax:success" must be indented at the same level as the other .on. And the code that follows must be indented accordingly as well:
jQuery ->
# Create a comment
$(".comment-form")
.on "ajax:beforeSend", (evt, xhr, settings) ->
$(this).find('textarea')
.addClass('uneditable-input')
.attr('disabled', 'disabled');
.on "ajax:success", (evt, data, status, xhr) -> #<-- this line!
$(this).find('textarea')
.removeClass('uneditable-input')
.removeAttr('disabled', 'disabled')
.val('');
$(xhr.responseText).hide().insertAfter($(this)).show('slow')
Related
I have follow and unfollow buttons for users on my application. I don't want to do anything fancy, I just want to not have the page refresh every time follow or unfollow button is clicked.
My controller
relationships_controller.rb
def create
current_user.follow(#user)
respond_to do |format|
format.html { #handle HTML, i.e. full page reload }
format.js # handle ajax request
end
end
def destroy
current_user.unfollow(#user)
respond_to do |format|
format.html
format.js # this one handle the request comes from `remote: true` button
end
end
My view
tweets/index.html.erb
<% if current_user.id != tweet.user.id %>
<% if current_user.following?(tweet.user) %>
<%= button_to "Unfollow", relationships_path(user_id: tweet.user), remote: true, method: :delete, :class => "btn btn-primary" %>
<% else %>
<%= button_to "Follow", relationships_path(user_id: tweet.user), remote: true, :class => "btn btn-primary" %>
<% end %>
<br>
<% end %>
<hr/>
<% end %>
Relationships model
relationship.rb
class Relationship < ApplicationRecord
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
end
User model
User.rb
has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
has_many :passive_relationships, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy
has_many :following, through: :active_relationships, source: :followed
has_many :followers, through: :passive_relationships, source: :follower
def follow(user)
active_relationships.create(followed_id: user.id)
end
def unfollow(user)
active_relationships.find_by(followed_id: user.id).destroy
end
def following?(user)
following.include?(user)
end
Routes
routes.rb
resource :relationships, :only => [:create, :destroy]
Application.js
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("chartkick")
require("chart.js")
//= require jquery3
//= require popper
//= require bootstrap-sprockets
Inspected button element
<form class="button_to" method="post" action="/relationships?user_id=1" data-remote="true"><input class="btn btn-primary" type="submit" value="Follow"><input type="hidden" name="authenticity_token" value="hfwF8wXBcp/OM2P/pCYBnEBrjw22BDKWbw/dZFwwDsRpiIFq5jBKS/AoTMjkCZRrGum7UyW1kaL3h/4XEM2wIg=="></form>
With this when I click follow nothing now happens. I think I need a new js file in my views but unsure how to implement it.
I have looked at solutions but they are many and varied and seeking to do more than I want to do which is just a simple no refresh.
How is this best achieved? (can provide more code if needed)
EDIT: This code got jQuery working in Rails 6 in my ..webpack/enironment.js file
# app/config/webpack/environment.js
const {environment} = require('#rails/webpacker');
const webpack = require('webpack');
environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery' # or if its not work specify path `'jquery/src/jquery'` which node_modules path for jquery
}));
module.exports = environment;
For #max
$(document).on('ajax:success', '.follow-btn', function(event){
let $el = $(this);
let method = this.dataset.method;
if (method === 'post') {
$('.follow-btn[href="'+this.href+'"]').each(function(el){ $(el).text('Unfollow'); });
this.dataset.method = 'delete';
} else if (method === 'delete') {
$('.follow-btn[href="'+this.href+'"]').each(function(el){ $(el).text('Follow'); });
this.dataset.method = 'post';
}
});
Instead of going down the js.erb rabbit hole you can just send a JSON request and write a simple event handler.
Lets start by adding a data-type="json" attribute to the buttons so they send a request for JSON instead of javascript:
<% unless current_user == tweet.user %>
<% if current_user.following?(tweet.user) %>
<%= link_to "Unfollow", relationships_path(user_id: tweet.user),
data: { remote: true, type: :json, method: :delete },
class: "follow-btn btn btn-primary"
<% else %>
<%= link_to "Follow", relationships_path(user_id: tweet.user),
data: { remote: true, type: :json, method: :post},
class: "follow-btn btn btn-primary"
%>
<% end %>
<% end %>
And then just write JSON responses for your controller.
def create
current_user.follow(#user)
respond_to do |format|
format.html
format.json { head :created }
end
end
def destroy
current_user.unfollow(#user)
respond_to do |format|
format.html
format.json { head :no_content }
end
end
As you can see its pretty damn simple, when creating a resource you return a 201 - Created and usually a location header or the entity in the body (a JSON payload describing what was created). When you update or destroy a record a 204 - No Content status code is sufficient.
If you test it now and look at the network tab in your browser inspector you will see that an AJAX request is sent but nothing happens in the view.
So lets write an event handler that toggles the button text and method after the request was sent. Since Rails UJS already created the AJAX handler for the button for us we can just hook into its events:
// put this in your application.js or anywhere in your pack
$(document).on('ajax:success', '.follow-btn', function(event){
let $el = $(this);
let method = this.dataset.method;
if (method === 'post') {
$el.text('Unfollow');
this.dataset.method = 'delete';
} else if (method === 'delete') {
$el.text('Follow');
this.dataset.method = 'post';
}
});
Why is this better than a js.erb template?
No server side involvement in updating the UI on the client. No spagetti-code views.
JavaScript is minified, not generated by ERB and easy to debug/reason about.
It can be changed to use optimistic create/delete to give instant feedback
I have a simple inventory system application I've been developing for a class project. One of the requirements is to have some form of Javascript and AJAX doing something in the app. It doesn't have to be anything large or super complicated, but it does have to be there. What my group decided to do was render a popup that displays information about an item when you click on the 'show' link, as it was similar to an example the professor did in class and it was somewhat useful for our app as well. However I cannot get it to work, it just bypasses the ajax and javascript stuff and goes straight to the show.html.haml page. Here is my code:
index.html.haml
%p#notice= notice
%h1 Items
%table
%thead
%tr
%th Name
%th Description
%th Quality
%th Price
%th Location
%th Options
%tbody
- #items.each do |item|
%tr
%td= item.name
%td= item.description
%td
= item.quality
%br/
%br/
= item.quality_desc
%td= item.price
%td= item.location
%td{:colspan => "3"}
= link_to 'Show', item, class: "items"
= link_to 'Edit', edit_item_path(item)
= link_to 'Destroy', item, method: :delete, data: { confirm: 'Are you sure?' }
%br/
= link_to 'New Item', new_item_path
_item.html.haml
This is the information that the popup is supposed to display
%h1 Items
%h2
= item.name
, #{item.category}
%br/
- item.images.each do |image|
= image_tag(image.small.url)
%br
Price: $#{item.price}
%br/
Description: #{item.description}
%br/
Quality: #{item.quality},
\#{item.quality_desc}
%br/
Location: #{item.location}
%br/
%br/
%br/
= link_to 'Edit', edit_item_path(#item)
= link_to 'Close', '', id: 'closeLink'
items_controller.rb
class ItemsController < ApplicationController
before_action :set_item, only: [:show, :edit, :update, :destroy]
# GET /items
# GET /items.json
def index
#items = Item.all
end
# GET /items/1
# GET /items/1.json
def show
render(:partial => 'item', :object => #item) if request.xhr?
end
# GET /items/new
def new
#item = Item.new
end
# GET /items/1/edit
def edit
end
# POST /items
# POST /items.json
def create
#item = Item.new(item_params)
respond_to do |format|
if #item.save
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render :show, status: :created, location: #item }
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /items/1
# PATCH/PUT /items/1.json
def update
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #item }
else
format.html { render :edit }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /items/1
# DELETE /items/1.json
def destroy
#item.destroy
respond_to do |format|
format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_item
#item = Item.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def item_params
params.fetch(:item, {}).permit(:name, :description, :quality, :quality_desc, :price, :location, :category, { images: [] })
end
end
items.js
var ItemPopup = {
setup: function() {
// add hidden 'div' to end of page to display popup:
var popupDiv = $('<div id="itemInfo"></div>');
popupDiv.hide().appendTo($('body'));
$(document).on('click', '#items a', ItemPopup.getItemInfo);
},
getItemInfo: function() {
$.ajax({type: 'GET',
url: $(this).attr('href'),
timeout: 5000,
success: ItemPopup.showItemInfo,
error: function(xhrObj, textStatus, exception) {alert('Error!'); }
//'success' and 'error' functions will be passed 3 args
});
return(false);
},
showItemInfo: function(data, requestStatus, xhrObject) {
//center a floater 1/2 as wide and 1/4 as tall as screen
var oneFourth = Math.ceil($(window).width() / 4);
$('#itemInfo').css({'left': oneFourth, 'width': 2*oneFourth, 'top': 250}).html(data).show();
//make the Close link in the hidden element work
$('#closeLink').click(ItemPopup.hideItemInfo);
return(false); //prevent default link action
},
hideItemInfo: function() {
$('#itemInfo').hide();
return(false);
}
};
$(ItemPopup.setup);
application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
// require turbolinks
// require_tree .
//= require items
application.html.haml
!!!
%html
%head
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
%title InventoryManager
= csrf_meta_tags
// = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
// = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
= stylesheet_link_tag 'application'
= javascript_include_tag "application"
%body
%nav.navbar.navbar-default
.container-fluid
/ Brand and toggle get grouped for better mobile display
.navbar-header
%button.navbar-toggle.collapsed{"aria-expanded" => "false", "data-target" => "#bs-example-navbar-collapse-1", "data-toggle" => "collapse", :type => "button"}
%span.sr-only Toggle navigation
%span.icon-bar
%span.icon-bar
%span.icon-bar
%a.navbar-brand{:href => "/default/index"} InventoryManager
/ Collect the nav links, forms, and other content for toggling
#bs-example-navbar-collapse-1.collapse.navbar-collapse
%ul.nav.navbar-nav
%li.active
%a{:href => "#"}
Items
%span.sr-only (current)
%ul.nav.navbar-nav.navbar-right
- if admin_signed_in?
%li= link_to "Logout", destroy_admin_session_path, :method => :delete
- elsif employee_signed_in?
%li= link_to "Logout", destroy_employee_session_path, :method => :delete
- else
%li
%a{:href => "/admins/sign_in"} Admin
%li
%a{:href => "/employees/sign_in"} Staff
/ /.navbar-collapse
/ /.container-fluid
= yield
If you need anymore of the code just ask. This is in Ruby on Rails 5
EDIT: So I fixed it by changing the selector in the event handler function so that it read '#items' and it grabbed the elements on my page with that id. However I got the code I was trying to use originally from a textbook, implying that what was there was supposed to work. Can someone explain to me why it didn't work initially?
EDIT2: Nevermind I figured it out.
So it turns out my trouble was this line right here:
$(document).on('click', '#items a', ItemPopup.getItemInfo);
I got this code from my class's textbook and modified it slightly to fit my application. As a result of this and a lack of knowledge of how the selectors worked, I thought this was selecting anchor tags with an id of 'items'. As it turns out, what it was actually doing is getting all the anchor tags inside an element with an id of 'items', in the case of the book, this particular element was a table, and the only links inside that table went to that applications show.html.haml page. That didn't quite work for my app since the index table has 3 different types of links on it, so I changed the line to read
$(document).on('click', '.items', ItemPopup.getItemInfo);
and changed the 'show' links on my index.html.haml to have a class of 'items'. This fixed my problem and it works perfectly now.
That being said if there is a solution to this sort of problem that is considered a better practice feel free to share it as an answer to this proble, as well, I'm all for learning something new.
Webpage Look
So I have a Todo List and contains Todo Items. And for each incomplete task(item), there is a button next to it called "Mark Item as Done". (See button_to method) Whenever I click on that button, it should go into that item and mark it as done. However, I'm struggling to implement AJAX into this project and I need help. I'm new to rails and ajax, so I have no clue what I'm doing... The alert message in the update.js.erb is to test if it's reaching there.
Am I supposed to create a partial file called _todoitems.html.erb or _todolists.html.erb? And what else am I missing and what else do I need to do?
Here are the relevant files of what I've done so far...
routes.rb
todolist_todoitems GET /todolists/:todolist_id/todoitems(.:format) todoitems#index
POST /todolists/:todolist_id/todoitems(.:format) todoitems#create
new_todolist_todoitem GET /todolists/:todolist_id/todoitems/new(.:format) todoitems#new
edit_todolist_todoitem GET /todolists/:todolist_id/todoitems/:id/edit(.:format) todoitems#edit
todolist_todoitem GET /todolists/:todolist_id/todoitems/:id(.:format) todoitems#show
PATCH /todolists/:todolist_id/todoitems/:id(.:format) todoitems#update
PUT /todolists/:todolist_id/todoitems/:id(.:format) todoitems#update
DELETE /todolists/:todolist_id/todoitems/:id(.:format) todoitems#destroy
todolists GET /todolists(.:format) todolists#index
POST /todolists(.:format) todolists#create
new_todolist GET /todolists/new(.:format) todolists#new
edit_todolist GET /todolists/:id/edit(.:format) todolists#edit
todolist GET /todolists/:id(.:format) todolists#show
PATCH /todolists/:id(.:format) todolists#update
PUT /todolists/:id(.:format) todolists#update
DELETE /todolists/:id(.:format) todolists#destroy
root GET / todolists#index
todolists/_form.html.erb
<%= form_for(#todolist, remote: true) do |f| %>
todolists_controller.rb
# PATCH/PUT /todolists/1
# PATCH/PUT /todolists/1.json
def update
respond_to do |format|
if #todolist.update(todolist_params)
format.html { redirect_to #todolist, notice: 'Todolist was successfully updated.' }
format.json { render :show, status: :ok, location: #todolist }
format.js
else
format.html { render :edit }
format.json { render json: #todolist.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_todolist
#todolist = current_user.todolists.find(params[:id])
end
todolists/show.html.erb
<!-- paginate_items is basically the current user's items -->
<% #paginate_items.each do |item| %>
<div class="list">
<% if item.due_date > Date.today %>
<% if item.done? %>
<a class="complete">
<%= item.due_date %>
</a>
<a class="linkResults">
<%= link_to "#{item.task_title}", [#todolist, item], style: "font-weight: bold;" %><br/> <br/>
</a>
<% else %>
<form class="oneLine">
<a class="notDue">
<%= item.due_date %>
</a>
<a class="linkResults">
<%= link_to "#{item.task_title}", [#todolist, item], style: "font-weight: bold;" %>
<%= button_to "Mark Item as Done", edit_todolist_todoitem_path(#todolist, item), remote: true, id: "done_item_true" %><br/> <br/>
</a>
</form>
<% end %>
todolists/update.js.erb
alert("TEST TEST TEST");
Add a custom route for the ajax request in routes.rb. If you have resources for items make it something like:
resources :items do
collection do
post 'check_it_off'
end
end
Add a corollary controller action in your items controller and update the state when that action is called:
def check_it_off
item_id = params[:item_id]
item = Item.find(item_id)
# whatever you are updating, just an example
item.status = done
item.save
render json: {data: "Success"}
end
Attach an event to marking the item off and call your ajax request:
$(document).on('click', '.some-class', function(e){
e.preventDefault();
var itemId = $('#item_id')
$.ajax({
type: 'POST',
url: '/items/check_it_off'
data: itemId
}).done(function(response){
console.log(response)
})
})
In your view, give every item an id that relates to their actual id by saying something like: id="<%= item.id %>"
That should do it. That's basically a full ajax post request.
Add some javascript to handle the response on the form and the update the dom on the success callback.
$(function(){
$("#form_id").on("ajax:success", function(e, data, status, xhr) {
// update the dom here, e.g.
$("#stuff").append('<img src="check.png"/>');
}
).on("ajax:error", function(e, xhr, status, error) {
console.log(e, xhr, status, error);
}
)
});
I am following section 4 (Server Side Concerns) to set up ajax on a page. I've copied the tutorial text completely (replacing the model names with my own) and it creates and saves my "Participants" record, but does not automatically refresh the ajax partial.
This is the error I get...which looks like it's referrring to my create.js.erb
ActionView::Template::Error ('nil' is not an ActiveModel-compatible object. It must implement :to_partial_path.):
1: $("<%= escape_javascript(render #participant) %>").appendTo("#participants");
2: // $('#participants').html("<%= j (render #participants) %>");
app/views/participants/create.js.erb:2:in `_app_views_participants_create_js_erb___1675277149181037111_70181034249880'
Here's my code
class ParticipantsController < ApplicationController
def new
#participant = Participant.new
#participants = #participants.recently_updated
end
def create
#participant = Participant.new(participant_params)
respond_to do |format|
if #participant.save
format.html { redirect_to #participant, notice: 'Helper Invited!' }
format.js {}
format.json { render json: #participant, status: :created, location: #participant }
else
format.html { render action: "new" }
format.json { render json: #participant.errors, status: :unprocessable_entity }
end
end
end
_form.html.erb
<ul id="participants">
<%= render #participants %>
</ul>
<%= form_for(#participant, remote: true) do |f| %>
<%= f.label :email %><br>
<%= f.email_field :email %>
<%= f.submit 'SUBMIT' %>
<script>
$(document).ready(function() {
return $("#new_participant").on("ajax:success", function(e, data, status, xhr) {
return $("#new_participant").append(xhr.responseText);
}).on("ajax:error", function(e, xhr, status, error) {
return $("#new_participant").append("<p>Oops. Please Try again.</p>");
});
});
</script>
<script>
$(function() {
return $("a[data-remote]").on("ajax:success", function(e, data, status, xhr) {
return alert("The helper has been removed and notified.");
});
});
</script>
_participant.html.erb
<li >
<%= participant.email %> <%= link_to participant, remote: true, method: :delete, data: { confirm: 'Are you sure?' } do %>REMOVE<% end %>
</li>
create.js.erb
$("<%= escape_javascript(render #participant) %>").appendTo("#participants");
destroy.js.erb
$('#participants').html("<%= j (render #participants) %>");
It's on line 2 of your create.js.erb file, it's the missing #participants not the #participant.
You've commented the line out in JS, but the ERB is still going to be processed by Rails, so it's still trying to do the render #participants
Update
For future... it's the last line of that error that's the key:
app/views/participants/create.js.erb:2
See the 2 at the end, that's telling you which line the error happened on, and so that's where you need to focus when looking for the problem.
I am getting an uncaught reference error: XHR is not defined in my coffeescript below.
jQuery ->
# Create a comment
$(".comment-form")
.on "ajax:beforeSend", (evt, xhr, settings) ->
$(this).find('textarea')
.addClass('uneditable-input')
.attr('disabled', 'disabled');
.on "ajax:success", (evt, data, status, xhr) ->
$(this).find('textarea')
.removeClass('uneditable-input')
.removeAttr('disabled', 'disabled')
.val('');
$(xhr.responseText).hide().insertAfter($(this)).show('slow')
# Delete a comment
$(document)
.on "ajax:beforeSend", ".comment", ->
$(this).fadeTo('fast', 0.5)
.on "ajax:success", ".comment", ->
$(this).hide('fast')
.on "ajax:error", ".comment", ->
$(this).fadeTo('fast', 1)
I have been unable to figure out the issue and I've pretty weak in javascript.
What I'm trying to do is add a comment to a users page then show it via AJAX. The comment saves without any problem as I can see it if I manually refresh the page. However neither the create or delete actions work in the Coffeescript.
Since neither the create or delete AJAX calls seem to work, I am assuming it's in the way the script is called. I'll include the relevant controller code here as well.
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :destroy]
def create
#comment_hash = comment_params
#obj = #comment_hash[:commentable_type].constantize.find(#comment_hash[:commentable_id])
# Not implemented: check to see whether the user has permission to create a comment on this object
#comment = Comment.build_from(#obj, current_user, #comment_hash[:body])
#comment.user = current_user
if #comment.save
render partial: "comments/comment", locals: { comment: #comment }, layout: false, status: :created
else
p #comment.errors
render js: "alert('error saving comment');"
end
end
def destroy
if #comment.destroy
render json: #comment, status: :ok
else
render js: "alert('error deleting comment');"
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit( :commentable_id, :commentable_type, :body, :user_id)
end
end
Also my partial for the comment:
<div class='comment'>
<hr>
<%=link_to "×", comment_path(comment), method: :delete, remote: true, confirm: "Are you sure you want to remove this comment?", disable_with: "×", class: 'close' %>
<small><%=comment.updated_at.to_s(:short) %></small>
<p><%= comment.body %></p>
And the form itself to add new comments:
<div class='comment-form'>
<%= simple_form_for comment, remote: true do |f| %>
<%= f.input :body, input_html: { rows: "2" }, label: false %>
<%= f.input :commentable_id, as: :hidden, value: comment.commentable_id %>
<%= f.input :commentable_type, as: :hidden, value: comment.commentable_type %>
<%= f.button :submit, 'New Note', class: "button tiny radius", disable_with: "Submitting…" %>
<% end %>
</div>
Any help would be appreciated since I just don't know where to start right now. I'm not sure how I should be defining the XHR.
Incidentally, most of the code for this was from the tutorial here