Edit Action rendering blank page; Parameters hash is displayed in URL - ruby-on-rails

I am working on an application where one controller controls the create action of several models. I have a lot more code, but I'm not sure if this error is specific to code or a generic fix (like changing the HTTP request) that doesn't require me to post my entire set up.
I have a 'basketball' model that belongs_to 'activities' that is generated from the activities controller. Each activity has_one basketball model.
Then in the basketballs controller I have this.
def edit
#activity = Activity.find(params[:id])
#basketball = #activity.basketball
end
def update
#activity = Activity.find(params[:id])
#basketball = #activity.basketball
if #basketball.update_attributes(basketball_params)
flash[:notice] = "Activity has been updated."
redirect_to activities_path
else
flash[:notice] = "Activity has not been updated."
render 'edit'
end
end
However, when I click the update button, my page renders a blank page with all of the parameters in the url. Example:
http://0.0.0.0:8080/basketballs/10/edit?utf8=%E2%9C%93&_method=patch&authenticity_token=[token]&basketball
Does anyone know how to fix this?

You have 3 nested forms in your views.
Here are the problems: app/views/strengthworkouts/_formatting.html.erb line 65 and app/views/workouts/_strengthworkout.html.erb line 5
Remove those <form> tags, keep the form_for.
Only the outermost form was used. And because it doesn't have any action or method or whatsoever attribute, submitting it just triggers a GET to the current path with the params in the query string.

Related

How work render action in controller?

