Alerts without page reload Rails AJAX - ruby-on-rails

I have a model Snippit and I want users to be able to delete a snippit, from a list, and then show an alert saying it was deleted, all using ajax. I have figured out how to do the actual deleting, but not the alert.
Here's the code:
snippits_controller.rb
def destroy
#snippit = Snippit.find(params[:id])
#snippit.destroy
respond_to do |format|
format.html { redirect_to snippits_url}
format.json { head :no_content }
format.js {render :alert => "Sippit destroyed. "}
end
end
destroy.js.erb
$('#snippit_<%= #snippit.id %>').remove();
index.html.erb
<% #snippits.each do |snippit| %>
<span class="panel panel-default" id="snippit_<%= snippit.id %>">
<%= link_to edit_snippit_path(snippit), :class => "text" do %>
<div class="panel-body">
<h3 class="text"><%=snippit.title%></h3>
<p class="trash"><%= link_to snippit, method: :delete, remote: true do %>
<i class="fa fa-2x fa-trash-o"></i>
<% end %></p>
</div>
<% end %>
</span>
<% end %>
Any and all help is greatly appreciated :)

If you want a JS alert response, then you'd want something like the following instead
format.js {render js: "alert('Sippit destroyed.');"}
The format.js render above means you're rendering a JS response. Your alert render :alert => "Sippit destroyed. " only works for HTML response because the flash[:alert] is rendered in the HTML page, but since you are rendering a JS response, then you'd either do the JS alert implementation above OR you partially update the HTML page to update the flash message by something like the following
destroy.js.erb
$('#snippit_<%= #snippit.id %>').remove();
$('#flash_container').html('<%= j render partial: "flash_container" %>');
UPDATE (Added working controller code for method 2: using destroy.js.erb above)
def destroy
#snippit = Snippit.find(params[:id])
#snippit.destroy
respond_to do |format|
format.html { redirect_to snippits_url}
format.json { head :no_content }
format.js { flash.now[:alert] = #snippit.destroyed? ? 'Sippit destroyed.' : #snippit.errors.full_messages }
end
end
I added a failure-handler code above for format.js. It will set the flash alert message into either 'Sippit destroyed' if #snippit was successfully destroyed, OR into 'Some failure to destroy error' if #snippit was not destroyed.

Related

Ruby on Rails 7 + Turbo - Not showing notice message

I am learning Ruby on Rails. Rails 7 + Turbo stream... I am following a tutorial and I am having a problem with displaying the Notice message.
Can you help me understand why I am not getting notice message after I create a new quote?
Here is a create action in QoutesController.rb. Only when I put this line of code:
flash[:notice] = "Gets displayed with this line and a refresh... "
before the format.html line, then I will get the notice message after I refresh the page upon creating a quote. Only then the message gets displayed.
Can you please help me understand this?
(Yes, I am using a Devise gem here, Turbo stream, Turbo Rails, Rails 7)
Thank you
def create
#quote = current_company.quotes.build(quote_params)
if #quote.save
respond_to do |format|
flash[:notice] = "Gets displayed with this line and a refresh... " #weird
format.html { redirect_to quotes_path, notice: "Quote was successfully created." }
format.turbo_stream
#debugger
end
else
render :new, status: :unprocessable_entity
end
end
In Rails 7, unrefresh page when you create successfully. So, flash[:notice] not display.
Create views/shared
In share folder, we have _flash.html.erb, _notices.html.erb
_flash.html.erb
<div class="alert <%= bootstrap_class_for(msg_type) %> alert-dismissible fade show" role="alert">
<div class="container text-center">
<%= message %>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
_notices.html.erb
<div id="flash">
<% flash.each do |msg_type, message| %>
<%= render partial: "shared/flash", locals: { msg_type: msg_type, message: message } %>
<% end %>
</div>
When you create success -> create views/qoutes/create.turbo_stream.erb
<%= turbo_stream.update "flash", partial: "shared/flash", locals: { msg_type: :notice, message: "your message" } %>
// msg_type: :notice, :alert, :error, :success
In views/layouts/application.html.erb
<%= render 'shared/notices' %>
<%= yield %>
In application_helper
module ApplicationHelper
def bootstrap_class_for(flash_type)
{
success: "alert-success",
error: "alert-danger",
alert: "alert-warning",
notice: "alert-info"
}.stringify_keys[flash_type.to_s] || flash_type.to_s
end
end
and if create failed
ex:
def create
if #object.save
// code
else
render_flash(:alert, full_messages(#post.errors.full_messages))
end
end
In application_controller
class ApplicationController < ActionController::Base
protected
def render_flash type, message
render turbo_stream: turbo_stream.update("flash", partial: "shared/flash", locals: { msg_type: type, message: message })
end
def full_messages messages
messages.join("\n")
end
end
=> This is my way. Hope to help you.

rails redirect user to profile page after destroy action

I have a form for work_histories. When a user deletes a work history I would like them to be redirected to their users profile page instead of the user_work_histories_url which calls this controller action (work_histories#show). I wanted to redirect to the users profile page which is user_path(#user).
I tried changing the work_histories destroy action to redirect to user_path(#user) instead of user_work_histories_url but it says the id of the job I just deleted couldn't be found.
here's my controller for work_histories
# DELETE /users/:user_id/work_histories/:id
def destroy
#work_history = WorkHistory.find(params[:id])
#work_history.destroy
respond_to do |format|
format.html { redirect_to user_work_histories_url,
notice: "The work history for your #{#work_history.job_title.upcase} job was successfully destroyed." }
format.json { head :no_content }
end
end
here's the show.html.erb for work_histories
<p id="notice"><%= notice %></p>
<p>
<strong>Job Title:</strong>
<%= #work_history.job_title %>
</p>
<p>
<strong>Job Description:</strong>
<%= #work_history.description %>
</p>
<%= link_to 'Back', user_work_histories_path(#user) %> |
<%= link_to 'Edit', edit_user_work_history_path(#user, #work_history) %> |
<%= link_to 'Delete', user_work_history_path(#user, #work_history), method: :delete,
data: { confirm: 'Are you sure you want to delete this work history?' } %>
Think I figured it out. I'm not sure if this is the "rails way" of doing it or if it's just another one of my hacked together solutions though.
I was in the work_history controller trying to call user_url(#user) which is how i do it in the users controller but looks like it works when I change it user_url(#work_history.user). work history belongs to user. It works...for now.
# DELETE /users/:user_id/work_histories/:id
def destroy
#work_history = WorkHistory.find(params[:id])
#work_history.destroy
respond_to do |format|
format.html { redirect_to user_url(#work_history.user),
notice: "The work history for your #{#work_history.job_title.upcase} job was successfully destroyed." }
format.json { head :no_content }
end
end

Rails 5 flash not working for redirect

I have created rails 5 application and I have the following code in controller and views for showing flash messages. I saw many question like this but I could not solve the problem.
controller side
respond_to do |format|
if #trigger.update(trigger_params)
flash[:success] = 'Trigger was successfully updated.'
format.html { redirect_to edit_project_trigger_path(#trigger, project_secret_key: #project.secret_key) }
format.json { render :show, status: :ok, location: #trigger }
else
error = ''
#trigger.errors.full_messages.each do |msg|
error += "#{msg} <br>"
end
flash.now[:error] = error
format.html { render :new }
format.json { render json: #trigger.errors, status: :unprocessable_entity }
end
end
view side
<% if flash[:error].present?%>
<div class="alert alert-danger alert-message alert-message-common" role="alert">
<%= flash[:error].html_safe %>
</div>
<% end %>
<% if flash[:notice].present? %>
<div class="alert alert-success alert-message alert-message-common" role="alert">
<%= flash[:notice].html_safe %>
</div>
<% end %>
<% if flash[:alert].present? %>
<div class="alert alert-danger alert-message alert-message-common" role="alert">
<%= flash[:alert].html_safe %>
</div>
<% end %>
<% if flash[:success].present?%>
<div class="alert alert-success alert-message alert-message-common" role="alert">
<%= flash[:success].html_safe %>
</div>
<% end %>
It's show when using alert but success messages are not shown. Is there any problem in rails 5 or any problem in my code ?
I hope alert working because of page render and success not working because of redirect.
Only alert and notice flash keys are supported by default.
To add success:
class ApplicationController
add_flash_types :successs
Reference: Ruby Guides
try this:
format.html { redirect_to edit_project_trigger_path(#trigger, project_secret_key: #project.secret_key), :success => 'Trigger was successfully updated.' }
This should work:
format.html { redirect_to edit_project_trigger_path(#trigger, project_secret_key: #project.secret_key), flash: {success: 'Trigger was successfully updated.'} }
For some reasons, in rails you should you either notice or alert keys in redirect_to method, but if you need success or something else, you should use nested hash in flash key.
Check here http://blog.remarkablelabs.com/2012/12/register-your-own-flash-types-rails-4-countdown-to-2013
The Rails docs for redirect_to mention that "There are two special accessors for the commonly used flash names alert and notice as well as a general purpose flash bucket." You need to use regular flash syntax for any others.

Using flash message instead of #game.errors

Instead of using the following (which i think was generated by rails):
def create
#game = current_user.games.create(params[:game])
respond_to do |format|
if #game.save
format.html { redirect_to #game, notice: 'Game was successfully created.' }
format.json { render json: #game, status: :created, location: #game }
else
format.html { render action: "new" }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
end
end
I want to put the errors into a flash message. My application.html.erb already has:
<% flash.each do |name, msg| %>
<div class="row-fluid">
<div class="span12">
<div class="alert alert-<%= name == :notice ? "success" : "error" %>">
<a class="close" data-dismiss="alert">×</a>
<%= msg.html_safe %>
</div>
</div>
</div>
<% end %>
So it is already able to handle it, but I can't figure out what to do in the controller. I have no idea how or what populates #game.errors but do know that when a model validation fails, it contains why
This is for rails 2.3.8 but I found it useful anyhow.
http://api.rubyonrails.org/v2.3.8/classes/ActiveRecord/Errors.html
Flash is just a hash. You can add to it like this:
Rails - Getting an error message from the model that is not a Validation error
Sorry for the lazy answer, but it's late and I'm on a tablet. Hope it at least points you in the right direction.

Flash messages in Rails 3.2.3 and json

There is an action in a controller. It can be called only with json format via ajax.
def update
#article = Article.find_by_id params[:id]
respond_to do |format|
if #article.update_attributes(params[:article])
flash[:message] = "good"
else
flash[:error] = #article.errors.full_messages.join(", ")
end
format.json { render :json => flash}
end
end
the part of a page
<% unless flash[:error].blank? %>
<%= flash[:error] %>
<% end %>
<% unless flash[:message].blank? %>
<%= flash[:notice] %>
<% end %>
<!-- page content goes -->
Of course, a page contains a button_to with :remote=>true that calls the method update.
The bottom line is that it shows nothing after updating. JSON object definitely returns, I can see it in fireBug.
The question is, am I using flash correctly? And how do I use it to show a message on a page? Please don't forget about ajax.
Why do you have an if/else statement in your respond_to block?
def update
#article = Article.find_by_id params[:id]
if #article.update_attributes(params[:article])
flash[:notice] = "Good"
else
flash.now[:notice] = "Bad"
render "edit"
end
respond_to do |format|
format.html {redirect_to #article}
format.js
end
end
Then create update.js.erb
$("#notice").text("<%= escape_javascript(flash[:notice]) %>")
$("#notice").show()
Code above might not be 100% correct.
For flash, I'd have something like:
<div id="notice">
<% flash.each do |key, value| %>
<%= content_tag(:div, value, :class => "flash #{key}") %>
<% end %>
</div>
This posting has all the code you'll need. It saved my hide:
https://gist.github.com/linjunpop/3410235
Here's a fork of it that makes a few minor modifications:
https://gist.github.com/timothythehuman/5506787
I think
You have to bind ajax:success call back which will display flash message by replacing message or placing message to dom.

Resources