Using the respond_to method to render a js.erb partial - ruby-on-rails

I have a feature where users like/unlike and dislike/undislike dishes. This is how I initially have my actions setup:
Dishes Controller
class DishesController < ApplicationController
def like
#dish.liked_by current_user
end
def dislike
#dish.disliked_by current_user
end
...
end
Considering the js.erb templates for each template are completely identical I wanted to create just one shared partial that each could use:
Original Setup
# like.js.erb, unlike.js.erb,dislike.js.erb,undislike.js.erb
$(".restaurant__dish-vote--<%= #dish.modifier_class %>").html('<%= escape_javascript(render "restaurants/menu_partials/dish_votes", dish: #dish) %>');
New Setup
# shared/_vote.js.erb
$(".restaurant__dish-vote--<%= #dish.modifier_class %>").html('<%= escape_javascript(render "restaurants/menu_partials/dish_votes", dish: #dish) %>');
Now I'm trying to refactor my controller to reflect these changes but the ajax functionality doesn't seem to work with the following:
class DishesController < ApplicationController
def like
respond_to do |format|
format.js { render partial: "dishes/shared/vote.js.erb" }
end
#dish.liked_by current_user
end
end
The action completes but the changes on the user-facing side are only reflected upon refresh. What am I doing wrong?

I think you should call #dish.liked_by current_user before render partial: "dishes/shared/vote.js.erb". The problem is that #dish is not updated yet.

Related

Tree comments Ruby on Rails