I have method in controller like this:
def create
#player = Player.new(player_params)
if #player.save
flash[:success] = "Player created"
redirect_to player_path(#player)
else
render 'new'
end
end
And I have also test:
it "add players without nickname" do
visit new_player_path
click_button "Add player"
current_path should eq new_player_path
end
But after call render method my current path is:
http://localhost:3000/players
not
http://localhost:3000/players/new
But the layout is from players/new. Why?
And what should be my test? In test I just want to check if user don't type in nickname in nickname filed application return to create user page (players/new path).
Actually when there is any errors then it moves from new to create action, so the path becomes http://localhost:3000/players, and the render just renders the new action's template here. Now the main question is why so?
As in the new action you have submitted the form with some data to the create action. Now if suppose it sends you back to new action then it would have to redirect you back to that page, so what will redirect do? It will make rails to loose all the form data which you have submitted and the data would never persist. So instead what is done is you remain on the create action which has the url: http://localhost:3000/players and it renders the new action which means the new action's template (or you can say form). It doesn't redirects it just renders it in the same one.
Now the question is how does the data persist? The data persists with the object. This line #player = Player.new(player_params) creates a new object of the Player class with the attributes you have passed in the form. Now as you remain in the same action and the object is persisted so the data on the form is also persisted.
If you want to test it then in your code replace this:
render 'new'
with:
redirect_to new_player_path
and you will notice the data would never persist unless you pass that explicitly.
Hope this helps.

Ruby redirect to same page and show errors if form input is bad

Forgive me I'm new at Ruby. I am trying to create a site to contain information about a zoo.
I have an enclosure model and an animal model.
This is my code for the create method in animal_controller
def create
if params.has_key?(:enclosure_id)
#enclosure = Enclosure.find(params[:enclosure_id])
#animal = Animal.new(animals_params)
#animal.user_id = current_user.id
if #animal.save
#enclosure.animals.push(#animal)
redirect_to enclosure_path(#enclosure)
else
# ????
end
else
#animal = Animal.new(animal_params)
#animal.user_id = current_user.id
if #animal.save
redirect_to #animal
else
render 'new'
end
end
end
I then have two places where a new animal can be created. One is using a form at localhost:3000/animals/new. The other is using a similar form on the show page of a particular enclosure, so for example at localhost:3000/enclosures/1/
In my code above, I check for the presence of enclosure_id to determine where the call is coming from. If the parameter is found, I add the animal to the enclosure there and then. However, if #animal.save fails, I do not understand how I can return to the localhost:3000/enclosures/id page with the validation error messages being passed. In the case of no enclosure_id, render 'new' takes the user back to the ../animal/new page with error messages passed as well.
Thanks
I don't think it's a good idea to go to an other page, because you will have to serialize errors linked to the model and it's gonna be complicated and ugly.
I think you should render the show page of the enclosure and then display the errors
#....
if #animal.save
#enclosure.animals.push(#animal)
redirect_to enclosure_path(#enclosure)
else
render 'enclosures/show'
end
#....

when to render with instance variable, and when to redirect?

My new and edit pages depend on an #important_data instance variable that is not used in the create and update actions.
As a result my page can't render the new page upon failure.
def create
#my_object = MyObject.new(params[:my_object])
if #my_object.save
redirect_to root_path
else
render action: "new"
#this can't render because the page asks for an #important_data variable that's not defined.
end
end
Which of the two solutions below should I choose?
What are the advantages/disadvantages of each?
OPTION 1: declare #important_data prior to render
def create
#my_object = MyObject.new(params[:my_object])
if #my_object.save
redirect_to root_path
else
#important_data = ImportantData.all
render action: "new"
end
end
OPTION 2: Redirect
def create
#my_object = MyObject.new(params[:my_object])
if #my_object.save
redirect_to root_path
else
redirect_to new_my_object_path
end
end
When you use render, you're using #my_object with the attributes updated from params[:my_object]. Most of the case, this is what you want. When you show the page to the user, you want to preserve the changes they made to the form and show them the errors.
When you use redirect, you're doing a different and additional request so the parameters submitted from the form are not preserved (unless you pass them in your call to redirect and build them up in the controller action).
So in most cases, you'll definitely want to declare #important_data when the validation fails. I can't think of a case where you'd want to redirect.
Offcourse, the Option1 will work best, since you are rendering new in case of errors only. Also, redirection li'l bit mess up the user experience, it will take a bit long to render the page again with same query #important_data = .... running again.
I think you should use OPTION1
So the place where redirect_to should be used is when you're doing a HTTP POST request and you don't want the user to resubmit the request when it's done (which may cause duplicate items and other problems).
In Rails, when a model fails to be saved, render is used to redisplay the form with the same entries that was filled previously. This is simpler because if you use redirect, you'll have to pass the form entries either using parameters or session. The side effect is that if you refresh the browser, it will try to resubmit the previous form entries. This is acceptable because because it will probably fail the same way, or if it's successful now, it was what the user should expect in the first place anyway.
The above answer is referenced from: Are redirect_to and render exchangeable?

Rails : Is it possible to put a "create" form on a "index" or "show" view?

Hi I'm trying to work on my first rails project and was wondering if it was possible to combine the show or index view (of photo albums) with a form that creates more photo albums. Would the URL not have the correct parameters to do this? Would I be able to set the action on the form to make it "create" and redirect_to the index page again on success?
Sure you can do this, just put the form code on whatever page you want to create/update from and it will work.
The only issue is where the action would redirect you to after a successful or unsuccessful create/update: usually from the new page, you would redirect to the newly-created record (show action for the new record) on success and back to the new action on failure (with the errors on the form fields). If you want to create/update records from different pages, and have the action redirect to different pages in each case, then you'll have to do just a bit more work.
On possibility would be to add a hidden parameter to the form with the action to redirect to, and make the action check for it and redirect accordingly. For example:
VALID_REDIRECT_ACTIONS = ["show", "index"]
def create
...
if #photo.save
flash[:success] = "Photo successfully created!"
if VALID_REDIRECT_ACTIONS.include?(params[:redirect])
redirect_to params[:redirect]
else
redirect_to #photo
end
else
...
end
end

How do I make form_for to complete with the previously submitted data when validation fails?

Given that I have a large form
When the user submits it
And the validation of the data fails
Then the user is redirected to the previous page again
And the form should contain the data that the user previously submitted
How can I achieve the last part? :P
There is something like flash[] for the form_for helper?
I have to use AJAX?
As some of the comments have suggested, this can be the default behavior, if you're using best practices.
Here's an example of the new/create controller actions that should exhibit said behavior:
def new
#model = MyModel.new
end
def create
#model = MyModel.new(params[:my_model])
if #model.save
redirect_to my_models_url, :notice => "Success!"
else
flash.now[:error] = "There was an error"
render :new
end
end
Check in your view if request.method == :post, and if it is then use the data in params[] instead. It will contain the data you just posted.

Resources