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.
Related
I try to allow user to fill the form with a delay between each user,
The delay is set to 100 between the last user registered in my database and the new one
Here is what I do in my controller :
class EmailsController < ApplicationController
def index
redirect_to root_path
end
def new
#email = Email.new
end
def create
if Time.now - Email.last.created_at < 100
respond_to do |format|
format.html{render :new, notice: "Wait !"}
end
else
respond_to do |format|
#email = Email.create(email_params)
if#email.persisted?
format.html {redirect_to invoice_index_path, notice: 'Email validated '}
else
format.html{render :new}
end
end
end
end
private
def email_params
params.require(:email).permit(:email, :id_user)
end
end
My view :
<div class="container">
<% if flash[:notice].present?%>
<center><p id="notice" class="alert alert-success"><%= flash[:notice] %></p></center>
<%end%>
<center><h1>Nouvelle Connection </h1></center>
<%= form_with model: #email, local: true do |form|%>
<% if #email.errors.any? %>
<div id="error explanation" class="alert alert-danger">
<p>Erreur(s) : </p>
<ul>
<% #email.errors.full_messages.each do |message|%>
<li><%=message%></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= label_tag :email %> :
<%= form.email_field :email, placeholder: "Insérez votre email", class: "form-control" %>
</div>
<div class="form-group">
<%= form.submit class: "btn btn-primary btn-lg btn-block", value: "Se connecter" %>
</div>
<%end%>
</div>
When I fill the form, nothing happen, just the url change from http://localhost:3000/ to http://localhost:3000/emails and when I re-click on Validate, it goes to http://localhost:3000/emails/53 with the error The action 'update' could not be found for EmailsController but I guess I have this error because I don't have any update/edit in my controller.
Do you know how to fix that to allow me a delay between each user ?
Edit : I now have the error undefined method errors for nil:NilClass in my view at the line <% if #email.errors.any? %>. I understand this is because my #email is nil but I tried to integrate this in my view :
<% if #email.nil?%>
<%= Wait for the moment %>
<%end%>
Also tried : <% if #email&.errors&.any? %> why so, I return to the URL : http://localhost:3000/emails
But still have the same error, do you know how to fix it ?
First off, in your view you check for notice.present? and that should be flash[:notice].present?. So then the error will be shown.
Secondly, in your controller you are actually first creating the email, and only then checking if it should be created, and then not even removing it? So the only result is that people will see a notice, but the email would still be created.
So instead do something like:
def create
if Time.now - Email.last.created_at < 100
respond_to do |format|
#email = Email.new(email_params)
format.html do
flash[:notice] = 'Wait! You cannot enter emails so quickly!'
render :new
end
end
else
respond_to do |format|
#email = Email.create(email_params)
if #email.persisted?
format.html {redirect_to invoice_index_path, notice: 'Email validé '}
else
format.html{render :new}
end
end
end
end
Secondly this does seem to mean that any user wanting to enter a new email, will be punished if another user has also entered another email. So in that case you might want to check as follows:
Email.where(created_by_id: current_user.id).last
to only check for Email 's the current user has entered (but maybe that is taking your problem/solution too far?).
Also note there are much better/efficient ways to throttle requests (rate limiting) using apache/nginx (which is probably how it will be deployed), so is this actually a good approach to handle in your ruby on rails code?
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.
I have RoR 4.2.0beta. (Although it s irrelevant as this is a beginer problem).
My form does not insert in the database the "propuneres" that I am creating trough it. And as a result they do not show in the index page when I get redirected to it. They show up when I create them through the console.
class PropuneresController < ApplicationController
before_action :prop_params
def new
#user = User.find(params[:user_id])
#propunere = #user.propuneres.build
end
def create
#user= User.find(params[:user_id])
#propunere = #user.propuneres.new(params[:prop_params])
#propunere.save
if #propunere.empty?
render 'new'
else
redirect_to user_propuneres_path
end
end
def index
#user = User.find(params[:user_id])
#propunere = #user.propuneres(params[:prop_params])
end
private
def prop_params
params.require(:propunere).permit(:titlu, :body)
end
end
new.html.erb
<h2> Propunere Nouă </h2>
<%= form_for #propunere do |f| %>
<ul>
<% #propunere.errors.full_messages.each do |error| %>
<li><%= error %></li>
<% end %>
</ul>
<p>
<%= f.label :titlu %><br />
<%= f.text_field :titlu %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
index.html.erb
<h2> Propuneri: </h2>
<% #propunere.each do |p| %>
<%= p.titlu %>
<%= p.body %>
<% end %>
Not sure if its relevant, but you have code
#propunere.save
if #propunere.empty?
render 'new'
else
redirect_to user_propuneres_path
end
Object #prorunere will never be empty, since you have
#propunere = #user.propuneres.new, which assigneds user_id to your #propunere object and
render 'new' will never be rendered, therefore you wont see any validation errors and never find out why your record wasnt created
Also since you have that piece of code, and dont see errors, this is what most like broke your code
#user.propuneres.new(params[:prop_params]) - you should use your permitted params, so it'd look like
#propunere = #user.propuneres.new(prop_params)
I've cloned your repo, here's the problem: in new.html.erb you had
<%= form_for #propunere, url: new_user_propunere_path(#user, #propunere), html: { method: :get } do |f| %>
Both the url and the method are wrong. user_propuneres_path will give you the correct url for the create action and the correct method is :post, not :get. This is why you never reached the create action.
You also need to change from #propunere = #user.propuneres.new(params[:propunere]) to #propunere = #user.propuneres.new(prop_params), otherwise you'll get a ActiveModel::ForbiddenAttributesError exception.
You can see all the routes in the app by running rake routes in the terminal.
I don't think you need the params in your index action:
#propunere = #user.propuneres
and it would be more logical to write it in plural since you have many of them.
Edit:
As Avdept suggested your create action should look like this:
def create
#user = User.find(params[:user_id])
#propunere = #user.propuneres.new(prop_params)
respond_to do |format|
if #propunere.save
format.html { redirect_to user_propuneres_path(#user), notice: 'Your propunere has been saved' }
else
format.html { render :new }
end
end
end
Do you have any validations for the Propunere model? Maybe the model is invalid. You can use
the create! method instead of create for testing, because it will throw an exception if the object cannot be saved. Also try puts #propunere.inspect before persisting it and check that the contents of the object are ok, the output will be shown in the development log.
I cannot figure out why my rails views are not recognizing flash[:notice] or flash[:error]. I keep getting the following error regarding the partial view being rendered. The specific error is:
ActionView::Template::Error (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]):
In my controller I have
def index
#organisms = Organism.all
flash[:error] = "test"
flash[:notice] = "test"
respond_to do |format|
format.html
format.json { render :json => #organisms }
end
end
In my index.html.erb file I render out a partial through:
<%= render "shared/flash" %>
The partial has the following code.
<div id="flashes">
<% if flash[:notice] %>
<p id="flash_notice" class="messages notice"><%= flash[:notice] %></p>
<%= javascript_tag "$('#flash_notice').effect('highlight',{},1000);" %>
<% end %>
<% if flash[:error] || flash[:errors] %>
<p id="flash_errors" class="messages errors"><%= flash[:error] || flash[:errors] %></p>
<%= javascript_tag "$('#flash_errors').effect('highlight',{},1000);" %>
<% end %>
<% flash[:error] = flash[:errors] = flash[:notice] = nil %>
</div>
However, if instead of rendering the partial I throw in <%= notice %> it renders out the notice.
If I take the partial code and stick it in the top of the index.html.erb file it renders correctly. Thus, I assume that I am rendering the partial view wrongly?
Any help is much appreciated. Thanks!
Don't name your partial flash. Ruby on Rails creates a local variable with the same name as the partial. In your case, a flash local variable is being created.
Rename your partial to something other than flash and it should work.
Also, you shouldn't need to set flash to nil at the bottom of your partial. Let Rails take care of that for you.
You have to pass the flash to the partial:
<%= render 'shared/flash', flash: flash %>
Or a bit longer:
<%= render partial: 'shared/flash', locals: { flash: flash } %>
I'm creating a simple demo app that allows a user to enter their email address to register their interest in receiving beta access. The app then sends them a confirmation email that lets them know we've received their request. If you've ever signed up to be notified of a beta launch then you get the idea.
I'm curious about how to handle errors in Rails 3 while using AJAX. Before implementing my respond_to block I had a form that rendered a shared errors partial.
Here's the form.
<% if flash[:notice] %>
<p><%= flash[:notice] %></p>
<% end %>
<p>Sign up to be notified when the beta launches.</p>
<%= form_for #user, :remote => true do |form| %>
<%= render '/shared/errors', :target => #user %>
<%= form.label :email, "Your Email Address" %>
<%= form.text_field :email %>
<%= form.submit "Notify Me" %>
<% end %>
And here's the aforementioned errors partial.
<% if target.errors.any? %>
<ul>
<% target.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
Very standard stuff. The controller action looks like this.
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to :back, flash[:notice] = "Thanks for your interest! We'll let you know when the app is in beta." }
format.js
else
format.html { render :action => :new }
format.js
end
end
end
Everything works perfectly before implementing ajax. If the form passes validation then they see the success flash message and if not then they see a list of errors. So now that i have a create.js.erb file how should I handle the errors without repeating myself or is that impossible. I obviously want to keep this as DRY as possible.
You can still render a shared partial for all .js errors in your js.erb file.
<% if #user.errors.any? %>
var el = $('#create_user_form');
// Create a list of errors
<%= render :partial=>'js_errors', :locals=>{:target=> #user} %>
<% else %>
$('#users_list').append("<%= escape_javascript(render :partial=>"users/show", :locals=>{:user => #user }) %>");
// Clear form
el.find('input:text,textarea').val('');
el.find('.validation-errors').empty();
<% end %>
And your partial could look like (Assuming jquery):
<% target.errors.full_messages.each do |error| %>
var errors = $('<ul />');
errors.append('<li><%= escape_javascript( error ) %></li>');
<% end %>
But there's also ANOTHER option...It's even DRYer.
http://www.alfajango.com/blog/rails-3-remote-links-and-forms/
If you are working your way through ajax in rails 3, this guide is really the best for understanding responses and ajax rendering as it currently stands.
I worked through this guide and posted in the comments how you can actually use your HTML partials for both HTML and AJAX request responses. I did it by accident and then followed up on how to do it.
Enjoy!
You can actually return straight-up html with your response just like before.
Here's the short version:
def create
#something = Somethng.new(params[:something])
if #something.save
respond_with( #something, :status => :created, :location => #something ) do |format|
format.html do
if request.xhr?
render :partial => "something/show", :locals => { :billable => #billable }, :layout => false
end
end
end
else
respond_with( #something.errors, :status => :unprocessable_entity ) do |format|
format.html do
if request.xhr?
render :partial => "something/new", :locals => { :something => #something }, :layout => false
else
render :action => :new
end
end
end
end
end
I'm not sure the rails remote form way to do it, but my standard mode of operation is to return objects on ajax request in this format:
{ success: true|false,
data: "html or some other data",
errors: {} } // jsonified ActiveModel::Errors object
It works very well and lets you render partials into the data field for use on the page, or you can loop through errors in the error object to insert error messages or highlight fields.
I have been facing the same problem a few days ago. I used remote => true option in my form to use Ajax in my Rails 3 application. After that, I have been looking for solution for validating my form fields. After trying a good number of jQuery / Javascript approaches (none of them worked for me though) I came to know about a superb gem called client_side_validations. It is very easy to install by following the instructions on github link (https://github.com/bcardarella/client_side_validations). It works like charm for client side validation of form fields, an awesome gem indeed. Hope this helps with people who are tired of looking for a simple solution for client side validation of model fields after using Ajax in Rails 3 application.