Trying to implement a tree-like comments on the site via a gem - acts-as-commentable-with-threading.
Comments are excellent and are displayed on the site when I visit a site under the user (implemented via the gem devise).
But when trying to view pages anonymously, naturally, I receive an error that id is not may be due to the elements onto a blank.
This is my controller recipes_controller.rb:
class RecipesController < ApplicationController
before_action :authenticate_chef!, except: [:index, :show]
def show
#recipe = Recipe.find(params[:id])
#comments = #recipe.comment_threads.order('created_at desc')
#user_who_commented = current_chef
#new_comment = Comment.build_from(#recipe, #user_who_commented.id, "")
end
...
comments_controller.rb:
class CommentsController < ApplicationController
before_action :authenticate_chef!
def create
commentable = commentable_type.constantize.find(commentable_id)
#user_who_commented = current_chef
#comment = Comment.build_from(commentable, #user_who_commented.id, body)
respond_to do |format|
if #comment.save
make_child_comment
format.html { redirect_to(:back, :notice => 'Comment was successfully added.') }
else
format.html { render :action => "new" }
end
end
end
...
recipe.rb:
class Recipe < ActiveRecord::Base
acts_as_commentable
...
In views (recipes/show.html.erb) I put this render :
<%= render partial: "comments/template", locals: {commentable: #recipe, new_comment: #comment} %>
I think that you may need in the controller to create something like a design if ... else for those who just browse the site, because the default at this point in the show method is set current_chef, because of what and error.
You need to handle the special case in view(probably comment template) for anonymous visit. Cause then current_chef would be nil. So where you're using it in view and controller, handle that properly.
A tip: You don't need to assign current_chef to any instance variable actually. It's already a helper method. You can call it directly from view.

Putting a respond_to method inside a before_action callback

I guess you can consider this a continuation from my previous question. Basically I'm rendering a js.erb partial which enables ajax functionality to like/dislike a restaurant dish. I have four actions that render this partial:
class DishesController < ApplicationController
def like
#dish.liked_by current_user
respond_to do |format|
format.js { render partial: "dishes/shared/vote.js.erb" }
end
end
def unlike
#dish.unliked_by current_user
respond_to do |format|
format.js { render partial: "dishes/shared/vote.js.erb" }
end
end
...
end
To DRY this up I planned to put the respond_to method inside of a before_action callback:
class DishesController < ApplicationController
before_action :render_vote_partial
...
private
...
def render_vote_partial
respond_to do |format|
format.js { render partial: "dishes/shared/vote.js.erb" }
end
end
end
Unfortunately this doesn't render the partial at all. What am I doing wrong?
If you want to dry up the respond_to, just stick it in a method (like you have already) and call that method after each action.
Instead of
before_action :render_vote_partial
just do do:
def like
# do your work here ...
render_vote_partial
end
def unlike
# do your work here ...
render_vote_partial
end

routing in rails - displaying the contents of one controller in a different view

I am trying to figure out how to routes the contents of one controller into that of another.
Currently, I have two controllers -
1. Static Pages controller - this is very simple, all it used for is to yield one page (with tabbable pages)
class StaticPagesController < ApplicationController
def home
end
end
2.Guides controller - This is where a user may (currently) add guides to the db.
class GuidesController < ApplicationController
def home
end
def show
#guide = Guide.find(params[:id])
end
def index
#guide = Guide.all
end
def new
#guide = Guide.new
end
def create
#guide = Guide.new(guide_params)
if #guide.save
redirect_to '/guides'
else
render 'new'
end
end
private
def guide_params
params.require(:guide).permit(:title, :description, :image, :date, :date_end, :extra_info)
end
end
I want to display the INDEX part of the controller (which currently works at '/guides', in my root directory, or 'home' in the static pages controller.
I've tried fiddling with all of this, and my last port of call is the routes.rb file. However I am not all together sure, this seems straight forward enough and its cheesing me off not being able to do it.
One of the possible solutions is that you use:
class StaticPagesController < ApplicationController
def home
#guide = Guide.all
end
end
and copy the code from index,html.erb of your guide to home.html.erb of static pages.
other than that you can use rendering: link
EDIT:
use partial to show index of guides:
class GuidesController < ApplicationController
def index
#guide = Guide.all
render partial: "index"
end
end
in your views of guide rename "index.html.erb" to "_index.html.erb" and
in static_pages/home.html.erb add:
<%= render :partial => "guides/index" %>

DRYing up respond_to code in Rails

I have several actions (lets call them action_a, action_b, etc.)
In each action I want to check if the user is logged in and if not to have a respond_to block as follows
format.js {
if current_user.nil?
render partial: 'some_partial', handler: [:erb], formats: [:js]
end
}
For one action this is fine, but not for many actions, as there will be many duplications of this code which will do exactly the same thing, it is not very pretty or maintainable
Is there a way to put this somewhere so I can reuse this code and not rewrite it in every needed action?
Use before_filter (rails <4.0) or before_action (rails 4.0)
class YourController < ApplicationController
before_filter :check_user
...
your actions
...
private
def check_user
redirect_to sign_in_path if current_user.nil?
end
end
or if you want specific actions and respond use around_action (filter):
class YourController < ApplicationController
around_action :check_user
...
your actions
def show
#variable = Variable.last
end
...
private
def check_user
yield #(you normal action without js respond)
format.js {
if current_user.nil?
render partial: 'some_partial', handler: [:erb], formats: [:js]
end
}
end
end
Read up on Responders. These are meant to help with that.
Your specific problem is what filters are generally used for. See this Section on Filters in the Action Controller Guide
More generally, this is just ruby code, so you can refactor everything out into methods:
def do_stuff_with(partial_name, format)
if current_user.nil?
render partial: partial_name, handler: [:erb], formats: [format]
end
end
format_js { do_stuff_with('some_partial', :js) }

respond_to is acting weird in my create action

I have the following controller (pretty basic).
class ActivityTypesController < ApplicationController
respond_to :html
def show
#model=ActivityType.find(params[:id])
respond_with #model
end
def new
#folder = Folder.find(params[:folder_id])
#model = #folder.activity_types.build
respond_with #folder, #model
end
def create
#folder = Folder.find(params[:folder_id])
#model = #folder.activity_types.build(params[:activity_type])
if #model.save
flash[:notice] = 'hoorraaaaayyy'
end
respond_with #folder, #model, location: root_path
end
def edit
#folder = Folder.find(params[:folder_id])
#model = ActivityType.find(params[:id])
respond_with #folder, #model
end
def update
#folder = Folder.find(params[:folder_id])
#model = #folder.activity_types.find(params[:id])
if #model.update_attributes(params[:activity_type])
flash[:notice] = 'yeeeeaaaaaaah'
end
respond_with #folder, #model, location: root_path
end
The interesing thing is: the :location option within the #create action is ignored, while in #update, it is honored.
I have no idea, why this is the case. Even stranger: when removing the :location within #create, it seems to stay on the #update action and renders the edit view, instead of redirecting to the #show view.
Has anybody an idea how I could track this problem down?
I found the problem.
We had a view activity_types/create.html.haml which only rendered the _form.html.haml partial (this seems to be a leftover of a previous unclean implementation or workaround of the new/create action combo).
Because respond_with always checks for a corresponding view first, after creation, it rendered the create view which looked the same like the edit action. So if you run into something like this, too, make sure you don't have any views that prevent respond_to from redirecting to any other action.
Any by the way: if you only accept :html requests, then you only need a respond_with call in the create and update action, so it automatically renders the new and edit form when there are errors. If you, however, want to serve for example JSON or XML and have respond_to :xml, then you need a respond_with #my_model in the #show action, too (and any other action that should respond with data to a my_action.xml call).

Resources