I am following Michael Hartl's book to put in some following functionality into my app and when I attempt to use the AJAX on my follow and unfollow buttons I am receiving these errors when trying to change the buttons that are rendered:
Completed 500 Internal Server Error in 81ms
ActionView::MissingTemplate (Missing template users/follow_user, application/follow_user with {:locale=>[:en], :formats=>[:js, :html], :handlers=>[:erb, :builder, :coffee]}. Searched in:
* "/Users/hugo/Web Development/Rails/sample/app/views"
* "/Users/hugo/.rvm/gems/ruby-1.9.2-p318/gems/kaminari-0.13.0/app/views"
* "/Users/hugo/.rvm/gems/ruby-1.9.2-p318/gems/devise-2.0.4/app/views"
):
app/controllers/users_controller.rb:73:in `follow_user'
lib/ct_gems/dm-core-1.2.0/lib/dm-core.rb:263:in `block in repository'
lib/ct_gems/dm-core-1.2.0/lib/dm-core/repository.rb:114:in `scope'
lib/ct_gems/dm-core-1.2.0/lib/dm-core.rb:263:in `repository'
Rendered /Users/hugo/.rvm/gems/ruby-1.9.2-p318/gems/actionpack-3.2.3/lib/action_dispatch/middleware/templates/rescues/missing_template.erb within rescues/layout (0.5ms)
This is the code in my controller:
def follow_user
#other_user = User.get(params[:user_id].to_i)
current_user.follow(#other_user)
respond_to do |format|
format.html {redirect_to user_profile_path(#other_user)}
format.js
end
end
This is my form...well not form but the link to follow function:
<% unless current_user == #user %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'users/unfollow' %>
<% else %>
<%= render 'users/follow' %>
<% end %>
</div>
<% end %>
And this is one of the partials I am trying to render:
<%= link_to "Follow", user_follow_user_path(#user), :class => "btn btn-primary", :style => "margin-bottom:20px;", :remote => true %>
And this is the file to render the right button, I'm using this code my Michael's book:
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
However I am getting the error above that my partial is not found; can anyone explain to me why? Thanks
It's saying it's trying to render a template, which from my experience is a file in the views/ folder without the underscore preceding the name. Add the underscore to the start of the file name and do render :partial => 'users/follow' and see if that helps
Bad reading on my part, the problem was the naming of my javascript file. The name of that has to match your controller action.
Related
I was making a simple variation of the simple example of ajax in rails: http://guides.rubyonrails.org/working_with_javascript_in_rails.html#a-simple-example
I am trying to create a user show view in which new posts are created upon pressing a button. These posts are all listed below the user on the same show page and appear upon creation.
The posts are created fine and shown correctly on the page, however when I refresh the page my
#post = User.posts.build()
Overwrites all the previously created posts giving each of them a nul id.
Also, is it correct to place the create.js.erb in the views folders, or should it go in the assets/javascripts folder?
Here are my files:
UsersController
def show
#user = User.find(params[:id])
#posts = Post.all
#post = #user.posts.build
end
users/show.html.erb
<%= "user-id: #{#user.id}" %>
<ul id="posts">
<%= render :partial => #posts %>
</ul>
<%= form_for(#post, remote: true) do |f| %>
<%= f.hidden_field :user_id, :value => #user.id %>
<%= f.submit %>
<% end %>
PostsController
def create
puts params[:post][:user_id]
#user = User.find(params[:post][:user_id])
puts #user
#post = #user.posts.build()
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.js {}
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
Rails.logger.info(#post.errors.inspect)
end
end
def index
#posts = Post.all
#post = Post.new
end
posts/_post.html.erb
<li><%= #post.id %></li>
posts/create.js.erb
$("<%= escape_javascript(render #post) %>").appendTo("#posts");
The Problem
The reason why your partial is rendering all new posts is because you are using the instance variable #post instead of the local variable post inside your partial.
In your UsersController#show action, you set #post = #user.posts.build. When you render <%= #post.id %> inside the partial, you are referencing that same variable which comes from the controller and was set to a new post.
It seems that all the previously created posts are being "null'ed" out, but it's really just that you are continuously rendering a new post, not the existing ones.
The Solution
You need to update your partial to use a local variable, not the instance variable.
<li><%= post.id %></li>
This local variable is automatically provided to you by Rails when you render a collection of records like this
<%= render #user.posts %>
or alternatively
<%= render partial: "posts/post", collection: #user.posts %>
How to Avoid in the Future
This is a really common mistake and can be easy to miss.
For this reason, my recommendation is to stop using instance variables in partials altogether.
Resources
Rails Guides - Rendering Collections
Stop Using Instance Variables In Partials
Found a workaround by avoiding the use of the _post partial to display the older posts:
edit: users/show.html.erb
<ul id="posts">
<% #posts.each do |post| %>
<li>
<%= post.id %>
</li>
<% end %>
</ul>
I don't think this is an ideal solution but it works fine for now.
Yes, you are correct.
create.js.erb with the suffix erb to help you add code ruby to it.
Write code in this file the same with you write javascript code on view html.erb with syntax
<script>
$("<%= escape_javascript(render #post) %>").appendTo("#posts");
</script>
I've a users list and I want to delete elements on click of a "delete" link on the same line.
Views:
# users/index.html.erb
<ul class="users">
<%= render #users %>
</ul>
# users/_user.html.erb
<li id="user-<%= user.id %>">
<%= link_to user.email, user %>
<% if current_user.admin? %>
<%= link_to "delete", user, remote: true, method: :delete, data: { confirm: "You sure?" } %>
<% end %>
</li>
Users Controller:
# users_controller.rb
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
respond_to do |format|
format.html { redirect_to users_url }
format.js
end
end
The javascript to delete the list element is:
# users/destroy.js.erb
$("li#<%= user.id %>").remove();
On click nothing happen, but on page refresh the resource is correctly destroyed. Checking server's LOG I see the following error:
Completed 500 Internal Server Error in 40ms (ActiveRecord: 5.0ms)
ActionView::Template::Error (undefined local variable or method user'
for #<#<Class:0x0000000851d300>:0x00000008e8e7e0>):
1: $("li#<%= user.id %>").remove(); app/views/users/destroy.js.erb:1:in
_app_views_users_destroy_js_erb___2066095411338793994_74738360'
app/controllers/users_controller.rb:46:in `destroy'
Can you pls help me to understand where the error is and why 'user' is undefined? Thanks
edit
I know there are many q&a similar to this question, and I actually build my code consulting these questions. Still, I'm stuck and I need support. Pls do not mark the question as duplicate.
your destroy.js.erb template is not getting the user variable, as it is undefined. try:
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.js
end
end
and
$("li#<%= #user.id %>").remove();
the reason this works is because rails passes data from controller to view by setting variables with # prefix. so you set #user to an instance of the model you grabbed from the database, then you called .destroy on that model, and it got deleted, and then you rendered your destroy.js template which had #user in it as well, and you deleted the list item matching the 'li#233' selector or whatever the id integer was
You're not defining an user variable.
You would save your #user_id in a variable to be accessible in your js.erb. Like that:
def destroy
#user_id = params[:id]
...
end
And then:
$("li#<%= #user_id %>").remove();
I'm trying to render boxes_list by clicking Link_to. Don't know why its not working.
# Routes.rb
resources :modifications do
collection do
get 'refresh'
end
end
# ModificationsController
def refresh
respond_to do |format|
format.js {}
end
end
# link in /views/modifications/_boxes_list.html.erb that should refresh boxes_list
<%= link_to "refresh", refresh_modifications_path(#modification), remote: true, method: :refresh %>
# JS responce in /views/modifications/refresh.js.erb
$('#boxes_count').html("<%= escape_javascript(render( :partial => 'boxes_list' )).html_safe %>");
In server console I see nothing when press this link. Link is on Modifications show page under regular show action. Rails 4!
You firstly should remove method: :refresh from your link_to (you don't need it):
<%= link_to "refresh", refresh_modifications_path, remote: true %>
You also don't need to provide an object if you're using collection routes. If you used a member route, you'd have to pass the object.
--
To save the hassle of trying to pick through the code, here's what you should have:
#config/routes.rb
resources :modifications do
get :refresh, on: :member #-> url.com/modifications/:id/refresh
end
#app/controllers/modifications_controller.rb
class ModificationsController < ApplicationController
respond_to :js, only: :refresh
def refresh
end
end
#app/views/modifications/refresh.js.erb
$('#boxes_count').html("<%=j render partial: 'boxes_list' %>");
You'd send the request as follows:
<%= link_to "Refresh", refresh_modification_path(#modification), remote: true %>
Why you put the method: :refresh. Remove the method: :refresh from the link. Your route should be
resources :modifications do
member do
get :refresh
end
end
Then your path should be
<%= link_to "refresh", refresh_modification_path(#modification), remote: true %>
And in `refresh' action
def referesh
#modification = Modification.find(params[:id])
respond_to do |format|
format.js{}
end
end
Source Adding More RESTful Actions
Here is my controller action:
*controller/books_controller.rb*
def search_book
#found_book = Book.find_by_token(params[:token_no])
#once found I am rendering my search_book.js.erb file (with UJS)
respond_to do |format|
format.js
end
end
Here is my js file to alter my html contents : views/books/search_book.js.erb
$("#found_book").html("<%= escape_javascript( render(:partial => "book_view") ) %>");
If my book is successfully found then rendering a partial via UJS.(Done)
Let's say if my book is not found i.e. if #found_book.nil? is true.
In that case I want to render another partial for my div "found_book". How to do that ?
Remember that search_book.js.erb is still erb and thus you can evaluate your instance variable and use a conditional to render the partial you choose.
<%- if #found_book.nil? %>
$("#found_book").html("<%= escape_javascript( render(:partial => "no_book_view") ) %>");
<%- else %>
$("#found_book").html("<%= escape_javascript( render(:partial => "book_view") ) %>");
<% end %>
I am trying to destroy a comment through Ajax. In my app, my comment model uses a polymorphic association. The comment deletes successfully (in the database) using the code below. However, when I call the destroy.js.erb, it doesn't do anything and I think the problem is that the dom_id doesn't match the HTML id, so it is not updating. I think I am experiencing the same thing that #mu_is_too_short articulated in the answer to this question. I need help with how to solve this though. I do not know if the solution involves a) somehow passing the local variable comment to the destory.js.erb or b) another solution.
routes.rb
resources :feeds do
resources :comments
end
destroy.js.erb
$('#<%= dom_id(#comment) %>')
.fadeOut ->
$(this).remove()
_comment.html.erb
<div id=<%= dom_id(comment) %> class="comment">
<em>on <%= comment.created_at.strftime('%b %d, %Y at %I:%M %p') %></em>
<%= link_to "Remove", [#commentable, comment], :method => :delete, :remote => true %>
<%= simple_format comment.content %>
</div>
feeds/show.html.erb
<div id="comments">
<%= render #comments %>
</div>
Comments controller
class CommentsController < ApplicationController
def create
#comment = #commentable.comments.new(params[:comment])
if #comment.save
respond_to do |format|
format.html { redirect_to #commentable }
format.js
end
else
render :new
end
end
def destroy
#comment = Comment.find(params[:id])
#commentable = #comment.commentable
if #comment.destroy
respond_to do |format|
format.html { redirect_to #commentable }
format.js
end
end
end
end
Feeds controller
class FeedsController < ApplicationController
def show
#feed = Feed.find(params[:id])
#commentable = #feed
#comments = #commentable.comments
#comment = Comment.new
end
end
By the looks of it, #comment will contain a comment when you get to destroy.js.erb, as you set it in the controller immediately before that, so I do not think it has anything to do with the referenced answer. I wonder if this is being caused by the lack of quotes around your id here: <div id=<%= dom_id(comment) %> class="comment">... I suspect if you correct this, and any other relevant HTML validation errors, it will start working.