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.
Related
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.
I have a page with a partial containing a form in my rails app (5.1.1)
I am using the simple_form gem.
This page is for showing details of a a Journey, which can contain many legs. Inside the journey view, we render a partial "_form" for the legs view. This view contains a form which creates a new leg to add to the journey, and in this case is being rendered from the 'show' view of journey.
journeys/show.html.erb
<div class="container">
<div class="col-xs-12">
<h3><%= #journey.name %></h3>
<h4><%= #journey.legs.count %> <%= "leg".pluralize(#journey.legs.count) %> covering <%= #journey.total_distance.round(1) %> <%="mile".pluralize(#journey.total_distance)%>!</h4>
<hr/>
<h4><%= (#journey.has_legs) ? 'Add another leg to the journey' : "Your journey has no legs, and we all know a journey can't go far without its legs! Quick...give it some legs..." %></h4>
<%= render partial: "legs/form", locals: {leg: #new_legs.first} %>
<%= link_to 'Edit', edit_journey_path(#journey) %> |
<%= link_to 'Back', journeys_path %>
</div>
When a validation error occurs on the leg that is being created, due to the leg's create action code - it renders the :new view of the leg, which works and shows all errors etc on the new view for the leg. This is due to the following action code on the legs controller:
create action of legs
def create
#leg = Leg.new(leg_params)
respond_to do |format|
if #leg.save
format.html { redirect_to #leg, notice: 'leg was successfully created.' }
format.json { render :show, status: :created, location: #leg }
else
format.html { render :new }
format.json { render json: #leg.errors, status: :unprocessable_entity }
end
end
end
However, I would like to render the journey's "show" view showing all errors as would be seen on the :new view of the leg.
I know you can do render "journeys/show" which renders the show view of the journey, however, it doesn't persist the validation errors in the rendered partial "legs/form".
How do I render the journey show view, making sure to pass it all validation errors on the included partial? I have tried using redirect_back(fallback_path=>root_url)but that does not persist the errors.
Please help!
The answer was relatively simple - thanks to the freenode #rubyonrails channel for helping.
Pass the partial a controller created instance of #leg, this #leg object will either be a new object, or it will be the old object with all errors in it.
Create that #leg in the journeys show controller, and in the leg create action, if it fails, create a #journey instance variable from #leg.journey and then render "journeys/show" et voila, everything works as expected.
Upd: it is not the best advise, but it can set you to right direction. i think it sounds as How to display Ruby on Rails form validation error messages one at a time
also here it describes http://guides.rubyonrails.org/v2.3.11/activerecord_validations_callbacks.html#errorsadd
in my case i use this feature without db validation:
controller:
def create
...
flash.now[:danger] = 'Invalid data'
render 'index'
end
view index.html.erb
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
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.
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.
Currently, this is the code I have for creating a new message:
if #message.save
respond_to do |format|
format.html { redirect_to messages_path }
format.js
end
else
flash[:notice] = "Message cannot be blank!"
redirect_to :back
end
How do I get the same message to print in Ajax? Would also like control to format it and position it.
In aplication controller
after_filter :add_flash_to_header
def add_flash_to_header
# only run this in case it's an Ajax request.
return unless request.xhr?
# add different flashes to header
response.headers['X-Flash-Error'] = flash[:error] unless flash[:error].blank?
response.headers['X-Flash-Warning'] = flash[:warning] unless flash[:warning].blank?
response.headers['X-Flash-Notice'] = flash[:notice] unless flash[:notice].blank?
response.headers['X-Flash-Message'] = flash[:message] unless flash[:message].blank?
# make sure flash does not appear on the next page
flash.discard
end
Move notifications code into partial:
<div class="noticesWrapper">
<% flash.each do |name, msg| %>
<div class="alert alert-<%= name == :notice ? "success" : "error" %>">
<a class="close" data-dismiss="alert"><i class="icon-remove"></i></a>
<%= msg %>
</div>
<% end %>
</div>
In js.erb file:
$('.noticesWrapper').html("<%= j(render partial: 'layouts/flash_notices') %>");
In controller action you need to flash messages with flash.now:
flash.now[:error] = "your message"