I have a form I built using Formtastic in Rails 3. The form submits to the #create action of ClientsController, and if the save is successful the controller redirects to a "thank you" page. If the save is not successful, it redirects to the page where the form is embedded. I'd like to be able to show the validation errors inline on the form page, but after the redirect back to that page, the errors object comes back empty.
What can I do so I can display the validation errors on the form?
Here is the code from the controller.
if client.save && event.save
redirect_to "/thank-you"
else
redirect_to :back
end
Some additional details: I am using RefineryCMS so there is no view for the page where the form is, and therefore I can't render the view.
You need to save your errors into session.
if client.save && event.save
session[:client_create_errors] = nil
redirect_to "/thank-you"
else
session[:client_create_errors] = client.errors
redirect_to :back
end
now you can access errors object from anywere using session[:client_create_errors]
Why not:
render :action => 'name-of-the-view-the-form-is-in'
instead of the redirect_to :back ?
Related
I’m using Rails 5. When my user is logged in, I want to replace the ‘/users/4’ action with a generic ‘/dashboard’ home link. I would also like the remove the user’s ability to typing in ‘/users/##’ into the browser, instead only allowing them to visit ‘/dashboard’. How do I do this? Currently, in my config/routes.rb I have
get '/dashboard', to: 'users#show'
resources :users
and in my users_controller.rb file I have
def show
#user = User.find(params[:id])
#user_subscriptions = UserSubscription.find_active_subscriptions_by_user(#user)
end
But currently when I visit “/dashboard” in my browser, I get the error
Couldn't find User with 'id'=
How can I set up my route to disable the show action but allow /dashboard to successfully navigate to the action above?
What I like to do is something like this
get '/dashboard' => 'users#show', as: :dashboard
now on your view you can do
link_to 'Dashboard', dashboard_path(current_user)
and in the controller you can do
def show
params[:id] == current_user.id unless params[:id]
#user = User.find(params[:id])
#user_subscriptions = UserSubscription.find_active_subscriptions_by_user(#user)
end
I'm making AJAX based application with Devise as authentication system. The problem I encountered is that when I sign in with Devise with AJAX, then when view changes and log out button appears it's showing this error when clicked:
ActionController::InvalidAuthenticityToken in Customization::SessionsController#destroy
ActionController::InvalidAuthenticityToken
Parameters:
{"_method"=>"delete",
"authenticity_token"=>"hitX5aEjoTzi3tKP3y76+c60MuJumv5mwNEjyGUOQiY="}
Here you have my devise session controller's create method for signing in (I had to change few things to make AJAX happen):
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
sign_in(resource_name, resource)
yield resource if block_given?
if user_signed_in?
flash[:logged] = "Zalogowany"
respond_to do |format|
format.html { redirect_to root_path }
format.js { render "sign_in_success.js.erb" }
end
end
end
sign_in_success.js.erb file:
$("body").empty();
$("body").append("<%= j(render template: 'layouts/user') %>");
button inside "layouts/user":
a href="#{destroy_user_session_path}" data-method="delete" rel="nofollow"
button.btn.btn-primary.m-r-20 type="button"
b Log Out
How do I send Authenticity Token with AJAX? Can I send it to "layouts/user" via locals option in render and use it this way?
I have solution. The problem was that csrf_meta_tags, was not updated when new session was created. The solution to that problem was to include additional code inside sign_in_success.js.erb file:
$("body").empty();
$("meta[name='csrf-token']").remove()
$("meta[name='csrf-param']").remove()
$("head").append("<meta name='csrf-token' content='<%= form_authenticity_token %>'>");
$("head").append("<meta name='csrf-param' content='<%= request_forgery_protection_token %>'>");
$("body").append("<%= j(render template: 'user/logged_signed') %>");
With code seen above firstly we are empting body element , then we are removing from DOM meta tags created by csrf_meta_tags helper. After that we are manually adding new csrf-token and csrf-param, this time our new authenticity token is assigned to meta name="csrf-token".
After that when we click on our log_out button rendered by "user/logged_signed" template we are logged out successfully and back at our root_path.
I'm trying to make a form in Rails that will respond with a js file. Right now, I have a file in app/assets/javascripts/login.js.coffee.erb that I'd like to be returned when the user submits the form via ajax (I've got users without javascript enabled working fine). Here's my template code for the form:
<%= form_tag("/trade/submit", :method => "post", :remote => true) do %>
# some stuff in here
<% end %>
In my trade controller, I have a method submit, which follows:
def submit
respond_to do |format|
format.html { render :layout => 'widget' + #widget_type.to_s, :template => 'login/index' }
format.js { render :action => 'login', :content_type => 'text/javascript' }
end
end
My respond with html works fine, but when calling the form via ajax, it returns this response:
Missing template trade/submit, application/submit with {:handlers=>[:erb, :builder, :coffee], :formats=>[:js, :html], :locale=>[:en, :en]}. Searched in:
* "~/app_dir/app/views"
Obviously, it shouldn't be looking in views, but rather in javascripts, right? I tried removing the render block after format.js (keeping it default so it will look for submit), and I get the same problem. Does this mean I have to save my js files in my views directory? Seems kinda messy, so I feel like surely I must just be doing something wrong. Any help is greatly appreciated!
It tries to find app/view/trade/submit.js.erb! Try to do a simple test.
touch app/view/trade/submit.js.erb
vim app/view/trade/submit.js.erb
alert('done!');
And run it again.
Ch8 of Beginning Rails book has an Ajax forms example which works ok except it does not output an alert for invalid input.
The controller code is:
def create
#comment = #article.comments.new(params[:comment])
if #comment.save
respond_to do |format|
format.html { redirect_to #article, :notice => 'Thanks for your comment' }
format.js
end
else
respond_to do |format|
format.html { redirect_to #article, :alert => 'Unable to add comment due to errors in your input'}
# logger.info("#{Time.now} Ajax invalid validation
##{#comment.errors.full_messages}!")
format.js { render 'fail.js.erb' }
end
end
end
The 'fail_create.js.erb' file contains the one line;
alert("<%= #comment.errors.full_messages.to_sentence %>");
Can some kind person explain why this is not working, thank you
You are rendering "fail.js.erb" but in your question you say the file "fail_create.js.erb" contains the code. Is that a typo in your question or is that the problem in your code?
Also, using RJS is considered bad form in Rails. If you are going through the example as a learning experience more power to you, but it was a failed experiment in the Rails community. Javascript should live on its own (and preferably be added to a site unobtrusively).
Book says to use jQuery 1.4.2
Upgraded to 1.4.4 and all worked well
I'm trying to add some Ajax functionality in my Rails 3 app.
Specifically, I want a button that will submit an Ajax request to call a remote function in my controller, which subsequently queries an API and returns a JSON object to the page.
Once I receive the JSON object I want to display the contents.
All of this with the new Rails 3 UJS approach, too. Is there a good example/tutorial for this online somewhere? I haven't been able to find one on google. A simple example using a button as the entry point (ie, the user clicks the button to start this process) would work, too.
Edit
Let me try this with a different approach. I want to have this button query an external API, which returns JSON, and display that JSON on the page. I have no idea where to even begin. Does the button itself query the external API? Do I need to go through the controller, and have the controller query the external API, get the JSON, and give the JSON back to this page? How do I display/access the contents of this JSON? I honestly can't find a good Rails 3.x example of how to handle JSON...
Here is a start:
First create your button with a link_to method in your view, for example:
=link_to "delete", "#{invitation_path(invitation)}.json", :method=>:delete, :remote=>true, :class=>"remove", :confirm=>'Are you sure you?'
Note that I am appending ".json" to the url of my resource. This is just an example of a an AJAX delete, google link_to to see the meaning of the parameters. The concept if that you make your HTTP request with the parameter :remote set to true, in other words this is translated to an AJAX call from your browser.
Second, write some javascript so that you can process what ever is the result of the AJAX call your browser will make when the user click on the link_to of step 1. For details you can see this blog post: http://www.alfajango.com/blog/rails-3-remote-links-and-forms/
An example from my site:
jQuery(function($) {
// create a convenient toggleLoading function
var toggleLoading = function() { $("#loading").toggle() };
$("#pending_invitation")
.live("ajax:loading", toggleLoading)
.live("ajax:complete", toggleLoading)
.live("ajax:success", function(event, data, status, xhr) {
var response = JSON.parse(xhr.responseText)
if (response.result == "ok") {
$(this).fadeOut('fast');
}
else {
var errors = $('<div id="error_explanation"/>');
errors.append('<h2>Pending invitation action error</h2><ul><li>' + response.error + '</li></ul>');
$('#new_invitation_error').append(errors)
}
});
});
where you can see that I parse the returned json and and change the html on the page based on that. Note that this js uses the CCS ids and classes defined in the top view that is not included here.
If you now want to write you own controller to spit out the json here is an example:
class InvitationsController < ApplicationController
respond_to :html, :json
# other methods here
# ...
def destroy
#invitation = Invitation.find(params[:id])
respond_to do |format|
if #invitation
#invitation.destroy
flash[:success] = I18n.t 'invitations.destroy.success'
format.json { render :json =>{:result => "ok", :message=>"Invitation #{params[:id]} was destroyed", :resource_id=>params[:id] } }
else
format.json { render :json => { :result=>"failed", :error=>"Cannot find Invitation #{params[:id]}", :resource_id=>params[:id] } }
end
end
end
end
Hope this help.
Old question, but a really good overview of Ajaxifying Rails applications is:
Ajax in Rails 3.1 - A Roadmap
Also consider returning errors in the following format:
render :json => #myobject.to_json, :status => :unprocessable_entity
This will ensure that your client can process the response as an error.