Update Ruby on Rails partial with Ajax - ruby-on-rails

I've built a fav icon that works like a Facebook like/unlike button, and I'm trying to update it via Ajax but can't seem to get it working. I think I'm missing something simple.
events_controller.rb
def fav
#event = Event.find(params[:id])
current_user.toggle_flag(#event, :fav) #events_helper.rb
respond_to do |format|
format.js
end
end
events_helper.rb
def toggle_fav(event, user)
if user_signed_in? #change icon from heart to empty heart and vice-versa
link_to user.flagged?(event, :fav) ? #if the event is flagged
content_tag(:span, " ", :class => "glyphicon glyphicon-heart") : #show full heart
content_tag(:span, " ", :class => "glyphicon glyphicon-heart-empty"), #else show empty heart
fav_event_path(event), #path that changes the state of the heart
:remote => true
else
link_to content_tag(:span, " ", :class => "glyphicon glyphicon-heart-empty"), fav_event_path(event) #prompt user to sign in
end
end
Events/index.html.erb
<% #events.each do |event| %>
<%= render 'each_event', :event => event %>
<% end %>
_each_event.html.erb (relevant info only)
<div class="row">
<div class="event-div">
<div class="event-details">
<ul><li class="fav-li"><%= render 'fav_li', :event => event %></li></ul>
</div>
</div>
</div>
_fav_li.html.erb
<%= toggle_fav(event, current_user) %>
fav.js.erb
$('.fav-li').html('<%=j render 'events/fav_li', :event => event, :layout => false %>');
I followed this tutorial to make the like button: http://www.youtube.com/watch?v=GG-kCSx0taU
And am using the make_flaggable gem.
Right now when I update the button it directs me to http://localhost:3000/events/23/fav but that template doesn't exist (and shouldn't). The events are displayed on the event index page after going through the index filters. There are multiple events on a single page.
I'd appreciate any help! Thanks.

Your controller is doing format.js in the respond_to block. It's expecting a js template to exist so it can run it as the response. Something like app/views/events/fav.js.erb. This file will contain some js code that will update your view with the results of your controller action e.g. update the icon from glyphicon-heart-empty to glyphicon-heart.
Here's another question/answer discussing js.erb templates: How does js.erb work
Hope that helps.

Related

Understanding Rails rendering an error from controller

I am still new to Rails and am having trouble understanding how to render certain sections of a page conditionally. I have a button in index.html.erb as well as another partial rendered:
<%= #facade.processing_button %>
<%= render 'snap', app: #facade.app %>
Which is defined as follows:
link_to processing_path(#app.id),
method: :post, action: :processing,
class: 'btn btn-danger' do
concat([
image_tag('blah', class: 'check_icon'),
content_tag(:span, 'Processing')
].join(' ').html_safe)
end
This button calls a controller method:
def processing
if service.upload
# render success bar?
else
# render error bar?
end
end
I would like to render something like the following pictures. In the snap partial, a section looks like this normally:
Once the button is clicked, if the action is successful I want to render the following green success bar:
It is unclear to me how to accomplish this. Should I be leveraging some form of JS/CoffeeScript? Should I add the bars to the partial as hidden by default and simply show them with JS when the action is completed?
link_to processing_path(#app.id), method: :post, action: :processing Using both _path and :action parameters doesn't make sense. Use only one of them
You need to decide whether your button is doing a "traditional" request or an AJAX request
In case of a traditional request, you can use a controller variable #success = ..., and then check this variable inside the view: <% if #success %>
In case of an AJAX request, things would get a little more complicated. However, there's Rails support for "success" and "failed" AJAX responses. Take a look at https://guides.rubyonrails.org/working_with_javascript_in_rails.html#rails-ujs-event-handlers. Typically, you would show/hide certain elements on the page, depending on the server response
You would need something like this on your layouts
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, class: "alert alert-info" %>
<% end %>
Then on your controller
def processing
if service.upload
flash[:notice] = "Success"
else
flash[:notice] = "Error"
end
end
Take a look at this: rails 4 -- flash notice
see Doc: https://coderwall.com/p/jzofog/ruby-on-rails-flash-messages-with-bootstrap
Step 1: Add flash code in layouts/application.html.erb file
<% flash.each do |key, value| %>
<div class="<%= flash_class(key) %>">
<%= value %>
</div>
<% end %>
Step 2: Just need to quickly extend application_helper.rb with the following
def flash_class(level)
case level
when :notice then "alert alert-info"
when :success then "alert alert-success"
when :error then "alert alert-error"
when :alert then "alert alert-error"
end
end
# sometimes it will not work then wrap it with single quotes. for example:
when 'notice' then "alert alert-success"
Step 3: Add below in controller.erb
def processing
if service.upload
flash[:success] = "Processing complete!"
else
flash[:error] = "Something went wrong!"
end
end
Hope it will work :)

undefined method `each' for nil:NilClass while attempting to use a partial

I'm currently having the issue for when I try to use a partial inside of invoices/_form.html.erb, it goes into parts/_index.html.erb and breaks.
Inside of the parts_controller I have:
def _index
#parts = Part.all
end
#unsure if this is needed
Inside of invoices_controller I have:`
def new
#invoice = Invoice.new
#parts = Part.all
end`
Inside of invoices/_form.html.erb I have:
<%= render :partial => "parts/index" , :part => #parts %>
And inside of invoices/new.html.erb I have:
<h1 style="padding-left:120px">New Invoice</h1>
<%= render 'form', invoice: #invoice, part: #parts %>
<%= link_to 'Back', invoices_path, class: "btn btn-default col-md-2" %>
So what this code is attempting to do is display the index page of parts so the user is able to see all current parts they have in stock, and how many of that part is in stock. The parts/index page is the exact same as the the default index page for parts, but it just has a link removed.
The line of code that gives me an issue in parts/index is:
<% #parts.each do |part| %>
And what's confusing me about that is that I should be passing it an object that has data inside of it, since it's declared in both the controller for parts, and the invoice controller. Am I missing something super simple with my syntax, or is what I'm trying to do not the right way to do it? I'm still a noob to rails, so sorry if what I'm trying to get across doesn't make too much sense.
so here is the problem:
<%= render :partial => "parts/index" , :part => #parts %>
you are sending :part to your _index.html.erb partial while using #parts
you need to update your render call to following:
<%= render :partial => "parts/index" , locals: {parts: #parts}%>
and your loop to:
<% parts.each do |part| %>
you provide to _index.html.erb variable part but try to render #parts.
1. you don't need method _index, when your patial _index.html.erb render that not get variable #parts from method _index. I think it's wrong.
2. You need to render in _index.html.erb variable which it's provided from _form
<% part.each do |part_| %>

Displaying a messaging right away to the user when page is loaded

I am not sure if this is possible but I want to display a flash message to the user when they come onto on of the pages automatically. I kind of played around with it but no luck. Does anyone know how to do that if so any help would be greatly appreciated!
CODE FOR CONTROLLER
class BookinController < ApplicationController
def flash
flash.now[:notice] = "Test"
render :action => :new
end
def bookin
#alert = "Successfully saved!"
end
def bookout
#customer_list = Customer.all
#customer_name = params[:customer_name_in]
#r = Customer.find_by_last(#customer_name)
end
end
CODE FOR VIEW
<h2>The Maintenance Functions are restricted to authorized users.
Please login below</h2>
<%= form_tag(bookin_bookout_path, :method => "post") do %>
<div class="field">
Name
<%= text_field_tag :customer_name_in %>
</div>
<br>
Password
<%= text_field_tag :customer_name_in %>
</div>
<br>
<div class="actions">
<br>
<%= submit_tag "Submit Customer Name" %>
</div>
<% end %>
<h2> Main Menu</td> </h2>
You could try the bootbox-rails gem.
In a nutshell:
Add it to your Gemfile,
Add it to your app/assets/javascripts/applications.js
Put something like this in your view:
<script>
<%= raw #alerts %>
</script>
Put something like this in your controller:
#alerts = "bootbox.alert('Some kind of alert!');"
Flash
You'll want to set the flash message in the action, so it's there when the user hits the page
The flash is basically a session variable which will only persist per one action, meaning if you set it on your action, the next one will not have the same message
You can set the flash, as you've already done, like this:
def action
flash[:notice] = "Welcome to our website"
end
Code
As RSB has queried, you've not provided us with the most specific code. So instead, I'll show you a simple example and look out for some comments to come back with updates:
#app/controllers/bookin_controller.rb
class BookinController < ApplicationController
def index
flash[:notice] = "Welcome To Our Page!"
end
end
#app/views/bookin/index.html.erb
<%= flash[:notice] %>
This will display your message for the rendered action. You don't need any specific methods - just set the flash var value in the action you're rendering

Youtube embed link not displaying in Rails

I'm making resourceful routes for youtube videos. So, a person just pastes the youtube embed link in the form. In the controller I have a normal set of resourceful actions:
class VideosController < ApplicationController
def index
#videos = Video.all
end
def new
#video = Video.new
end
def create
Video.create(params[:video])
redirect_to :action => :index
end
def destroy
Video.destroy(params[:id])
redirect_to :action => :index
end
end
And in the view I'm just displaying it: (in Haml)
- #page_title = 'Video'
#videos
%ul
= list_of(#videos) do |video|
%h1= video.title
!= video.link
= link_to "Delete", video_path(video), :method => :delete
= link_to "Add new video", new_video_path
%p#top
= link_to 'Go to top ↑', '#'
For the one who don't use Haml, != escapes the string. video.link holds the YouTube embed code
The problem is that, when I create a new video, and when it redirects me back to the index page, the newly created video isn't displayed (the other ones are normally displayed). Only after I refresh the page, it's normally displayed.
I saw in the web inspector that the src attribute is missing from the iframe (so that's why the video isn't displayed). But when I look in the page source, everything is normal there. So, thinking it may be Javascript's fault, I tried disabling it. But nothing changed.
I don't think you want to escape it using haml... I think you want to call
video.link.html_safe
Note: if the user is pasting in the link, this is very unsafe.
Update --- If you have the javascript develop console open, you'll see this error pop up:
**Refused to execute a JavaScript script. Source code of script found within request.**
Check this answer for why it's refusing to due XSS Here's a method that is both safe and works. You'll paste in the youtube ID in the text field: ibWYROwadYs
index.erb
<% if session[:youtube].present? %>
<iframe width="480" height="360" src="http://www.youtube.com/embed/<%=session[:youtube]%>" frameborder="0" allowfullscreen></iframe>
<% end %>
<%= form_tag load_path do %>
<%= text_field_tag :youtube_id %>
<%= submit_tag "Submit" %>
<% end %>
<%= link_to "Clear", clear_path, :method => :delete %>
home_controller.rb
class HomeController < ApplicationController
def index
end
def smth
session[:youtube] = params[:youtube_id]
redirect_to :action => :index
end
def clear
session.clear
redirect_to :action => :index
end
end

AJAX Form Issues with Ruby on Rails

I'm sure this question has been asked before in a different context but I'm still so stuck with figuring out AJAX Rails and, I guess, Rails in general (kinda makes me wonder if I should just go back to PHP...). Well anyways I have this form that I want to AJAXify.
This is the "list" view which is part of the "subject" controller
<h1>Listing Subjects</h1>
<ul id="subject_list">
<% #subjects.each do |c| %>
<li><%= link_to c.name, :action => 'show', :id => c.id %></li>
<% end %>
</ul>
<p id="add_link"><%= link_to_function("Add a Subject",
"Element.remove('add_link'); Element.show('add_subject')")%></p>
<div id="add_subject" style="display:none;">
<%= form_tag(:action => 'create') do%>
Name: <%= text_field "subject", "name" %>
<%= submit_tag 'Add' %>
<% end %>
</div>
Code for my "subject" controller
class SubjectController < ApplicationController
def list
#subjects = User.find(:all)
end
def show
#subject = User.find(params[:id])
end
def create
#subject = User.new(params[:subject])
if #subject.save
render :partial => 'subject', :object => #subject
end
end
end
My "subject" partial
<li id="subject_<%= subject.id %>">
<%= link_to subject.name, :action => 'show', :id => subject.id %>
</li>
And the User is just a simple model I made that contains two columns "name" and "email".
How this code currently works is that when you click "Add", the textfield input is revealed. When you type something in the input and submit it, the "_show" partial is rendered in the create link. I was following a Rails 2.0 tutorial but I have 3.0 and I've read through some tutorials and they all mention ":remote => true" and jquery_ujs.js but I have no idea how to apply them to a "form_tag" rather than "form_for" Rails helper.
Basically I want to asynchronously add the element to the bottom of the list without a page load. I've really tried to understand absolutely all of the tutorials I could find but I just can't figure it out.
I believe that you'd better use some Unobtrusive JavaScript to tell to your app
and browser what exactly you want to render and how.
You want too much from simple render :partial => 'subject', :object => #subject line of code.
Here's my snippet that may be helpful to you.
# in the view (:remote => true for form_tag is not problem at all)
<%= form_tag({:controller => :products, :action => :empty_cart }, {:id => 'empty_cart', :remote => true}) do %>
<%= submit_tag 'Clear' %>
<% end %>
# in the controller (note that format.js section in the respond_to block)
def empty_cart
...
respond_to do |format|
format.html { redirect_to :root, :notice => 'Your cart is empty now' } # in the case of disabled JS support
format.js { render :js => "$('#empty_cart').fadeOut()" } # or you can place js code in the empty_cart.js.erb file and specify format.js here without the block
end
end
Check this article if I'm not clear enough.

Resources