I am working on rails ..
Want to add status feature, but having problem as we need to go create and edit page of each status.
Want to know how can I do on the same page without leaving the page..
I would do something like:
<%= form_for(#status, remote: true) do |f| %>
...
<% end %>
Check out the Rails guide on ajax forms.
You can render back with json like:
def create
#status = Status.find(params[:id])
respond_to do |format|
if #status.update_attributes(status_attributes)
format.html { redirect_to #status }
format.js {}
format.json { render json: #status }
else
format.html { render action: "new" }
format.json { render json: #status.errors }
end
end
I edited this to reflect updating a status.
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}}
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} ...
I’m using Rails 4.2.3. I want to submit a form in a modal dialog, so I have set up my form like so
<%= form_for #my_object, :remote => true do |f| %>
but if the user submits the form successfully, I would like to reload the page that invoked the modal dialog with a notice of “Saved Successfully.” I can’t figure out what I need to put in my “format.js” to make this happen. This is what I have in my controller so far …
def create
#my_object = MyObject.new(my_object_params)
#current_user = User.find(session["user_id"])
#my_object.user = #current_user
respond_to do |format|
if #my_object.save
format.html { redirect_to controller: "users", action: "index", notice: 'Saved successfully.' }
format.js { render action: ‘../users/index’, notice: ‘Saved Successfully’, location: #my_object }
else
format.html { render action: "index" }
format.js { render json: #my_object.errors, status: :unprocessable_entity }
end
end
end
Right now, a successful submission results in a 500 error complaining about missing partials when I try and execute the above. Pretty sure what I have is wrong anyway.
You can do the following:
#app/controllers/redirect.rb
...
format.js { render js: "window.location='#{url.to_s}'" }
...
If you like keeping things separated, just put format.js in your controller and do the javascript redirect in your view (redirect.js.erb)
In both cases, just set flash[:notice] to whatever you need before redirecting.
redirect_to events_path, format: 'js'
For this you will need to have events/index.js.erb in your file structure.
If you are redirecting anyway, you might as well avoid the remote/AJAX call, and just redirect from the create action.
<%= form_for #my_object do |f| %>
and
def create
#my_object = MyObject.new(my_object_params)
...
redirect_to some_path
end
If you have want to redirect it after successfully create/updated and just use .html method. Otherwise just use JS option like in this LINK.
def create
#my_object = MyObject.new(my_object_params.merge(user: User.find(session["user_id"])))
respond_to do |format|
if #my_object.save
format.html { redirect_to controller: "users", action: "index", notice: 'Saved successfully.' }
else
....
end
end
end
That will help you, from your controller
render :js => "window.location = '/jobs/index'"
(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 very common HABTM relationship between Product and Category. I'm based on Railscasts Episode #17. The problem I'm facing is related to the way all the categories are fetched to show them in the product form (this is the way R. Bates has the view for it):
<% for category in Category.find(:all) %>
<div>
<%= check_box_tag "product[category_ids][]", category.id, #product.categories.include?(category) %>
<%= category.name %>
</div>
<% end %>
but I want to implement it this way:
<% for category in #categories %>
where I have #categoriesdefined in my controller:
def edit
#categories = Categories.all
#product = Product.find params[:id]
end
It all goes smoothly until some validation fails. Say some field can't be blank and so the redirection (on the update action of the ProductsController) shoot's me back to edit:
def update
#product = Product.find(params[:id])
#supplier.category_ids = params[:product][:industry_category_ids] ||= []
respond_to do |format|
if #product.update_attributes(params[:product])
format.html { redirect_to #supplier, notice: 'Profile was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" } <=== HERE
format.json { render json: #supplier.errors, status: :unprocessable_entity }
end
end
end
An that point I get the following error, saying that #categories in the correponding form is nil:
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.each
...
<% for ic in #industry_categories %> <==== HERE
...
So, is there a way to keep the MVC best practices to accomplish this? Or I just have to do it Bate's way?
In other words, is is possible to have a form_for say #product with checkboxes for the "HABTM" related objects and be redirected to it after validation fails BUT without fetching the stuff on the view (Category.all) (i.e. doing it on the corresponding controller #categories = Category.all as I showed before)
Thanks!
Populate #categories when you fail your validation:
def update
#product = Product.find(params[:id])
#supplier.category_ids = params[:product][:industry_category_ids] ||= []
respond_to do |format|
if #product.update_attributes(params[:product])
format.html { redirect_to #supplier, notice: 'Profile was successfully updated.' }
format.json { head :ok }
else
#categories = Categories.all <--- HERE
format.html { render action: "edit" }
format.json { render json: #supplier.errors, status: :unprocessable_entity }
end
end
end
When you make a call to "render :action", Rails just continues processing the current request and renders the view mapping to the :action you specified. So in this case, you're re-rendering the 'edit' view (because you failed your validation) but since there's no #categories variable declared in the 'update' action you will get a nil reference exception.