This seems simple, but I can't find anything on it.
I have a link to request a meeting with another user. This produces a url like this:
http://localhost:3000/meetings/new?requestee_id=5
The requestee id, and other information in the form are passed to the MeetingController:
def create
requestor = current_user
#meeting_with_params = meeting_params
#meeting = Meeting.new(meeting_params)
respond_to do |format|
if #meeting.save
format.html { redirect_to home_url, notice: 'Your lex was successfully requested! Click Plan Meeting ' }
format.json { render :show, status: :created, location: #meeting }
else
format.html { render :new, params: #meeting_with_params }
format.json { render json: #meeting.errors, status: :unprocessable_entity }
end
end
end
If there are errors, the url now looks like this:
http://localhost:3000/meetings
which means the form will never submit since the requestee_id is not present.
What is right way to have the user see errors, but the url params are never reset?
Thanks!
You can do this:
format.html { render "path/to/new?{#meeting_with_params.to_param}" }
OR
You can use rails path helpers. You canrake routes and find your url's helper path (it looks something like this: edit_user_path, new_user_path)
format.html { render new_meeting_path(#meeting_with_params) }
As you are ok to use ajax for this checkout [https://github.com/rails/jquery-ujs](jquery-ujs), your form tag has to look something like this:
form_for #meeting, data: {remote: true} ...
Related
I've just started to play with Rails applications and I'm trying to use Ajax on a form, but I don't know how to catch the status code inside a js.erb file. I'm following this tutorial: http://guides.rubyonrails.org/working_with_javascript_in_rails.html
On my Users controller I have a code for my update method:
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.js {}
format.json { render json: #user, status: :created, location: #user}
else
format.html { render action: 'edit' }
format.js {}
format.json { render json: #user, status: :unprocessable_entity }
logger.debug #user.response_errors
end
end
I've created a update.js.erb file inside my views/users/ folder and is very easy to debug the #user var, but I don't know how to get the status code setted on my method.
Sorry if it's a stupid question, but I'm new with rails and I'm trying to follow all the frameworks concepts to the letter and I don't know the best pratices to create responses to Ajax requests.
What I'm trying to achieve is something like this:
#on my update.js.erb
if( status == 'created' ) {
alert( 'Ok, created' )
} else {
alert( 'Something wrong happened' )
}
I appreciate any help.
Option 1: Check Validity Inside update.js.erb
This is the option that I recommend in most cases.
update.js.erb is an ERB template whose result is a JavaScript code to evaluate on the client. In this case, you can make it look like:
<% if #user.valid? %>
alert('Ok, created');
<% else %>
alert('Something wrong happened');
<% end %>
The decision which alert to displays happens server-side. The client receives either:
alert('Ok, create');
or
alert('Something wrong happened');
depending on the status of #user.
Option 2: Two separate js.erb files
You can split your update.js.erb into two files. update.js.erb should contain the happy path code:
alert('Ok, create');
update-error.js.erb should contain some error handling:
alert('Something wrong happened');
Then you decide which one to display in your controller:
respond_to do |format|
if #user.save
# ...
format.js {}
# ...
else
# ...
format.js { render 'update-error' }
# ...
end
end
I would try to do:
format.js {render json: {#user, status: :created, location: #user}}
from the default scaffold generator I have the following create action in my blogs controller:
# POST /blogs
# POST /blogs.json
def create
#blog = Blog.new(params[:blog])
respond_to do |format|
if #blog.save
format.html { redirect_to #blog, notice: 'Blog was successfully created.' }
format.json { render json: #blog, status: :created, location: #blog }
else
format.html { render action: "new" }
format.json { render json: #blog.errors, status: :unprocessable_entity }
end
end
end
When the sent form contains errors, my browser is redirected to /blogs URL but in the page the new action is rendered.
This is really ugly in my opinion and (also to simplify my javascript) I would like the browser to remain in the same blogs/new URL.
I tried with changing redirect_to :new instead of render action: "new", but this of course loses the #blog data.
any clue on how to do this?
thanks,
If you want to keep new in your path you could redirect with params like so:
redirect_to new_blog_path(blog: params[:blog])
and then check for these params in blog#new
(I've broken out the 2nd question that originally was part of this post into a separate post)
I am creating a product landing page with Rails in which users can enter their email address to be notified when the product launches. (Yes, there are services/gems etc that could do this for me, but I am new to programming and want to build it myself to learn rails.)
On submit of the form, if there are errors, the app currently redirects to '/invites' I would like to instead display error messages on the same page/URL as the original form? (In my case, the form is located at root while the error messages are displaying at '/invites')
I have read the Rails Guide on Routes and numerous stackoverflow posts on handling form errors nothing I've found seems to answer the question I have.
Update: Based on the reply from #rovermicrover I would like to clarify that, while I'm open to an Ajax solution, I'm fine with a page refresh that displays the error message. (I was not able to get the recommendation by #rovermicrover to function as desired - see my response to that solution below for more details.)
What I did:
Invite model:
class Invite < ActiveRecord::Base
attr_accessible :email
validates :email, :presence => {:message => "Please enter an email address."}
end
My routes file:
SuggestionBoxApp::Application.routes.draw do
root to: 'invites#new'
resources :invites
end
This is what I have in the Invites controller (I've only included the actions I'm referencing: new, create, show - it's basically the default of what Rails might generate):
class InvitesController < ApplicationController
def show
#invite = Invite.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #invite }
end
end
def new
#invite = Invite.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #invite }
end
end
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
format.html { redirect_to #invite }
format.json { render json: #invite, status: :created, location: #invite }
else
format.html { render action: "new" }
format.json { render json: #invite.errors, status: :unprocessable_entity }
end
end
end
end
Please let me know if there is any additional info I can provide in helping to answer this question. Thanks!
Make the form 'remote'
form_for #invite, :remote => true
....
Then in the controller
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
format.html { redirect_to #invite }
format.js { render :action => 'create_suc'}
else
format.html { render action: "new" }
format.js { render :action => 'create_fail' }
end
end
end
/invites/create_suc.js.erb
$('#errors').remove()
$('#new_invite').prepend("<div class='Thanks'>Thanks for signing up</div>")
$('#new_invite').hide("")
/invites/create_fail.js.erb
$('#new_invite').html('<%= escape_javascript render("form", :invite => #invite) %>');
Forms is a partial with your.... form in it, and also the handling of all errors on #invite.
There is a way to do this without resorting the making the form submit "remote", from a pure Ruby on Rails perspective. However, you can do this only if the browser has enabled cookies.
The idea is to save the form data in the session information in case of an error.
Just remember to delete the session data in case of success.
def new
#invite = Invite.new(session[:invite])
respond_to do |format|
format.html # new.html.erb
format.json { render json: #invite }
end
end
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
session.delete(:invite)
format.html { redirect_to #invite }
format.json { render json: #invite, status: :created, location: #invite }
else
session[:invite] = params[:invite]
format.html { render action: "new" }
format.json { render json: #invite.errors, status: :unprocessable_entity }
end
end
end
I have a form that is adding rows to the DB via remote => true. I then want to append the new data to a table, but cannot get the correct view to render.
As of now, it is rendering the entire show.html.erb page for the new entry, but I want to layout a minimal version to be added as a . Is there a quick way to tell my controller what view to render after inserting into the db? I want to render my partial named _newly_added.html.erb
My Controller
def new
#task = Task.new
render :partial => "/tasks/newly_added", :locals => { :t => #task }
end
Thanks!!
EDIT
I think what I need is just an alternative "show" view.
I found that the method I needed to change was actually this:
def create
#task = Task.new(params[:task])
respond_to do |format|
if #task.save
format.html { redirect_to #task, notice: 'Task was successfully created.' }
format.json { render json: #task, status: :created, location: #task }
else
format.html { render action: "new" }
format.json { render json: #task.errors, status: :unprocessable_entity }
end
end
end
I just need to make an alternative show view, and then tell this to redirect_to that view.
Edited per the changes in your question. However, nothing really changes. You're thinking about things wrong, and need to adjust how you're thinking. You don't need an alternative show, you need to handle the format.js request.
The partial should be rendered within a JavaScript response, not the controller. The controller looks more like this:
def create
#task = Task.new(params[:task])
respond_to do |format|
if #task.save
format.html { redirect_to #task, notice: 'Task was successfully created.' }
format.json { render json: #task, status: :created, location: #task }
format.js
else
format.html { render action: "new" }
format.json { render json: #task.errors, status: :unprocessable_entity }
format.js
end
end
end
Then, in views/tasks/create.js.coffee
($ '#mytable').append("<%= j render(partial: 'tasks/newly_added', locals: { t: #task }) %>")
What's going on here is that the browser makes a call to create.js. The controller responds with the create.js template, because of the respond_to block's format.js. The j escapes the contents of the _newly_added.html.erb file, and the contents of it are appended to the table. The controller doesn't interact with the existing view, instead, JavaScript is sent to the browser, and it interacts with the view.
This all changes somewhat if you're using a client-side MVC framework like Backbone or Ember, but you didn't specify that so I'm assuming you're going with stock Rails.
I want my page to refresh once a record has been created, at the moment it directs it to the page before. here is the code from my controller:
def create
#license = License.new(params[:license])
respond_to do |format|
if #license.save
format.html { redirect_to :controller => 'customers', :action => 'index' }
format.json { render json: #customer, status: :created, location: #customer }
else
format.html { render action: "new" }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
where it says redirect_to i need that to refresh, or link to the current page, with the current id, which would be :controller => 'customers', :action => 'show' but with the id of the current page's record.
Try
redirect_to customer_path(#license.id)
instead.
Depending on what your routes.rb file says, it should work.
But if it doesn't, try:
redirect_to show_customer_path(#license.id)
However, here I have to assume that somehow, your customers_controller.rb is somehow showing records from the License model. If License and Customer are separate models, you will have to find the customer_id in some other way.
Perhaps, it is:
redirect_to customer_path(#license.customer_id)
If License is not connected to Customer in any way, you will need to pass it in as part of the post request.
Try,
I think you are passing customer_id to on params(Licensee belongs to customer), if so then
redirect_to customer_path(#license.customer) or redirect_to customer_path(params[:customer_id])