how to pass key value through [action].js.erb remote: true ajax - ruby-on-rails

Here is how I display my flash messages using key value.
application_html.erb
<div class="container-fluid">
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>" data-turbolinks="false">
<a class="close lay" data-dismiss="alert">&#215</a>
<% if message.is_a?(String) %>
<div id="flash_<%=message_type%>">
<%= sanitize(message) %>
</div>
<% end %>
</div>
<% end %>
</div>
Now I have in my controller:
def saved
...
respond_to do |format|
format.js
end
end
And in my form:
<%= link_to... remote: true, method: :put %>
Now in my saved.js.erb file, I have the following:
<% if request.put? %>
<% response = current_user.saved_articles.new(article: #article) %>
<% if !response.valid? %>
FLASH SOMETHING HERE
<% else %>
<% response.save %>
FLASH SOMETHING HERE
<% end %>
<% else request.delete? %>
<% current_user.saveds.delete(#article) %>
FLASH SOMETHING HERE
<% end %>
How do I pass notice: "You have saved this article" and notice: "You have unsaved this article" ?

is saved action actually saving? if you're saving a record (or updating or deleting) you should (don't have to) do this using create and update and destroy actions. Put everything into one action isn't the proper way to do it, even when you're manipulating db records... why not proper CRUD:
def create
# create logic
render js: { model: #your_model, status: #your_model.persisted? : :ok, :unprocessable_entity }
end
(and other actions)
and then in your js, you can ask the async call status, and build the messaging from there.

Store the flash message component in a partial and call it in js.erb file, remove it after few seconds if you wish to do so.
One small note if you plan to name the partial as _flash.html.erb, flash object value would become nil in the partial's:
I found out that the reason this was not working for me was that I had
named my partial flash. Apparently Rails creates a local variable for
the partial using the partial's name (without the "" character.) So I
had a variable clash. As soon as I change the name of the partial to
something other than _flash everything worked perfectly. I found the
answer here: Rails flash[:notice] always nil
-from this SO post
application_html.erb:
<div class="container-fluid">
<%= render partial: 'shared/flash_messages' %>
</div>
shared/_flash_messages.html.erb
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %> flash_messages" data-turbolinks="false">
<a class="close lay" data-dismiss="alert">&#215</a>
<% if message.is_a?(String) %>
<div id="flash_<%=message_type%>">
<%= sanitize(message) %>
</div>
<% end %>
</div>
<% end %>
controller.rb
def saved
if saved?
flash[:success] = "You have saved this article"
else
flash[:danger] = "You have unsaved this article"
end
respond_to do |format|
format.js
end
end
saved.js.erb
<% if request.put? %>
<% response = current_user.saved_articles.new(article: #article) %>
<% if !response.valid? %>
// append to any element
$('body').append('<%= j render partial: "shared/flash_messages"%>').fadeOut(2000, function(){
$('.flash_messages').remove();
});
<% else %>
<% response.save %>
$('body').append('<%= j render partial: "shared/flash_messages"%>').fadeOut(2000, function(){
$('.flash_messages').remove();
});
<% end %>
<% else request.delete? %>
<% current_user.saveds.delete(#article) %>
$('body').append('<%= j render partial: "shared/flash_messages"%>').fadeOut(2000, function(){
$('.flash_messages').remove();
});
<% end %>

Related

How to create alert with redirect_to

Hi I want to create an success alert when a gossip was created and return on my home page or put's an danger alert when the validation fail
I've just succeeded to setup the error alert.
Here is my gossip controller :
class GossipsController < ApplicationController
def index
#gossips = Gossip.all
end
def show
#gossip = Gossip.find(params[:id])
end
def new
#error = false
end
def create
#gossip = Gossip.new(title: params[:title], content: params[:content], user: User.find(182))
if #gossip.save
redirect_to root_path
else
#error = true
render "new"
end
end
end
And here it's my view of new :
<% if #error %>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>Error</strong>
<ul>
<% #gossip.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<% end %>
<h2>Create your own gossip !</h2> <br><br>
<%= form_tag url_for(action: 'create'), method: "post" do %>
<%= label_tag 'Title :' %> <br>
<%= text_field_tag 'title'%> <br><br>
<%= label_tag 'Content :' %> <br>
<%= text_area_tag 'content'%> <br><br>
<%= submit_tag "Create Gossip" %>
<% end %>
I've try to do same for the success alert but if i put a #success = true in the controller and <% if #success %> in the index view that don't work. I don't have any ideas.
Tell me if you need some part of my code.
I've tried with flash but that doesn't worked and whatever i want the same style with the error and success alert
create flash message partial app/views/layouts/_flash.html.erb
(please give filename with underscore since it partial)
<% flash.each do |key, value| %>
<div class="alert alert-<%= key == "success" ? "success" : "danger" %>">
<%= value %>
</div>
<% end %>
add partial to your app/views/layouts/application.html.erb
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
...
<%= render 'layouts/flash' %>
<%= yield %>
</Body>
</html>
in your controller
def create
#gossip = Gossip.new(title: params[:title], content: params[:content], user: User.find(182))
if #gossip.save
flash[:success] = 'success'
redirect_to root_path
else
flash[:danger] = #gossip.errors.full_messages[0]
render "new"
end
end
Don't write in every form view instead of that you can just write common code to show the alerts related to success or error and then use that from any controllers :-
## app/views/layouts/application.html.erb
<html>
<body>
<%= render 'layouts/header' %> ## your header layout
<div class="container">
<% flash.each do |key, value| %>
<div class="alert <%= flash_class(key) %>"><%= value.try(:html_safe) %></div>
<% end %>
<%= yield %>
<%= render 'layouts/footer' %> ## your footer layout
</div>
</body>
</html>
Use helper to get correct bootstrap classes according to your requirement :-
module ApplicationHelper
def flash_class(level)
level = level.to_sym
case level
when :notice then "alert-info"
when :success then "alert-success"
when :error then "alert-danger"
when :alert then "alert-warning"
end
end
end
And then use above code in any controller :-
if #gossip.save
flash[:success] = "Your success custom message."
redirect_to root_path
else
err_msg = ""
flash.now[:error] = #gossip.errors.full_messages.map{|msg| err_msg << "#{msg} <br> "}
render "new"
end
Note :- Use flash when you are redirecting, and flash.now when you are rendering.
edited content :-
Add <br> tag in error messages before showing and then on view page add .html_safe for showing every error in next line. This hack should be work and user will able to see all error messages related to object.
flash.now[:error] = #gossip.errors.full_messages.map{|msg| err_msg << "#{msg} <br> "}
In view
<% flash.each do |key, value| %>
<div class="alert <%= flash_class(key) %>"><%= value.try(:html_safe) %></div>
<% end %>

Ruby on Rails Flash Notice Not working properly

Flash notice is not working. I am using rails 5.1.
My code is like this:
def message
redirect_to users_path, notice: "Message"
end
<% if flash.present? %>
<% flash.each do |k, v| %>
<p class="abc" id="a"><%= v %></p>
<% end %>
<% else %>
<p class="a" id="b"></p>
<% end %>
Flash Message is coming few times and few times it's not coming, It's going in else block.
So, for this I have fixed by using flash.keep in users index controller. But Now in every page whenever I am redirecting,that flash message is coming.
You can try as:
def message
flash[:notice] = 'Message'
redirect_to users_path
end
And in your view:
<% if flash[:notice].present? %>
<% flash.each do |k, v| %>
<p class="abc" id="a"><%= v %></p>
<% end %>
<% else %>
<p class="a" id="b"></p>
<% end %>
Hope it can solve your problem.
I think the flash hash is always present. You can check if it's empty instead https://api.rubyonrails.org/classes/ActionDispatch/Flash/FlashHash.html#method-i-empty-3F
<% if flash.empty? %>
<p class="a" id="b"></p>
<% else %>
<% flash.each do |k, v| %>
<p class="abc" id="a"><%= v %></p>
<% end %>
<% end %>

Edit action that creates and saves new object instead of updating existing - how to display errors?

In my app I have a Course model. For several reasons edit action should not update existing course, but create and save a new one.
Currently in my CoursesController I have following methods doing it:
def edit
find_course
end
def update
#course = Course.new(permitted_params)
if #course.save
redirect_to courses_path, notice: 'Course was updated'
else
find_course
render :edit
end
end
private
def find_course
#course = Courses.find(params[:id])
end
And views:
edit.html.erb
<div class="row">
<div class="col-md-10"><h3> Edit <%= #course.title %> </h3></div>
</div>
<div>
<%= render 'form', url:
course_path(#course) %>
</div>
_form.html.erb
<%= form_for #course, url: url, :html => { class: "form-horizontal" } do |f| %>
<% if #course.errors.any? %>
<div id="error_expl" class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title"><%= pluralize(#course.errors.count, "error") %> prohibited this Course from being saved:</h3>
</div>
<div class="panel-body">
<ul>
<% #course.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
My code does what is expected: when users edits a course, in fact a new course is being created. The problem is that with this approach I cannot display errors if update action fails, what is normal in this approach because in else statement object containing this info is no longer available.
My question is: what is the best, recommended by best practices and experienced developers approach to:
display errors in my solution?
how should I change my approach to have it implemented in a better way?

Implementing Ajax - Rails App

I'm trying to implement ajax into when I favorite a place, but the reload/update of the section/ajax functionality doesn't work. Only if I reload the page, then I see the action that has occurred. Would appreciate any tips.
My favorite_places/show.html.erb
<div class="heart">
<p class="text-center">
<% if current_user %>
<%- unless current_user.favorite_places.exists?(id: #place.id) -%>
<%= link_to favorite_places_path(place_id: #place), remote: true, method: :post do %>
<span title="Favorite this Place"><i class="glyphicon glyphicon-heart-empty"></i></span>
<% end %>
<%- else -%>
<%= link_to favorite_place_path(#place), remote: true, method: :delete do %>
<span title="Un-Favorite this Place"><i class="glyphicon glyphicon-heart"></i></span>
<% end %>
<% end %>
<% end %>
</p>
</div>
My favorite_places_controller.rb
def update
#favorite_place.update_attributes[params[:place]]
respond_to do |format|
format.html { redirect_to #place }
format.js
end
end
My update.js.erb
<% if #place.favorited %>
$(' #<%= #place.id %>').html("true");
console.log ("<%= #place.name %> has been favorited.");
<% else %>
$(' #<%= #place.id %>').html("false");
console.log ("<%= #place.name %> is not a favorite.");
<% end %>
My dev console output
DELETE http://0.0.0.0:3000/favorite_places/34 406 (Not Acceptable)
jquery.js?body=1:8716send
jquery.js?body=1:8716jQuery.extend.ajax
jquery.js?body=1:8146$.rails.rails.ajax
jquery_ujs.js?body=1:73$.rails.rails.handleRemote
jquery_ujs.js?body=1:149(anonymous function)
jquery_ujs.js?body=1:299jQuery.event.dispatch
jquery.js?body=1:5108elemData.handle

notices and errors on rails3

I read somewhere that rails 3 form helper does not have error messages embedded in it anymore. I am wondering how I am supposed to show flash messages when I set them up inside my controller or as an inline notice in redirect_to? How am I supposed to display them on my view? Is there helper for this?
For example if I have
def update
if #person.save
flash[:notice] = "Successfully saved!"
end
end
how do i show the notice on my view?
flash will still work as long as you display it in your layouts:
<div id="page">
<% if flash[:alert] %>
<p class="flash-error"><%= flash[:alert] %></p>
<% end %>
<% if flash[:notice] %>
<p class="flash-notice"><%= flash[:notice] %></p>
<% end %>
<%= yield %>
</div>
You can either display error messages manually or use the dynamic_form gem which gives you the old behavior.
You can still display flash messages in your view with this:
<%= flash[:notice] %>
But if you want to display for error messages:
#In your form
<%= form_for #foo do |f| %>
<%= render "shared/error_messages", :target => #foo %>
...
<% end %>
#shared/_error_messages.html.erb
<% if target.errors.any? %>
<div id="error_explanation">
<ul>
<% target.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

Resources