problem with RESTful forms in Rails 3 - ruby-on-rails-3

okay, so basically, I have a normal form for my model:
= form_for #operator do |f|
blah blah blah
In my operators controller, i have this:
def new
#operator = Operator.new
#operator.build_user
respond_to do |format|
format.html {}
end
end
def create
#user = User.create(params[:operator].delete(:user))
#user.update_attributes(:login => #user.email)
#operator = Operator.new(params[:operator].merge(:user => #user))
respond_to do |format|
if #operator.save
format.html {redirect_to new_operator_aircraft_path(#operator)}
else
format.html { render :action => "new", :error => #operator.errors }
end
end
end
very basic stuff. I have some validates_presence_of stuff in my model so naturally when I submit my form, it should show me that I have errors(and keep the fields I have filled up)
Right so far? yeah. The problem is, it seems I am posting to /operators and that's what renders. I seem to have forgotten about what happens in Rails2.3+ but shouldn't I be redirected to /operators/new again? or was that the intended behavior all along?

Here's what I think you are asking:
After I submit a form with errors, why does the URL
read "/operators" rather than
"/operators/new".
Thanks to resourceful routing, when submitting a form via POST to "/operators" the create action is called on the OperatorsController. If you encounter errors when saving your operator, you've instructed the controller to render the new action within the same request.
render :action => "new", :error => #operator.errors
This means a redirect is not occurring and therefore the URL remains "/operators".
If a redirect were to occur, you would lose all the state information of the #operator object in the current request, including the errors you encountered as well as the form values you just submitted.
In other words, working as intended.

Related

After deleting a record in Rails 3, the refreshed view isn't updated

I'm dealing with a basic one to many relation where I'm deleting a record on the many side. The models are "places" and "search_terms" where places has_many search_terms. When I create a new record, the view is updated and the new search_term appended to the list. However, when I delete a search_term record the view is not refreshed even though it deletes the record and runs the "show" method for Place.
I'm quite new to rails 3 so can't really figure out whats going on here...
Cheers,
Gearoid.
Edit: the search_terms controller destroy method:
def destroy
#search_term = SearchTerm.find(params[:id])
#search_term.destroy
#place = Place.find(params[:place_id])
redirect_to place_path(#place)
end
The places controller show method:
def show
#place = Place.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #place }
end
end
I might be misunderstanding you, could you post your controller's code?
Is this happening over ajax? If not, can you redirect to the Show instead of just re-rendering it? That's probably a preferred experience for the user anyway.
UPDATE
Ok, if this is going over ajax, then the problem is simple. Your destroy action is only expecting a normal browser event and doing a redirect_to call. The ajax call doesn't know how to handle it and just sits there. You can probably see the redirect code in something like Firebug.
I'm not super familiar with jquery-rails (I prefer to write all my js myself because I'm anal). You can have the destroy action return a js format like so:
def destroy
#search_term = SearchTerm.find(params[:id])
#search_term.destroy
#place = Place.find(params[:place_id])
respond_to do |format|
format.html { redirect_to place_path(#place) }
format.js { render :nothing => true }
end
end
That will give the ajax caller the ok signal that it has done its thing. Your javascript will still have to intelligently handle this response though, like remove the element from the DOM.

How to render validation errors on the page that submitted the form?

I've got a comments form in the article/show page. In this page, it displays the article and has a comments form.
When I submit a comment that has validation errors, I need it to go back to the article/show page, and display the errors there.
Should I change render :action => 'new' to something else?
In the Comment controller, I tried:
def create
...
if #comment.save?
redirect_to article_path(#comment.article), :notice => "Posted comment!"
else
# render :action => 'new'
render 'articles/show"
end
end
But this will complain, since the app won't know which article to show based on the ID.
EDIT: I found this solution. The approach would be to use a session to pass the errors instead. Is this the right way to go with this?
Try this
def create
...
if #comment.save?
redirect_to article_path(#comment.article), :notice => "Posted comment!"
else
# render :action => 'new'
#article = #comment.article
render 'articles/show"
end
end`
So fix your routing so the app does know what article to show based on the ID.

Displaying error messages in rails

I seem to have trouble handling error messages. Here's my method:
def destroy
#user = User.find(current_user)
#authorization = Authorization.find(params[:id])
if #user.authorizations.count > 1
#authorization.destroy
redirect_to(user_path(current_user))
else
...
end
end
I don't want a user to delete their last authorization (say, Facebook) because then the user won't have any authorizations associated with it and the account is lost. I want to send an error message that says why the destroy method fails, but I'm just not sure how. Everything I've tried just doesn't work.
I've tried things like #user.errors.add => "error message"
But it just shows up blank. I think my problem is with using render. If I try, for example:
respond_to do |format|
#user.errors[:base] << "Sorry, you can't delete your only authorized service."
format.html render :template => "users/show"
end
I get a problem because rails starts looking for the partials in users/show inside the authorizations directory for some reason, presumably because I'm calling the authorizations controller from a users view.
Here's how I display the flash in my views:
def show_flash
[:notice, :errors, :alert].collect do |key|
msg = (flash[key].to_s + " (close)")
content_tag(:div, (content_tag(:a, msg, :class => "#{key}", :href => "#", :onclick => "$('messages').slideUp(); return false;")), :id => key, :class => "flash_#{key}") unless flash[key].blank?
end.join
end
I can get notices to appear just fine.
So, this seems to be working:
respond_to do |format|
format.html {redirect_to(#user, :alert => "Sorry, you can't delete your only authorized service.")}
end
But, this does not:
respond_to do |format|
format.html {redirect_to(#user, :errors => "Sorry, you can't delete your only authorized service.")}
end

How do you pass validation errors across controllers?

I'm making a conventional forum in Rails to practice. I have a Topic model and a nested Post model. Topics can have many Posts.
Topics#Show has a list of #topic.posts and then a new Post form.
# Topics#Show
def show
#topic = Topic.find(params[:id])
#post = #topic.posts.new
end
Submitting a new post sends it to Posts#Create
# Posts#Create
def create
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.new(params[:post])
#post.user = current_user
if #post.save
redirect_to #topic, :notice => "Successfully created post."
else
render :action => 'new' # <-- Unsure what to do here
end
end
If the Post fails to save, I want it to render Topics#Show and display the validation errors there.
From what I understand, params don't persist through a redirect_to because a 302 redirect starts a new request.
You should render the topics/show view. So instead of
render :action => 'new' # <-- Unsure what to do here
Do:
render :template => 'topics/show'
Use render :template => "topics/show" and be sure to set up the #topic variable identically to how you do it in the TopicsController#show action. You will not be able to call this show method from the PostsController though.

Rails3 and Respond_with problem

I have an application, on which I have two user interfaces.
The first one is for normal users and the second one is for iphone users.
Everything was working fine until i refactored my code within controller to use the respond_with declarative instead of respond_to.
The application is still working for the html interface(:format => :html) but not on the iphone interface(:format => :iphone).
On the iphone, when I do the following action (:index, :new, :edit, :show) it works.
But when i do (:create, :update, :destroy), I get errors saying the template is not found(create.iphone.haml for example).
On my controller I have
respond_to :html, :iphone
And then for example, the edit and the update action
def edit
#refund = Refund.find(params[:id])
respond_with(#refund)
end
def update
#refund = Refund.find(params[:id])
if #refund.update_attributes(params[:refund])
flash[:notice] = 'Refund was successfully updated.'
end
respond_with(#refund, :location => project_refunds_path(#project))
end
In fact, I would like the :iphone format is handle as :html is ... and not by calling the to_format method as it is specified into the doc.
Solved it by myself.
Just need to add this to an initializer file :
ActionController::Responder.class_eval do
alias :to_iphone :to_html
end
What if you do:
respond_with(#refund, :location => project_refunds_path(#project)) do |format|
format.iphone { whatever you had here before refactoring }
end