Rails 5 AJAX refusing to render partial - javascript

I created an AJAX function that allows you to click to refresh posts at the top of the stack. Unfortunately, the ajax function is receiving the wrong parameters and returning server error 500. I am simply trying to load the latest posts available (most recent) I can't catch where the error is coming from. What do I need to do to get the newest posts to load on the stack using AJAX GET in index.html.erb?
posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: %[show edit update destroy share like]
before_action :authenticate_user!
def index
following_ids = current_user.following_users.pluck(:id)
following_ids << current_user.id
#posts = Post.where(user_id: following_ids).order('created_at DESC').page(params[:page])
#post = Post.new
end
def load_more
following_ids = current_user.following_users.pluck(:id)
following_ids << current_user.id
#posts = Post.where(user_id: params[:following_ids]).order('created_at DESC').limit(20)
respond_to do |format|
format.html
format.js
end
end
index.html.erb
<div class="col-md-5">
<div class="post-feed-bg">
<div id="post-index-form" class="post-form-bottom-padding">
<%= render 'posts/form' %>
</div>
<!---LOAD MORE POSTS BUTTON-->
<%= link_to load_more_path(#posts), class: 'bttn-material-circle bttn-danger bttn-md load-more-posts', :remote => true do %>
<i class="fas fa-sync"></i>
<% end %>
<div class="post-textarea-bottom-border"></div>
<div class="text-center">
<%= image_tag 'post/loading.gif', style: 'display: none;', class: 'loading-gif' %>
</div>
<div class="post-feed-container" id="container_posts">
<% if #posts.present? %>
<%= render partial: "posts/posts", locals: {posts: #posts} %>
<% end %>
</div>
</div>
</div>
_posts.html.erb
<% #posts.each do |post| %>
<div class="post-container" data-id="<%= post.id %>">
<div class="media" style="padding-bottom: 2em;">
<%= user_avatar_post(post.user) %>
<div class="media-body post-user-name">
<h5><i class="fas fa-user"></i> <%= link_to post.user.user_full_name, user_path(post.user) %></h5>
<p><%= linkify_hashtags(post.body_text) %> </p>
</div>
</div>
<div class="post-container-charm-bar">
<ul>
<li class="votes" id="#post_<%= post.id %>">
<%= link_to like_post_path(post), style: 'text-decoration: none', class: 'like-btn', method: :put, remote: true do %>
<p id="thumb-id" class="thumbs-up" style="cursor: pointer;">b</p>
<% end %>
</li>
<li><strong class="likes-count"><%= number_with_delimiter(post.get_likes.size) %></strong></li>
<li><%= link_to '#', data: {toggle: "modal", target: "#commentmodal"} do %>
<%= link_to post_path(post, anchor: 'comments') do %>
<i class="far fa-comments post-charm-bar-icon-color fa-2x"></i>
<% end %>
<% end %>
</li>
<li><strong><%= post.comment_threads.size %></strong></li>
<li>
<%= link_to({controller: 'posts', action: 'share', id: post.id}, method: :post, remote: true, style: 'text-decoration: none;') do %>
<i class="far fa-share-square fa-2x "></i>
<% end %>
</li>
<li>
<%= link_to post, style: 'text-decoration: none;' do %>
<i class="fas fa-eye fa-2x"></i>
<% end %>
</li>
<li>
<%= link_to edit_post_path(post), style: 'text-decoration: none;' do %>
<i class="fas fa-pencil-alt fa-2x post-charm-bar-icon-color"></i>
<% end %>
</li>
<li>
<% if current_user == post.user %>
<%= link_to post_path(post), style: 'text-decoration: none;', method: :delete, remote: true do %>
<i class="fas fa-trash-alt fa-2x"></i>
<% end %>
<% end %>
</li>
</ul>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-md-12 post-image">
<% if post.photo.present? %>
<%= image_tag post.photo.feed_preview, class: 'd-flex align-self-start mr-3 img-fluid rounded', lazy: true %>
<% else %>
<% end %>
</div>
</div>
</div>
</div>
<% end %>
<script type="text/javascript">
$(document).ready(function () {
$("img").lazyload({
effect: "fadeIn",
skip_invisible: true,
threshold: 500
});
});
</script>
index.js.erb
// Load new records
$("#container_posts").prepend("<%= escape_javascript(render(#posts)) %>").hide().fadeIn(1000);
//Append new data
$("<%= j render partial: "posts/#{#post.post_type}", locals: {post: #post } %>").appendTo($("#container_posts"));
//Update pagination link
<% if #posts.last_page? %>
$('.pagination').html("All done");
<% else %>
$('.pagination').html("<%= j link_to_next_page(#posts, 'Next Page', :remote => true) %> ");
routes.rb
resources :posts, on: :collection do
member do
......
end
end
get "/load_more", to: "posts#load_more", as: 'load_more'
load_more_posts.js
$(document).on('turbolinks:load', function () {
$('a.load-more-posts').click(function (e) {
// prevent the default click action
e.preventDefault();
// hide more load more link
$('.load-more-posts').hide();
// show loading gif
$('.loading-gif').show();
// get the last id and save it in a variable 'last-id'
var last_id = $('.post-container').last().attr('data-id');
// make an ajax call passing along our last career insight id
$.ajax({
// make a get request to the server
type: "GET",
// get the url from the href attribute of our link
url: "/posts",
// send the last id to our rails app
data: {
id: last_id,
user_profile: "", // maybe nil in certain cases
_: ""
},
// the response will be a script
dataType: "script",
success: function (data, textStatus, jqXHR) {
if (jqXHR.status == "204") {
$('.loading-gif').hide();
$('.load-more-posts').show();
}
$('.loading-gif').hide();
$('.load-more-posts').show();
},
error: function (jqXHR, exception) {
}
})
});
});
post parameters
=> #<Post id: 59, body_text: "Fix this!", photo: nil, user_id:
2, created_at: "2018-11-02 19:13:09", updated_at: "2018-11-02 19:13:09", post_id: nil, post_id: nil, post_counter: 0, cached_votes_total: 0, cached_votes_score: 0, cached_votes_up: 0, cached_votes_do
wn: 0, cached_weighted_score: 0, cached_weighted_total: 0, cached_weighted_avera
ge: 0.0, hash_id: "DQxad5rRVvfb">
server stacktrace
Started GET "/load_more.%23%3CPost::ActiveRecord_Relation:0x0000000016f89718%3E" for 127.0.0.1 at 2018-11-03 00:32:58 -0400
Started GET "/posts?id=41&user_profile=&_=1541219410513" for 127.0.0.1 at 2018-11-03 00:32:58 -0400
Processing by PostsController#load_more as
Processing by PostsController#index as JS
Parameters: {"id"=>"41", "user_profile"=>"", "_"=>"1541219410513", "on"=>:collection}
User Load (3.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 5], ["LIMIT", 1]]
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 5], ["LIMIT", 1]]
DEPRECATION WARNING: Setting custom parent classes is deprecated and will be removed in future versions. (called from parent_class_name at C:/Ruby24-x64/lib/ruby/gems/2.4.0/bundler/gems/acts_as_follower-c5ac7b9601c4/lib/acts_as_follower/follower_lib.rb:10)
DEPRECATION WARNING: Setting custom parent classes is deprecated and will be removed in future versions. (called from parent_class_name at C:/Ruby24-x64/lib/ruby/gems/2.4.0/bundler/gems/acts_as_follower-c5ac7b9601c4/lib/acts_as_follower/follower_lib.rb:10)
(2.0ms) SELECT "users"."id" FROM "users" INNER JOIN "follows" ON "follows"."followable_id" = "users"."id" AND "follows"."followable_type" = $1 WHERE "follows"."blocked" = $2 AND "follows"."follower_id" = $3 AND "follows"."follower_type" = $4 AND "follows"."followable_type" = $5 [["followable_type", "User"], ["blocked", false], ["follower_id", 5], ["follower_type", "User"], ["followable_type", "User"]]
(58.0ms) SELECT "users"."id" FROM "users" INNER JOIN "follows" ON "follows"."followable_id" = "users"."id" AND "follows"."followable_type" = $1 WHERE "follows"."blocked" = $2 AND "follows"."follower_id" = $3 AND "follows"."follower_type" = $4 AND "follows"."followable_type" = $5 [["followable_type", "User"], ["blocked", false], ["follower_id", 5], ["follower_type", "User"], ["followable_type", "User"]]
Completed 406 Not Acceptable in 127ms (ActiveRecord: 5.0ms)
ActionController::UnknownFormat (ActionController::UnknownFormat):
SERVER Stacktrace Update 2
Rendered collection of posts/_post.html.erb [25 times] (3464.5ms)
Rendered posts/_post.html.erb (2329.4ms)
Rendered posts/index.js.erb (10273.4ms)
Completed 500 Internal Server Error in 109620ms (ActiveRecord: 24197.5ms)
ActionView::Template::Error (undefined method `user_profile' for nil:NilClass):
1: <div class="post-container" id="post_<%= post.id %>" data-id="<%= post.hash_id %>">
2: <div class="media" style="padding-bottom: 2em;">
3: <%= user_avatar_post(post.user) %>
4: <div class="media-body post-user-name">
5: <h5><i class="fas fa-user"></i> <%= link_to full_name(post.user), user_path(post.user) %></h5>
6: <p><%= linkify_hashtags(post.body_text) %> </p>
app/helpers/posts_helper.rb:3:in `user_avatar_post'
app/views/posts/_post.html.erb:3:in `_app_views_posts__post_html_erb__891594994_136890360'
app/views/posts/index.js.erb:6:in `_app_views_posts_index_js_erb__704681650_227473700'
Processing by ExceptionHandler::ExceptionsController#show as JS
Parameters: {"id"=>"41", "_"=>"1541262709872", "on"=>:collection}
Error during failsafe response: Could not render layout: undefined method `[]' for nil:NilClass
C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionview-5.2.0/lib/action_view/layouts.rb:418:in `rescue in _default_layout'
C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionview-5.2.0/lib/action_view/layouts.rb:415:in `_default_layout'
C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionview-5.2.0/lib/action_view/layouts.rb:392:in `block in _layout_for_option'
C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionview-5.2.0/lib/action_view/renderer/template_renderer.rb:96:in `resolve_layout'
_post.html.erb partial is not rendering with user and bypassing helper methods in posts_helper.rb
posts_helper.rb
module PostsHelper
def user_avatar_post(current_user)
if current_user.user_profile.avatar.feed_thumb.url.nil?
inline_svg 'user_dashboard/add-user-avatar.svg', size: '12% * 12%', class: 'd-flex align-self-start mr-3 purple-rounded rounded'
else
image_tag current_user.user_profile.avatar.feed_thumb.url, class: 'd-flex align-self-start mr-3 img-thumbnail rounded'
end
end
def full_name(user)
user.first_name + ' ' + user.last_name
end
end
Updated Post Controller
def load_more
if params[:last_post_id]
following_ids = current_user.following_users.pluck(:id)
following_ids << current_user.id
#posts = Post.where(user_id: params[:following_ids]).where('id < ?', params[:last_post_id]).order('created_at DESC').limit(20)
else
head :no_content
end
respond_to do |format|
format.html
format.js
end
end
rotute.erb
get "/load_more/:last_post_id", to: "posts#load_more", as: 'load_more'
index.html.erb
<!---LOAD MORE POST BUTTON-->
<div class="float-right" style="z-index: 1000;">
<%= link_to load_more_path(#posts.last.id), class: 'bttn-material-circle bttn-danger bttn-md load-more-posts', :remote => true do %>
<i class="fas fa-sync"></i>
<% end %>
</div>
I'm using friendly_id to hash ids for posts.

On your logs, you can see the load_more request has a really weird extension:
Started GET "/load_more.%23%3CPost::ActiveRecord_Relation:0x0000000016f89718%3E"
Rails think's that's the format and does not know how to render that format.
Your route is defined like this:
get "/load_more", to: "posts#load_more", as: 'load_more'
but you are using it like this
load_more_path(#posts)
and the route does not expect a parameter and it ends up using it as a format.
You should add something to the route so you know from what post "load more". I'll do something like:
get "/load_more/:last_post_id", to: "posts#load_more", as: 'load_more'
And use it like
load_more_path(#posts.last.id)
And on the controller you'll have access to params[:last_post_id] so you know you need to load more posts after that post id.
following_ids = current_user.following_users.pluck(:id)
following_ids << current_user.id
#posts = Post.where(user_id: params[:following_ids]).where('id < ?', params[:last_post_id]).order('created_at DESC').limit(20)

Related

Active Storage failing to upload image attachment with AJAX Rails 5.2

I'm receiving Module::DelagationError (size delegated to attachment, but attachment is nil): for the create method in my posts_controller.rb when posting an AJAX based form with Active Storage. How can I fix my code to allow Active Storage to create the post with the image in an AJAX created container?
post.rb
has_one_attached :photo
posts_controller.rb
def create
#post = current_user.posts.build(post_params)
respond_to do |format|
if #post.save
format.js
format.html {redirect_to post_path}
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:body_text, :photo, :user_id, :post_id)
end
post/_form.html.erb
<%= simple_form_for(#post, html: {multipart: true}, remote: true, authenticity_token: true) do |f| %>
<%= f.error_notification %>
<div class="row">
<div class="col">
<div class="-textarea">
<%= f.input :body_text, as: :text, class: 'form-control post-placeholder post-txt-area', label: false, placeholder: 'Write a post', style: "overflow: hidden; resize: none;", input_html: {:maxlength => 100, data: {:'meteor-emoji' => 'true'}} %>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-5">
<%= f.button :submit, 'Post', class: 'form-control submit-button bttn-gradient bttn-md bttn-royal', :data => {:disable_with => 'Posting .'} %>
</div>
<div class="col-md-5">
<label class="bttn-minimal bttn-md bttn-red">
Add Photo
<span style="display:none;">
<%= f.input :photo, as: :file, label: false, input_html: {accept: 'image/*'} %>
</span>
</label>
<% if f.object.photo.attached? %>
<%= image_tag(url_for(f.object.photo), class: 'img-responsive img-thumbnail') %>
<% end %>
<div class="preview-container">
<img id="img_prev" width="100" height="100" src="#" alt="preview" class="img-thumbnail d-none"/> <br/>
<a href="#" id="cancel_img_btn" class="d-none" onclick="return !(document.getElementById('post_photo').innerHTML=document.getElementById('post_photo').innerHTML);">Cancel
Upload</a>
</div>
</div>
</div>
<% end %>
Server Development Log
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"yiPHWZDBoFZOxLyNh8AphWOX5regegegeRXVGtz7mFeMdA/ZKAiiaCYjpJ/UOQ0n820gK0m5ZoKpFd483QFt+bnFDgGrLA==", "post"=>{"body_text"=>"oook!"}, "commit"=>"Post"}
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1
ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(1.0ms) BEGIN
(0.0ms) ROLLBACK
Completed 500 Internal Server Error in 9ms (ActiveRecord: 3.0ms)
Module::DelegationError (size delegated to attachment, but attachment is nil):
You cannot send files using Ajax.
This is now all browsers work.
But you can used gem "remotipart" which can do a hack and behavior will be similar.

Rails 5 - Reinitializing Javascript after Ajax refresh?

So I have gotten a better understanding of the issue I have involving Javascript. The problem lies within the fact that after the AJAX call to refresh the contents of a div, the contents within that div are unlinked or uninitialized for the Javascript. What I am trying to do is make my list of activities sortable for the user. I use a priority field to save the order of the activities so when the user refreshes or leaves the page, then the order is maintained.
The problem I am receiving is the following:
ActiveRecord::RecordNotFound (Couldn't find Activity with 'id'=item):
and as a result, the activity order will not be saved. This happens after the AJAX call and refresh and it works normally beforehand, saving the order and whatnot. I have tried some solutions, such as one and moving the Javascript over into the partial to no success.
I believe the error above is the result of the activity not linking correctly with the Javascript file which leads it to an id of "item" so does anyone know how to fix this issue or any advice on how to fix it? Thanks!
Main View:
<!-- home.html.erb -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
</head>
<!-- the jScrollPane script -->
<!--IF THE USER IS LOGGED IN, DISPLAY THE FOLLOWING -->
<% if current_user %>
<!--
<style>
.navbar {
background-color:#2F4F4F
}
</style>
-->
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href='home'>TimeTracker</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li>Signed in as <%=current_user.email %></li>
<li>
<%= link_to 'Sign Out', sign_out_path, method: :delete %>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css">
<h1 align = "center">Activities</h1>
<div id = 'activity_container'>
<ul id="Categories" class="connectedSortable">
<% #categories.each do |cats| %>
<% if cats.user_id == current_user.id%>
<div class="panel-group">
<div class="panel text-left">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#collapse<%= cats.id%>">
<%= cats.c_name %>
</a>
</h4>
</div>
<div id="collapse<%= cats.id%>" class="panel-collapse collapse">
<ul id="category_activities" class=".connectedSortable">
<% cats.activities.each do |activity| %>
<li class="list-group-item" >
<% if activity.hidden == false || activity.hidden == nil%>
<label class="my_label"><%= activity.a_name %></label>
<!-- Delete Activity -->
<%= link_to destroy_act_path(activity.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<i class="fa fa-trash-o" aria-hidden="true" title="Delete"></i>
<% end %>
<!-- Edit activity -->
<%= link_to edit_act_path(activity.id)do %>
<!--<button class="editActivity" style="border:none; padding:0; background-color: transparent">-->
<i class="fa fa-pencil fa-fw" aria-hidden="true" title="Edit" id="editActivity"></i>
<!--</button>-->
<% end %>
<!-- Hide activity -->
<%= link_to hide_act_path(activity.id), method: :post do %>
<i class="fa fa-eye" aria-hidden="true" title="Hide" id="item"></i>
<% end %>
<% end %>
<% end %>
</li>
</ul>
</div>
</div>
</div>
<% end %>
<% end %>
</ul>
<ul id="Activities" class="connectedSortable" >
<!-- List each activity in database -->
<% #activities.each do |activity| %>
<% if (activity.hidden == false || activity.hidden == nil) && activity.category_id == nil %>
<li class="list-group-item" id='<%=activity.id%>' style="list-style: none;">
<!-- Display activity name -->
<label class="my_label"><%= activity.a_name %></label>
<!-- Delete Activity -->
<%= link_to destroy_act_path(activity.id), method: :delete, data: { confirm: "Are you sure?" }, remote: true do %>
<i class="fa fa-trash-o" aria-hidden="true" title="Delete"></i>
<% end %>
<!-- Edit activity -->
<%= link_to edit_act_path(activity.id)do %>
<button class="editActivity" style="border:none; padding:0; background-color: transparent">
<i class="fa fa-pencil fa-fw" aria-hidden="true" title="Edit" id="editActivity"></i>
</button>
<% end %>
<!-- Hide activity -->
<%= link_to hide_act_path(activity.id), method: :post do %>
<i class="fa fa-eye" aria-hidden="true" title="Hide" id="item"></i>
<% end %>
</li> <!-- End of list item -->
<% end %> <!-- End of if statement -->
<% end %> <!-- End of activity loop -->
</ul>
</div>
<ul class="pager">
<li class="previous"><span aria-hidden="true">←</span>Previous </li>
<li class="next"> Next<span aria-hidden="true">→</span></li>
<!-- *****************NEW*********************** -->
<%= form_for #activity, :url => create_act_path, remote: true, data: {type: 'script'} do |a| %>
<%= a.text_field :a_name, id: 'a_name_field', placeholder: 'Activity Name'%>
<%= a.select :category_id, Category.all.collect { |c| [c.c_name, c.id] }, include_blank: "--No Category--" %>
<%= a.submit 'Create', id: 'submitButton', class: 'btn btn-primary'%>
<% end %>
<%= form_for #category, :url => create_cat_path, remote: true do |c| %>
<%= c.text_field :c_name, id: 'c_name_field', placeholder: 'Category Name'%>
<%= c.submit 'Create', id: 'submitButton', class: 'btn btn-primary'%>
<% end %>
<!-- Button for showing all hidden items -->
<%= link_to unhide_act_path, method: :post do %>
<button class="showHidden" >Show Hidden</button>
<% end %>
<!-- Button to sort -->
<button class="sortActivity">Sort</button>
<button class="doneSorting">Done Sorting</button>
<!-- ***************************************** -->
</ul>
<!-- IF THE USER IS NOT LOGGED IN, DISPLAY THE FOLLOWING -->
<% else %>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">TimeTracker</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li class="active">
</li>
</ul>
</div>
</div>
</nav>
<div class="loginContainer" align="center">
<h1 align="center">
<b>
Please log in or sign up
</b>
</h1>
<div class="container">
<br>
<%= button_to 'Login', sign_in_path, :method => 'get', class: 'btn' %>
<br>
<%= button_to 'Sign Up', sign_up_path, :method => 'get', class: 'btn' %>
</div>
<!--<div class="container" style="background-color:#D3D3D3">
<input type="checkbox" checked="checked"> Remember me
<span class="psw">Forgot <a align="center" href="#">password?</a></span>
</div> -->
</div>
<% end %>
<script type="text/javascript">
function changeImg(img) {
if (img.src == "<%=asset_path('_unfilledbubble.png')%>"){
img.src = "<%=asset_path('_filledbubble.png')%>";
}
else {
img.src = "<%=asset_path('_unfilledbubble.png')%>";
}
}
</script>
<script type="text/javascript">
$(document).ready(function() {
$(function () {
$('.scroll-pane').jScrollPane({showArrows: true});
});
});
</script>
<script>
$(document).ready(function(){
function callAll(){
set_positions = function(){
// loop through and give each task a data-pos
// attribute that holds its position in the DOM
$('.list-group-item').each(function(i){
$(this).attr("data-pos",i+1);
});
}
// ready = function(){
// call set_positions function
set_positions();
// ************NEW execept for #Activities
$('#Activities').sortable({
connectWith: ".connectedSortable"
});
$('#Activities').disableSelection();
// $('#Categories').sortable({
// connectWith: ".connectedSortable"
// });
// $('#Categories').disableSelection();
$('#category_activities').sortable({
connectWith: ".connectedSortable"
});
$('#category_activities').disableSelection();
// *******end of NEW
$('#Activities li').on('click','li',function (){
var myid = $(this).attr('id');
alert(myid);
});
// after the order changes
$('#Activities').sortable().bind('sortupdate', function(e, ui) {
// array to store new order
var updated_order = []
// set the updated positions
set_positions();
// populate the updated_order array with the new task positions
$('#Activities li').each(function(i){
updated_order.push({ id: $(this).attr('id'), position: i });
});
// send the updated order via ajax
$.ajax({
type: "PUT",
url: '/home/sort',
data: { order: updated_order }
});
});
}
$(document).ajaxComplete(callAll());
})
</script>
Partial View:
<!-- List each activity in database -->
<% #activities.each do |activity| %>
<% if (activity.hidden == false || activity.hidden == nil) && activity.category_id == nil %>
<li class="list-group-item" id="item" data-id="<%activity.id%>" style="list-style: none;">
<!-- Display activity name -->
<label class="my_label"><%= activity.a_name %></label>
<!-- Delete Activity -->
<%= link_to destroy_act_path(activity.id), method: :delete, data: { confirm: "Are you sure?" }, remote: true do %>
<i class="fa fa-trash-o" aria-hidden="true" title="Delete"></i>
<% end %>
<!-- Edit activity -->
<%= link_to edit_act_path(activity.id)do %>
<button class="editActivity" style="border:none; padding:0; background-color: transparent">
<i class="fa fa-pencil fa-fw" aria-hidden="true" title="Edit" id="editActivity"></i>
</button>
<% end %>
<!-- Hide activity -->
<%= link_to activity, method: :post, :controller => :activities, :action => :set_hidden_true, remote: true do %>
<button class="hideActivity" style="border:none; padding:0; background-color: transparent">
<i class="fa fa-eye" aria-hidden="true" title="Hide" id="item"></i>
</button>
<% end %>
</li> <!-- End of list item -->
<% end %> <!-- End of if statement -->
<% end %> <!-- End of activity loop -->
Create Activity JS File:
<!--create_activity.js.erb-->
$('#Activities').html("<%= j (render 'object') %>");
Home Controller:
class HomeController < ApplicationController
respond_to :html, :js
def new
end
def index
end
def home
#activities = Activity.all
#activity = Activity.new
#categories = Category.all
#category = Category.new
end
def create_activity
#activity = Activity.create(activity_params)
#activity.user_id = current_user.id
#activity.priority = #activity.id
#object = Category.all
#activities = Activity.all
#categories = Category.all
if #activity.save
flash[:success] = 'Activity created successfully'
else
flash[:notice] ='ERROR: Activity could not be create'
end
end
def create_category
#category = Category.new(category_params)
#category.user_id = current_user.id
##category.priority = #category.id
#object = Category.all
#activities = Activity.all
#categories = Category.all
##category.priority = #category.id
if #category.save!
flash[:success] = 'Category created successfully!'
else
flash[:error] = 'ERROR: Category was not saved!'
end
end
def destroy_activity
#activity = Activity.find(params[:id])
#activity.destroy
#object = Category.all
#activities = Activity.all
#categories = Category.all
end
def welcome
end
def hide_activity
#object = Category.all
#activities = Activity.all
#categories = Category.all
#activity = Activity.find(params[:id])
#activity.update_attribute(:hidden, true)
respond_to do |format|
format.html {redirect_to activities_url}
format.js
end
end
#NEW 4/15
def edit_activity
#activity = Activity.find(params[:id])
end
def update_activity
#activity = Activity.find(params[:id])
if #activity.update_attributes(activity_params)
flash[:success] = 'Activity updated successfully!'
else
flash[:notice] = 'Activity was not updated'
end
end
def unhide_all
#object = Category.all
#activities = Activity.all
#categories = Category.all
#activities = Activity.all
#activities.update_all(hidden: false)
# redirect_to root_path
end
def sort
params[:order].each do |key, value|
Activity.find(value[:id]).update_attribute(:priority, value[:position])
end
render :nothing => true
end
private
def activity_params
params.require(:activity).permit(:a_name, :category_id)
end
def category_params
params.require(:category).permit(:c_name)
end
end
UPDATE
I have tried the following and as a test, replaced my script in the html with the following:
$('#Activities').on('click','li',function (){
var myid = $(this).attr('id');
alert(myid);
});
Before the Ajax, when I click on an activity, it correctly gives me its id. However, after doing an Ajax call, then when I try clicking on an activity, I get the same error where it claims it cannot find an activity with "id=item"
You have a lot of options here, one option is to change the bind to the document or the body and not directly to the id of the element because this is created dinamically, for example:
$("body").on('click',"#Activities" ,function () {
var myid = $(this).attr('id');
alert(myid);
});
you can initialize the event on the ajax request again when the element is rendered that is not recommended
or use plugins like https://github.com/adampietrasiak/jquery.initialize that can reinit the plugins if you bind it to a class, id or another selector.
I've created an example where you will be able to create a Person from the index page using an AJAX request. After the Person is created a new list of people is send to the index page. To simulate your JavaScript I set the background-color of every element to blue using jQuery.
Let's start with the index.html.erb itself.
<!-- app/views/people/index.html.erb -->
<p id="notice"><%= notice %></p>
<h1>People</h1>
<table>
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody id="people_tbody">
<%= render 'people', people: #people %>
</tbody>
</table>
<%= render('form', person: #people.new) %>
Next the two partials, _people.html.erb:
<!-- app/views/people/_people.html.erb -->
<% people.each do |person| %>
<tr>
<td><%= person.first_name %></td>
<td><%= person.last_name %></td>
<td><%= link_to 'Show', person %></td>
<td><%= link_to 'Edit', edit_person_path(person) %></td>
<td><%= link_to 'Destroy', person, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
and _form.html.erb from which the AJAX request gets fired:
<!-- app/views/people/_form.html.erb -->
<%= form_for(person, remote: true) do |f| %> <!-- remote true, makes it an AJAX call -->
<% if person.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(person.errors.count, "error") %> prohibited this person from being saved:</h2>
<ul>
<% person.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :first_name %>
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %>
<%= f.text_field :last_name %>
</div>
<div class="actions">
<%= f.submit %> <!-- when submit is clicked the AJAX request is fired to PeopleController#create -->
</div>
<% end %>
To simulate your JavaScript problem I have the following file:
// app/assets/javascripts/people.js
function init_people() {
$('#people_tbody tr').css('background-color', 'lightblue')
}
$(document).ready(init_people)
This gives all rows a light blue background.
As you can see I'm using AJAX to send the filled in form because the remote: true is set. If the form is submitted the request will arrive in PeopleController#create, which looks like this:
# app/controllers/people_controller.rb
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
# GET /people
# GET /people.json
def index
#people = Person.all
end
# GET /people/1
# GET /people/1.json
def show
end
# GET /people/new
def new
#person = Person.new
end
# GET /people/1/edit
def edit
end
# POST /people
# POST /people.json
def create # AJAX request arrives here
#person = Person.new(person_params)
respond_to do |format|
if #person.save
format.html { redirect_to #person, notice: 'Person was successfully created.' }
format.json { render :show, status: :created, location: #person }
# I added the underlying line to handle the AJAX response.
format.js { render :index, status: :created, location: #person }
else
format.html { render :new }
format.json { render json: #person.errors, status: :unprocessable_entity }
# I added the underlying line to handle the AJAX response.
format.js { render nothing: true }
end
end
end
# PATCH/PUT /people/1
# PATCH/PUT /people/1.json
def update
respond_to do |format|
if #person.update(person_params)
format.html { redirect_to #person, notice: 'Person was successfully updated.' }
format.json { render :show, status: :ok, location: #person }
else
format.html { render :edit }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# DELETE /people/1
# DELETE /people/1.json
def destroy
#person.destroy
respond_to do |format|
format.html { redirect_to people_url, notice: 'Person was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_person
#person = Person.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def person_params
params.require(:person).permit(:first_name, :last_name)
end
end
As you can see I added two lines to handle the js format in PeopleController#create. If the render comes from format.js { ... } rails knows to pick the index.js.erb file, and not the index.html.erb file. If you don't want this behavior you can specify the specific file.
My index.js.erb looks like this:
// app/views/people/index.js.erb
$('#people_tbody').html("<%= j(render('people', people: Person.all)) %>")
This replaces the contents of the #people_tbody with the new set op people (similar to your example). But now I've the same problem as you. The JavaScript isn't triggered anymore, and the background of every row is just white. To trigger the JavaScript over the new loaded content I just need to call the init function. This means any logic you want to apply after the document is ready and after an AJAX request should be extracted to a separate function. I placed my logic in the function init_people().
This means the index.js.erb should look like this:
// app/views/people/index.js.erb
$('#people_tbody').html("<%= j(render('people', people: Person.all)) %>")
init_people()
Now, after the AJAX content is loaded, the init_people() function is triggered setting up the JavaScript for the new loaded content.

Rails 4: update model attribute with AJAX call

This is a follow-up question on Rails 4: custom action to update only one param with AJAX and Rails 4: select DOM element with dynamically generated id.
I can't figure out how to make things work from the good answers I got, so I would like to start again from a blank slate.
In my Rails 4 app, I have a Calendar and a Post models, set up with shallow routes:
resources :calendars do
resources :posts, shallow: true
end
A calendar has_many post and a post belong_to a calendar.
In the calendar show.html.erb view, I display all the posts that belong to a calendar.
From this calendar show.html.erb view, I need to update the :approval param of a post, with an AJAX call, so that only the DOM element related to the :approval of this particular post is refreshed, not the entire page.
This is the part of the code in calendar show.html.erb that allows me to update the :approval of a post:
<tr id="post_row_<%= post.id%>">
[...] # Truncated for brivety
<td class="cell_content_center post_approval_section">
<% if post.approval == "ok" %>
<span class="ok_green">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "ok", approval_update: true), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-ok" data-toggle="tooltip" data-placement="left" title="Approve Post"></span>
<% end %>
</span><br/>
<% if post.approval == "edit" %>
<span class="edit_yellow">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "edit", approval_update: true), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-repeat" data-toggle="tooltip" data-placement="left" title="Require Edits"></span>
<% end %>
</span><br/>
<% if post.approval == "remove" %>
<span class="remove_red">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "remove", approval_update: true), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-remove" data-toggle="tooltip" data-placement="left" title="To Be Deleted"></span>
<% end %>
</span>
</td>
[...] # Truncated for brivety
</tr>
Then, in posts_controller.rb:
def update
if params["approval_update"]
respond_to do |format|
if #post.update(post_params)
format.js { render :action => "update_post_approval" }
else
format.html { redirect_to :back }
end
end
else
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to post_path(#post) }
format.json { render :show, status: :ok, location: #post }
format.js
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
end
def update_post_approval
respond_to do |format|
format.js
end
end
Note: here, I cannot use the default Posts#Update action, since it is already used by another AJAX call to update the :approval param from the post show.html.erb view, which the reason why we render the update_post_approval custom action.
Then, I have the following app/views/posts/update_post_approval.js.erb file:
$("tr#post_row_#{post.id} > td.post_approval_section").html('<%= j render(partial: "calendars/post_approval") %>');
Finally, I have the following calendars/_post_approval.html.erb partial:
<td class="cell_content_center post_approval_section">
<% if post.approval == "ok" %>
<span class="ok_green">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "ok", approval_update: true), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-ok" data-toggle="tooltip" data-placement="left" title="Approve Post"></span>
<% end %>
</span><br/>
<% if post.approval == "edit" %>
<span class="edit_yellow">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "edit", approval_update: true), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-repeat" data-toggle="tooltip" data-placement="left" title="Require Edits"></span>
<% end %>
</span><br/>
<% if post.approval == "remove" %>
<span class="remove_red">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "remove", approval_update: true), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-remove" data-toggle="tooltip" data-placement="left" title="To Be Deleted"></span>
<% end %>
</span>
</td>
When I click one of the three links in the <td class="cell_content_center post_approval_section"> section to update a post :approval param, the param is actually updated, as we can see in the server logs:
Started PATCH "/posts/38?approval_update=true&post%5Bapproval%5D=ok" for ::1 at 2015-11-20 08:03:50 -0800
Processing by PostsController#update as JS
Parameters: {"approval_update"=>"true", "post"=>{"approval"=>"ok"}, "id"=>"38"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
Post Load (0.7ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = $1 LIMIT 1 [["id", 38]]
(0.6ms) BEGIN
SQL (1.1ms) UPDATE "posts" SET "approval" = $1, "updated_at" = $2 WHERE "posts"."id" = $3 [["approval", "ok"], ["updated_at", "2015-11-20 16:03:50.888587"], ["id", 38]]
SQL (1.3ms) INSERT INTO "versions" ("event", "object", "whodunnit", "created_at", "object_changes", "item_id", "item_type") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["event", "update"], ["object", "---\nid: 38\ncalendar_id: 6\ndate: 2015-11-17 22:09:00.000000000 Z\nsubject: Subject\nformat: Link\ncopy: https://www.wid.la/\ncreated_at: 2015-11-17 22:09:28.713416000 Z\nupdated_at: 2015-11-20 16:03:20.613597000 Z\nimage_file_name: \nimage_content_type: \nimage_file_size: \nimage_updated_at: \nshort_copy: ''\nscore: \nfacebook: true\ntwitter: false\ninstagram: false\npinterest: false\ngoogle: false\nlinkedin: false\ntumblr: \nsnapchat: \napproval: remove\n"], ["whodunnit", "1"], ["created_at", "2015-11-20 16:03:50.888587"], ["object_changes", "---\napproval:\n- remove\n- ok\nupdated_at:\n- 2015-11-20 16:03:20.613597000 Z\n- 2015-11-20 16:03:50.888587000 Z\n"], ["item_id", 38], ["item_type", "Post"]]
(1.6ms) COMMIT
Rendered calendars/_post_approval.html.erb (0.1ms)
Rendered posts/update_post_approval.js.erb (1.5ms)
Completed 200 OK in 27ms (Views: 9.9ms | ActiveRecord: 6.3ms)
However, unless I manually refresh the page, nothing changes on the view.
I have now spent hours on this issue and can't figure out whether the issue is caused by the Ruby or the JS code.
If necessary, I am happy to share more code.
Any idea of what I am doing wrong here?
The mistake is here:
$("tr#post_row_#{post.id} > td.post_approval_section").html('<%= j render(partial: "calendars/post_approval") %>');
Updated
It should be:
$("tr#post_row_<%= #post.id %> > td.post_approval_section").html('<%= j render(partial: "calendars/post_approval", locals: {post: #post}) %>');

Rails 4: 500 (Internal Server Error) when loading partial with AJAX

In my Rails 4 app, I have a Calendar and a Post models, using shallow routes:
resources :calendars do
resources :posts, shallow: true
end
A calendar has_many post and a post belong_to a calendar.
On Calendars#Index, I display all the posts of a calendar.
I am trying to update the custom approval attribute of a post from this very same view, using an AJAX call, so the page is not reloaded but the new value of the attribute is displayed.
In the calendar index.html.erb file, I have:
<% #posts.each do |post| %>
<tr id="post_row_<%= post.id%>">
... # Truncated for brivety
<td class="cell_content_center post_approval_section">
<% if post.approval == "ok" %>
<span class="ok_green">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "ok"), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-ok" data-toggle="tooltip" data-placement="left" title="Approve Post"></span>
<% end %>
</span><br/>
<% if post.approval == "edit" %>
<span class="edit_yellow">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "edit"), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-repeat" data-toggle="tooltip" data-placement="left" title="Require Edits"></span>
<% end %>
</span><br/>
<% if post.approval == "remove" %>
<span class="remove_red">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "remove"), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-remove" data-toggle="tooltip" data-placement="left" title="To Be Deleted"></span>
<% end %>
</span>
</td>
</tr>
<% end %>
This is my PostsController:
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to post_path(#post) }
format.json { render :show, status: :ok, location: #post }
format.js
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
Then, in the update.js.erb file in the app/views/posts folder, I added:
$('#post_row_<%= j post.id %>').select.('.post_approval_section').html('<%= j render(partial: "calendar_show_approval") %>');
—————
UPDATE: I have also tried with:
$('#post_row_<%= j post.id %> > .post_approval_section').html('<%= j render(partial: "calendar_show_approval") %>');
But I get the same result in the browser and the error in the console.
—————
Finally, I have created a _calendar_show_approval.html.erb partial in the same app/views/posts folder:
<% if post.approval == "ok" %>
<span class="ok_green">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "ok"), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-ok" data-toggle="tooltip" data-placement="left" title="Approve Post"></span>
<% end %>
</span><br/>
<% if post.approval == "edit" %>
<span class="edit_yellow">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "edit"), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-repeat" data-toggle="tooltip" data-placement="left" title="Require Edits"></span>
<% end %>
</span><br/>
<% if post.approval == "remove" %>
<span class="remove_red">
<% else %>
<span class="approval_blue" %>
<% end %>
<%= link_to post_path(:id => post.id, "post[approval]" => "remove"), remote: true, :method => :patch do %>
<span class="glyphicon glyphicon-remove" data-toggle="tooltip" data-placement="left" title="To Be Deleted"></span>
<% end %>
</span>
When I click on one of my three links supposed to update the post approval attribute, nothing happens in the browser and I get the following error message in the console:
PATCH http://localhost:3000/posts/38?post%5Bapproval%5D=remove 500 (Internal Server Error)
send # jquery.self-a714331225dda820228db323939889f149aec0127aeb06255646b616ba1ca419.js?body=1:9665
jQuery.extend.ajax # jquery.self-a714331225dda820228db323939889f149aec0127aeb06255646b616ba1ca419.js?body=1:9216
$.rails.rails.ajax # jquery_ujs.self-d456baa54c1fa6be2ec3711f0a72ddf7a5b2f34a6b4f515f33767d6207b7d4b3.js?body=1:94
$.rails.rails.handleRemote # jquery_ujs.self-d456baa54c1fa6be2ec3711f0a72ddf7a5b2f34a6b4f515f33767d6207b7d4b3.js?body=1:177
(anonymous function) # jquery_ujs.self-d456baa54c1fa6be2ec3711f0a72ddf7a5b2f34a6b4f515f33767d6207b7d4b3.js?body=1:406
jQuery.event.dispatch # jquery.self-a714331225dda820228db323939889f149aec0127aeb06255646b616ba1ca419.js?body=1:4671
elemData.handle # jquery.self-a714331225dda820228db323939889f149aec0127aeb06255646b616ba1ca419.js?body=1:4339
—————
UPDATE 2: here is the content of my log/development.log file:
Started PATCH "/posts/37?post%5Bapproval%5D=ok" for ::1 at 2015-11-19 08:08:12 -0800
Processing by PostsController#update as JS
Parameters: {"post"=>{"approval"=>"ok"}, "id"=>"37"}
[1m[36mUser Load (1.2ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1[0m [["id", 1]]
[1m[35mPost Load (1.5ms)[0m SELECT "posts".* FROM "posts" WHERE "posts"."id" = $1 LIMIT 1 [["id", 37]]
[1m[36m (1.1ms)[0m [1mBEGIN[0m
[1m[35mSQL (3.3ms)[0m UPDATE "posts" SET "approval" = $1, "updated_at" = $2 WHERE "posts"."id" = $3 [["approval", "ok"], ["updated_at", "2015-11-19 16:08:12.522940"], ["id", 37]]
[1m[36mSQL (7.4ms)[0m [1mINSERT INTO "versions" ("event", "object", "whodunnit", "created_at", "object_changes", "item_id", "item_type") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"[0m [["event", "update"], ["object", "---\nid: 37\ncalendar_id: 6\ndate: 2015-11-18 04:25:00.000000000 Z\nsubject: Subjects\nformat: Link\ncopy: Copy 2\ncreated_at: 2015-11-16 04:25:59.404072000 Z\nupdated_at: 2015-11-19 00:39:30.866318000 Z\nimage_file_name: Capture_d’écran_2015-08-25_à_19.38.59.png\nimage_content_type: image/png\nimage_file_size: 1212743\nimage_updated_at: 2015-11-16 05:35:46.273534000 Z\nshort_copy: Short Copy 2\nscore: \nfacebook: true\ntwitter: true\ninstagram: false\npinterest: false\ngoogle: false\nlinkedin: false\ntumblr: \nsnapchat: \napproval: edit\n"], ["whodunnit", "1"], ["created_at", "2015-11-19 16:08:12.522940"], ["object_changes", "---\napproval:\n- edit\n- ok\nupdated_at:\n- 2015-11-19 00:39:30.866318000 Z\n- 2015-11-19 16:08:12.522940000 Z\n"], ["item_id", 37], ["item_type", "Post"]]
[1m[35m (12.0ms)[0m COMMIT
Rendered posts/_approval.html.erb (0.7ms)
Rendered posts/update.js.erb (2.5ms)
Completed 200 OK in 58ms (Views: 13.2ms | ActiveRecord: 26.5ms)
—————
What am I doing wrong?

Rails: AJAX not working with form Create Action

This is a simple grocery list app. Left column div is a list of lists. Items for a particular list are displayed in the right column div.
Here's the process:
A user clicks on one of the lists, which then loads (AJAX) it's related items in the right div. This is working fine.
Here's where I'm stuck:
Above the items is an input field to submit a new item to the list of items below. I want AJAX to add the new item to the items below but when I press enter on the form field, nothing happens. When I refresh, the new item is added.
Here's what the server said:
Processing by ItemsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"YWIlMPXqoTvhqzGGPqm6Rn/E7jPRt8do/2tkjd0H1Qk=", "item"=>{"name"=>"Mayo"}, "list_id"=>"4"}
List Load (0.1ms) SELECT "lists".* FROM "lists" WHERE "lists"."id" = ? LIMIT 1 [["id", "4"]]
(0.0ms) begin transaction
SQL (20.9ms) INSERT INTO "items" ("completed", "created_at", "description", "list_id", "name", "position", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["completed", false], ["created_at", Mon, 29 Apr 2013 21:59:06 UTC +00:00], ["description", nil], ["list_id", 4], ["name", "Mayo"], ["position", nil], ["updated_at", Mon, 29 Apr 2013 21:59:06 UTC +00:00]]
(1.6ms) commit transaction
Rendered items/_piece.html.erb (0.0ms)
Rendered items/create.js.erb (0.7ms)
Here's the page loading process:
home.html.erb > _single.html.erb > create.js.erb > adds _piece.html.erb to home.html.erb
This is the Create Action from my items_controller.rb file:
def create
#list = List.find(params[:list_id])
#item = #list.items.create!(params[:item])
respond_to do |format|
format.html
format.js
end
end
This is my create.js file:
$('#item-container').prepend('<%= j render(partial: 'piece', locals: {item: #item}) %>');
This is my _piece.html.erb file:
<li><%= item.name %></l1>
This is my _single.html.erb file:
<div id="filter">
<div id="filter-left">
</div>
<div id="filter-right">
<%= link_to 'Delete', #list, :method => :delete %>
</div>
</div>
<div id="quick-add">
<%= form_for [#list, #item], :id => "form-quick", remote: true do |form| %>
<%= form.text_field :name, :id => "input-quick", :autocomplete => "off" %>
<% end %>
</div>
<ul class="item-container">
<% #list.items.incomplete.each do |item| %>
<% if item.id %>
<li><%= link_to "", complete_item_path(#list.id,item.id), :class => "button-item button-item-incomplete" %> <%= item.name %></li>
<% end %>
<% end %>
</ul>
<div class="title">Completed items</div>
<ul class="item-container">
<% #list.items.completed.each do |item| %>
<% if item.id %>
<li><div class="button-item button-item-completed"></div><%= item.name %></li>
<% end %>
<% end %>
</ul>
This is my home.html.erb file:
<div id="main-left">
<div id="main-left-1">
<%= link_to 'Add List', new_list_path, class: "button", id: "new_link", remote: true %>
</div>
<ul id="lists" data-update-url="<%= sort_lists_url %>">
<% #lists.each do |list| %>
<%= content_tag_for :li, list do %>
<%= link_to list.name, list, :remote => true, :class => "link" %>
<% end %>
<% end %>
</ul>
</div>
<div id="main-right">
</div>
Well, I had "item-container" as an ID instead of a class in the JS.ERB file. SILLY ERRORS!

Categories

Resources